From 09aa8f4df4dd94eaef08cdb20e9090012d40fd88 Mon Sep 17 00:00:00 2001 From: "Mobile Joomla\\!" Date: Wed, 1 Jun 2011 00:33:53 +0300 Subject: [PATCH] Added RSS feed reader and notices on the main page. Had to hack JS a bit --- .gitignore | 21 +++ .pydevproject | 20 --- .settings/org.eclipse.core.resources.prefs | 3 - src/main.py | 7 + src/media/css/styles.css | 15 ++ src/media/jquery.minime.feed.js | 171 +++++++++++++++++++++ src/media/simplerss.js | 93 +++++++++++ src/proxy.py | 71 +++++++++ src/templates/main.html | 40 +---- src/templates/master.html | 5 +- src/templates/news.html | 10 ++ 11 files changed, 396 insertions(+), 60 deletions(-) delete mode 100644 .pydevproject delete mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 src/media/jquery.minime.feed.js create mode 100644 src/media/simplerss.js create mode 100644 src/proxy.py create mode 100644 src/templates/news.html diff --git a/.gitignore b/.gitignore index ccee5fd..72029e5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ downloads/* eggs/* fake-eggs/* parts/* +develop-eggs dist .installed.cfg .mr.developer.cfg @@ -30,3 +31,23 @@ dist *.orig *.rej __minitage__* +.metadata +.secret.cfg +.settings +.project +.pydevproject +flattened-eggs + +jsdoc* +releases + +.DS_Store +docs/apidocs/* + + +*.min.js +*.debug.js +*.min.css +*.debug.css + + diff --git a/.pydevproject b/.pydevproject deleted file mode 100644 index ff34f45..0000000 --- a/.pydevproject +++ /dev/null @@ -1,20 +0,0 @@ - - - - - -GOOGLE_APP_ENGINE -/home/moo/google_appengine - - -/pigfi/src - - -${GOOGLE_APP_ENGINE} -${GOOGLE_APP_ENGINE}/lib/django -${GOOGLE_APP_ENGINE}/lib/webob -${GOOGLE_APP_ENGINE}/lib/yaml/lib - -python 2.6 -Default - diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index c282d0a..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Thu Dec 09 13:29:48 EET 2010 -eclipse.preferences.version=1 -encoding//src/main.py=utf-8 diff --git a/src/main.py b/src/main.py index 44b769d..35a65aa 100644 --- a/src/main.py +++ b/src/main.py @@ -37,6 +37,10 @@ class MainPage(PigPage): def get(self): self.render_page("main.html") +class NewsPage(PigPage): + def get(self): + self.render_page("news.html") + class AboutPage(PigPage): def get(self): @@ -73,9 +77,12 @@ class NotFound(PigPage): def get(self): self.render_page("404.html") +from proxy import ProxyHandler application = webapp.WSGIApplication([ ('/about', AboutPage), + ("/proxy", ProxyHandler), + ('/news', NewsPage), ('/english', InEnglishPage), ('/companies', CompaniesPage), ('/blogs', BlogsPage), diff --git a/src/media/css/styles.css b/src/media/css/styles.css index 5b8c118..0a3fb33 100644 --- a/src/media/css/styles.css +++ b/src/media/css/styles.css @@ -304,3 +304,18 @@ overflow: hidden; margin-bottom: 0; padding-bottom: 0; } + +.minimeFeed, +.minimeFeed li { + list-style: none; +} + +#content .posts, +#content .minimeFeed { + padding-left:0; + margin-left: 0; +} + +.minimeFeed > li { + margin-bottom: 1em; +} diff --git a/src/media/jquery.minime.feed.js b/src/media/jquery.minime.feed.js new file mode 100644 index 0000000..077326d --- /dev/null +++ b/src/media/jquery.minime.feed.js @@ -0,0 +1,171 @@ +jQuery.fn.miniFeed = function (feedurl, options, callbackFunc) { + top.feedOpt = jQuery.extend ({ + /** + * + * minime RSS and Atom Feed Reader + * ver 1.0.1 + * + **/ + // Default options + phpRepeater: "getfeed.php", // XML - PHP repeater file for cross-domain errors against (Leave blank if extensions) + timeout: 5000, // Timeout + limit: 10, // Feed item limit + getFeedTitle: true, // Feed title visibility + getItemTitle: true, // Item title visibility + getItemDate: true, // Item date and time visibility + getItemSummary: true, // Item summary visibility + getItemDescription: false, // Item description visibility (only Atom feed) + getItemLink: true, // Item link visibility + getAtomId: false, // Item id visibility (only Atom feed) + nextLinkText: "next »", // Item hyperlink text + wrongXmlText: "Feeds are not given", // Wrong RSS and Atom xml message + timeoutText: "No responses were received within the specified time", // Timeout message + errorText: "The file is not found or network failure", // HTTP and other error message + notModifiedText: "The source has not changed since the last request", // Not modified message + parserErrorText: "Analytical error" // XML Parser error message + }, options); + + $(this).empty(); + // feedurl is empty + if(!feedurl||feedurl=='') { + $(this).append(top.feedOpt.errorText); + return false; + } + if(feedurl.substr(0,7)=='http://'&&(top.feedOpt.phpRepeater!=''||top.feedOpt.phpRepeater!=null)) { + feedurl = top.feedOpt.phpRepeater+'?url='+feedurl.substr(7); + } + top.selected = this; + top.setHtml = ''; + $.ajax({ + type: "GET", + url: feedurl, + dataType: "xml", + timeout: top.feedOpt.timeout, + success: function(xml) { + if($(xml).children('rss').length>0) { + // RSS feeds + if(top.feedOpt.getFeedTitle) { + var rssFeedTitle = $(xml).children('rss').children('channel').children('title').text(); + top.setHtml += '

