#! /usr/bin/env python
#-*- coding: utf-8 -*-
# pyAggr3g470r - A Web based news aggregator.
# Copyright (C) 2010-2012 Cédric Bonhomme - http://cedricbonhomme.org/
#
# For more information : http://bitbucket.org/cedricbonhomme/pyaggr3g470r/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
Error %s - This page does not exist.
" % status tmpl = lookup.get_template("error.html") return tmpl.render(message=message) def handle_error(): """ Handle different type of errors. """ message = "Sorry, an error occured.
" cherrypy.response.status = 500 cherrypy.response.body = [message] class RestrictedArea(object): """ All methods in this controller (and subcontrollers) is open only to members of the admin group """ _cp_config = { 'auth.require': [member_of('admin')] } @cherrypy.expose def index(self): return """This is the admin only area.""" class pyAggr3g470r(object): """ Main class. All pages of pyAggr3g470r are described in this class. """ _cp_config = {'request.error_response': handle_error, \ 'tools.sessions.on': True, \ 'tools.auth.on': True} def __init__(self): """ """ self.auth = AuthController() restricted = RestrictedArea() self.mongo = mongodb.Articles(conf.MONGODB_ADDRESS, conf.MONGODB_PORT, \ conf.MONGODB_DBNAME, conf.MONGODB_USER, conf.MONGODB_PASSWORD) @require() def index(self): """ Main page containing the list of feeds and articles. """ feeds = self.mongo.get_all_feeds() nb_unread_articles = self.mongo.nb_unread_articles() nb_favorites = self.mongo.nb_favorites() nb_mail_notifications = self.mongo.nb_mail_notifications() tmpl = lookup.get_template("index.html") return tmpl.render(feeds=feeds, nb_feeds=len(feeds), mongo=self.mongo, \ nb_favorites=nb_favorites, nb_unread_articles=nb_unread_articles, \ nb_mail_notifications=nb_mail_notifications, header_text=nb_unread_articles) index.exposed = True @require() def management(self): """ Management page. Allows adding and deleting feeds. Export functions of the MongoDB data base and display some statistics. """ feeds = self.mongo.get_all_feeds() nb_mail_notifications = self.mongo.nb_mail_notifications() nb_favorites = self.mongo.nb_favorites() nb_articles = self.mongo.nb_articles() nb_unread_articles = self.mongo.nb_unread_articles() tmpl = lookup.get_template("management.html") return tmpl.render(feeds=feeds, nb_mail_notifications=nb_mail_notifications, \ nb_favorites=nb_favorites, nb_articles=nb_articles, \ nb_unread_articles=nb_unread_articles) management.exposed = True @require() def statistics(self, word_size=6): """ More advanced statistics. """ articles = self.mongo.get_articles() top_words = utils.top_words(articles, n=50, size=int(word_size)) tag_cloud = utils.tag_cloud(top_words) tmpl = lookup.get_template("statistics.html") return tmpl.render(articles=articles, word_size=word_size, tag_cloud=tag_cloud) statistics.exposed = True @require() def search(self, query=None): """ Simply search for the string 'query' in the description of the article. """ param, _, value = query.partition(':') wordre = re.compile(r'\b%s\b' % param, re.I) feed_id = None if param == "Feed": feed_id, _, query = value.partition(':') feeds = self.mongo.get_all_feeds() tmpl = lookup.get_template("search.html") return tmpl.render(feeds=feeds, feed_id=feed_id, query=query, \ wordre=wordre, mongo=self.mongo) search.exposed = True @require() def fetch(self): """ Fetch all feeds. """ feed_getter = feedgetter.FeedGetter() feed_getter.retrieve_feed() return self.index() fetch.exposed = True @require() def article(self, param): """ Display the article in parameter in a new Web page. """ try: feed_id, article_id = param.split(':') feed = self.mongo.get_feed(feed_id) articles = self.mongo.get_articles(feed_id) article = self.mongo.get_articles(feed_id, article_id) except: return self.error("Bad URL. This article do not exists.") if article["article_readed"] == False: # if the current article is not yet readed, update the database self.mark_as_read("Article:"+article["article_id"]+":"+feed["feed_id"]) # Description (full content) of the article description = article["article_content"] if description: p = re.compile(r'<')
q = re.compile(r'>
')
description = p.sub('<', description)
description = q.sub('>
', description)
description = description + "\nYou are already following this feed!
" else: message = """Feed added. You can now fetch your feeds.
""" tmpl = lookup.get_template("confirmation.html") return tmpl.render(message=message) add_feed.exposed = True @require() def remove_feed(self, feed_id): """ Remove a feed from the file feed.lst and from the MongoDB database. """ feed = self.mongo.get_feed(feed_id) self.mongo.delete_feed(feed_id) utils.remove_feed(feed["feed_link"]) message = """All articles from the feed %s are now removed from the base.""" % (feed["feed_title"],) tmpl = lookup.get_template("confirmation.html") return tmpl.render(message=message) remove_feed.exposed = True @require() def change_feed_url(self, feed_id, old_feed_url, new_feed_url): """ Enables to change the URL of a feed already present in the database. """ self.mongo.update_feed(feed_id, {"feed_link":new_feed_url}) utils.change_feed_url(old_feed_url, new_feed_url) tmpl = lookup.get_template("confirmation.html") return tmpl.render(message="The URL of the feed has been changed.") change_feed_url.exposed = True @require() def change_feed_name(self, feed_id, new_feed_name): """ Enables to change the name of a feed. """ self.mongo.update_feed(feed_id, {"feed_title":new_feed_name}) tmpl = lookup.get_template("confirmation.html") return tmpl.render(message="The name of the feed has been changed.") change_feed_name.exposed = True @require() def change_feed_logo(self, feed_id, new_feed_logo): """ Enables to change the name of a feed. """ self.mongo.update_feed(feed_id, {"feed_image":new_feed_logo}) tmpl = lookup.get_template("confirmation.html") return tmpl.render(message="The logo of the feed has been changed.") change_feed_logo.exposed = True @require() def delete_article(self, param): """ Delete an article. """ try: feed_id, article_id = param.split(':') self.mongo.delete_article(feed_id, article_id) except: return self.error("Bad URL. This article do not exists.") return self.index() delete_article.exposed = True @require() def drop_base(self): """ Delete all articles. """ self.mongo.drop_database() return self.index() drop_base.exposed = True @require() def export(self, export_method): """ Export articles currently loaded from the MongoDB database with the appropriate function of the 'export' module. """ getattr(export, export_method)(self.mongo) try: getattr(export, export_method)(self.mongo) except Exception as e: print(e) return self.error(e) return self.management() export.exposed = True @require() def epub(self, param): """ Export an article to EPUB. """ try: from epub import ez_epub except Exception as e: return self.error(e) try: feed_id, article_id = param.split(':') except: return self.error("Bad URL.") try: feed_id, article_id = param.split(':') feed = self.mongo.get_feed(feed_id) articles = self.mongo.get_articles(feed_id) article = self.mongo.get_articles(feed_id, article_id) except: self.error("This article do not exists.") try: folder = conf.path + "/var/export/epub/" os.makedirs(folder) except OSError: # directories already exists (not a problem) pass section = ez_epub.Section() section.title = article["article_title"].decode('utf-8') section.paragraphs = [utils.clear_string(article["article_content"])] ez_epub.makeBook(article["article_title"], [feed["feed_title"]], [section], \ os.path.normpath(folder) + "article.epub", lang='en-US', cover=None) return self.article(param) epub.exposed = True if __name__ == '__main__': # Point of entry in execution mode root = pyAggr3g470r() root.favicon_ico = cherrypy.tools.staticfile.handler(filename=os.path.join(conf.path + "/img/favicon.png")) cherrypy.config.update({'error_page.404': error_404}) cherrypy.quickstart(root, "/" ,config=conf.path + "/cfg/cherrypy.cfg")