'+rssFeedTitle+'

'; + } + top.setHtml += ''; + } + + if($(xml).children('feed').length>0) { + // ATOM feeds + if(top.feedOpt.getFeedTitle) { + var atomFeedTitle = $(xml).children('feed').children('title').text(); + top.setHtml += '

'+atomFeedTitle+'

'; + } + top.setHtml += ''; + } + // wrong xml + if($(xml).children('rss').length==0&&$(xml).children('feed').length==0) { + top.setHtml += top.feedOpt.wrongXmlText; + } + $(top.selected).append(top.setHtml); + if(typeof callbackFunc == 'function'){ + callbackFunc.call(this, xml); + } + }, + // Error Handling + error: function (xhr, status, error) { + if(xhr.statusText=='timeout') { + top.setHtml += top.feedOpt.timeoutText; + } + if(xhr.statusText=='error') { + top.setHtml += top.feedOpt.errorText; + } + if(xhr.statusText=='notmodified') { + top.setHtml += top.feedOpt.notModifiedText; + } + if(xhr.statusText=='parsererror') { + top.setHtml += top.feedOpt.parserErrorText; + } + $(top.selected).append(top.setHtml); + } + }); + } + +$(document).ready(function() { + // Need to pipe through proxy due XSS not allowed in sites.google.com + var url = "http://sites.google.com/a/python.fi/tiedotus/tiedotteet/posts.xml"; + var url = "/proxy?url=" + encodeURI(url); + $('.posts').miniFeed(url, { limit: 10, getFeedTitle : false, getItemDate: false, getItemDescription : true}); +}); \ No newline at end of file diff --git a/src/media/simplerss.js b/src/media/simplerss.js new file mode 100644 index 0000000..0bbaeb3 --- /dev/null +++ b/src/media/simplerss.js @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2010, Till Klampaeckel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * o Neither the name of the nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category RSS + * @package simplerss + * @author Till Klampaeckel + * @license http://www.opensource.org/licenses/bsd-license.php The New BSD License + * @link http://github.com/till/jquery-simplerss + */ +(function($){ + jQuery.fn.extend({ + + /** + * simplerss + * + * @param array options To override the defaults. + * + * @return this + */ + simplerss: function(options) { + + var defaults = { + url: '', + html: '{title}
{text}', + wrapper: 'li', + dataType: 'xml', + display: 2 + } + var options = jQuery.extend(defaults, options); + + return this.each(function() { + var o = options; + var c = jQuery(this); + + if (o.url == '') { + return; // avoid the request + } + + jQuery.ajax({ + url: o.url, + type: 'GET', + dataType: o.dataType, + error: function (xhr, status, e) { + console.debug('C: #%s, Error: %s, Feed: %s', $(c).attr('id'), e, o.url); + }, + success: function(feed){ + + jQuery(feed).find('item').each(function(i){ + + var itemHtml = o.html.replace(/{title}/, jQuery(this).find('title').text()); + itemHtml = itemHtml.replace(/{text}/, jQuery(this).find('description').text()); + itemHtml = itemHtml.replace(/{link}/, jQuery(this).find('guid').text()); + + jQuery(c).append(jQuery('<' + o.wrapper + '>').append(itemHtml)); + + if (i == o.display) { + return false; + } + + }); + } + }); + }); + return this; + } + }); +})(jQuery); + + diff --git a/src/proxy.py b/src/proxy.py new file mode 100644 index 0000000..9869847 --- /dev/null +++ b/src/proxy.py @@ -0,0 +1,71 @@ +# http://gregdoesit.com/2010/12/using-google-app-engine-as-proxy-for-cross-domain-requests/ + +import logging +import pickle +import urllib +import re +import time +import urllib +import wsgiref.handlers +import hashlib + +from google.appengine.api import memcache +from google.appengine.api import urlfetch +from google.appengine.ext import db +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template +from google.appengine.runtime import apiproxy_errors + +CACHE_TIME = 1 # number of minutes to cache content for + +URL_PREFIXES = ["http://sites.google.com/a/python.fi"] # only allow URLs to be queried from certain domain(s) + +def getMemcacheKey(url): + url_hash = hashlib.sha256() + url_hash.update(url) + return "hash_" + url_hash.hexdigest() + +class ProxyHandler(webapp.RequestHandler): + + def get(self): + url = self.request.get('url') + url = urllib.unquote(url) + # only allow urls that start with prefixes defined in URL_PREFIXES to be used + if not self.isUrlAllowed(url): + self.response.out.write("The URL passed can not be proxied due to security reasons.") + return + memcacheKey = getMemcacheKey(url) + + # Use memcache to store the request for CACHE_TIME + proxiedContent = memcache.get(memcacheKey) + proxiedContentInMemcache = True + if proxiedContent is None: + proxiedContentInMemcache = False + try: + response = urlfetch.fetch(url) + except (urlfetch.Error, apiproxy_errors.Error): + return self.error(404) + proxiedContent = response.content + if proxiedContent is None: + return self.error(404) + + # Add the fetched content to memcache + if (not proxiedContentInMemcache): + memcache.add(memcacheKey,proxiedContent,CACHE_TIME) + self.response.out.write(proxiedContent) + + def isUrlAllowed(self, url): + for urlPrefix in URL_PREFIXES: + if url.startswith(urlPrefix): + return True + return False + +app = webapp.WSGIApplication([ + ("/proxy", ProxyHandler), +], debug=True) + +def main(): + wsgiref.handlers.CGIHandler().run(app) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/templates/main.html b/src/templates/main.html index 214dce3..0f5dac1 100644 --- a/src/templates/main.html +++ b/src/templates/main.html @@ -26,40 +26,8 @@

Yhdistys perustettu

-
-

Yhdistyksen perustamiskokous

-

- Python Interest Group Finland ry:n perustamiskokous - järjestetään lauantaina 7.5.2011 klo - 10:00 DjangoCon Finlandin - yhteydessä Aalto Venture Garagen tiloissa, Betonimiehenkuja 3, - Espoo. Perustamiskokouksessa mm. hiotaan kuntoon yhdistyksen - säännöt - (työversio - Google Docsissa) sekä valitaan yhdistyksen ensimmäinen - hallitus. Kaikki ovat tervetulleita! -

-

- Virallinen kokouskutsu yhdistyksen perustamiskokoukseen - löytyy täältä. -

-
- -
-

Kehittäjä hakusessa

-

- Mikäli olet aloitteleva Python-kehittäjä ja haluat osallistua vapaaehtoistyöhön, meillä - olisi juuri oikea erikoistehtävä sinulle. -

- -

- Pääset kehittämään python.fi-sivustoa Suomen kovimpien web-ammattilaisten ohjaamana. -

- -

- Työ on palkatonta, mutta voimme järjestää tämän oppilaitoksen yms. harjoitustyön tai - työharjoittelun puitteissa. -

-
- +

Tiedotteet

+ +
    + {% endblock %} diff --git a/src/templates/master.html b/src/templates/master.html index 8d81864..ec262cd 100644 --- a/src/templates/master.html +++ b/src/templates/master.html @@ -5,9 +5,12 @@ - + + + +
    diff --git a/src/templates/news.html b/src/templates/news.html new file mode 100644 index 0000000..e154e92 --- /dev/null +++ b/src/templates/news.html @@ -0,0 +1,10 @@ +{% extends "master.html" %} + +{% block content %} +
    +

    Tiedotteet ja uutiset

    + +
      + +
      +{% endblock %}