diff options
Diffstat (limited to 'source/pyAggr3g470r.py')
-rwxr-xr-x | source/pyAggr3g470r.py | 606 |
1 files changed, 107 insertions, 499 deletions
diff --git a/source/pyAggr3g470r.py b/source/pyAggr3g470r.py index 9a16d437..9bc53b3e 100755 --- a/source/pyAggr3g470r.py +++ b/source/pyAggr3g470r.py @@ -22,13 +22,13 @@ __author__ = "Cedric Bonhomme" __version__ = "$Revision: 3.6 $" __date__ = "$Date: 2010/01/29 $" -__revision__ = "$Date: 2012/11/8 $" +__revision__ = "$Date: 2012/12/04 $" __copyright__ = "Copyright (c) Cedric Bonhomme" __license__ = "GPLv3" # # This file contains the "Root" class which describes -# all pages of pyAggr3g470r. These pages are: +# all pages (views) of pyAggr3g470r. These pages are: # - main page; # - management; # - history; @@ -36,13 +36,19 @@ __license__ = "GPLv3" # - notifications; # - unread; # - feed summary. +# Templates are described in ./templates with the Mako +# template library. # import os import re -import cherrypy import calendar +import cherrypy +from mako.template import Template +from mako.lookup import TemplateLookup +lookup = TemplateLookup(directories=['templates']) + from collections import Counter import datetime @@ -56,7 +62,7 @@ from auth import AuthController, require, member_of, name_is #from qrcode import qr -def error_page_404(status, message, traceback, version): +def error_404(status, message, traceback, version): """ Display an error if the page does not exist. """ @@ -97,9 +103,7 @@ htmlfooter = '<p>This software is under GPLv3 license. You are welcome to copy, htmlnav = '<body>\n<h1><div class="right innerlogo"><a href="/"><img src="/img/tuxrss.png"' + \ """ title="What's new today?"/></a>""" + \ - '</div><a name="top"><a href="/">pyAggr3g470r - News aggregator</a></a></h1>\n<a' + \ - ' href="http://bitbucket.org/cedricbonhomme/pyaggr3g470r/" rel="noreferrer" target="_blank">' + \ - 'pyAggr3g470r (source code)</a>' + '</div><a name="top"><a href="/">pyAggr3g470r - News aggregator</a></a></h1>\n' class RestrictedArea(object): """ @@ -140,126 +144,14 @@ class pyAggr3g470r(object): nb_unread_articles = self.mongo.nb_unread_articles() nb_favorites = self.mongo.nb_favorites() nb_mail_notifications = self.mongo.nb_mail_notifications() - - # if there are unread articles, display the number in the tab of the browser - html = htmlheader((nb_unread_articles and \ - ['(' + str(nb_unread_articles) +')'] or \ - [""])[0]) - html += htmlnav - html += self.create_right_menu() - html += """<div class="left inner">\n""" - - if feeds: - html += '<a href="/management/"><img src="/img/management.png" title="Management" /></a>\n' - html += '<a href="/history/"><img src="/img/history.png" title="History" /></a>\n' - html += ' \n' - - html += """<a href="/favorites/"><img src="/img/heart-32x32.png" title="Your favorites (%s)" /></a>\n""" % \ - (nb_favorites,) - - html += """<a href="/notifications/"><img src="/img/email-follow.png" title="Active e-mail notifications (%s)" /></a>\n""" % \ - (nb_mail_notifications,) - - html += ' ' - if nb_unread_articles != 0: - html += '<a href="/mark_as_read/"><img src="/img/mark-as-read.png" title="Mark articles as read" /></a>\n' - html += """<a href="/unread/"><img src="/img/unread.png" title="Unread article(s): %s" /></a>\n""" % \ - (nb_unread_articles,) - html += '<a accesskey="F" href="/fetch/"><img src="/img/check-news.png" title="Check for news" /></a>\n' - - - # The main page display all the feeds. - for feed in feeds: - html += """<h2><a name="%s"><a href="%s" rel="noreferrer" - target="_blank">%s</a></a> - <a href="%s" rel="noreferrer" - target="_blank"><img src="%s" width="28" height="28" /></a></h2>\n""" % \ - (feed["feed_id"], feed["site_link"], feed["feed_title"], \ - feed["feed_link"], feed["feed_image"]) - - # The main page display only 10 articles by feeds. - for article in self.mongo.get_articles_from_collection(feed["feed_id"], limit=10): - if article["article_readed"] == False: - # not readed articles are in bold - not_read_begin, not_read_end = "<b>", "</b>" - else: - not_read_begin, not_read_end = "", "" - - # display a heart for faved articles - if article["article_like"] == True: - like = """ <img src="/img/heart.png" title="I like this article!" />""" - else: - like = "" - - # Descrition for the CSS ToolTips - article_content = utils.clear_string(article["article_content"]) - if article_content: - description = " ".join(article_content.split(' ')[:55]) - else: - description = "No description." - # Title of the article - article_title = article["article_title"] - if len(article_title) >= 80: - article_title = article_title[:80] + " ..." - - # a description line per article (date, title of the article and - # CSS description tooltips on mouse over) - html += article["article_date"].strftime('%Y-%m-%d %H:%M') + " - " + \ - """<a class="tooltip" href="/article/%s:%s" rel="noreferrer" target="_blank">%s%s%s<span class="classic">%s</span></a>""" % \ - (feed["feed_id"], article["article_id"], not_read_begin, \ - article_title, not_read_end, description) + like + "<br />\n" - html += "<br />\n" - - # some options for the current feed - html += """<a href="/articles/%s">All articles</a> """ % (feed["feed_id"],) - html += """<a href="/feed/%s">Feed summary</a> """ % (feed["feed_id"],) - if self.mongo.nb_unread_articles(feed["feed_id"]) != 0: - html += """ <a href="/mark_as_read/Feed_FromMainPage:%s">Mark all as read</a>""" % (feed["feed_id"],) - html += """ <a href="/unread/%s" title="Unread article(s)">Unread article(s) (%s)</a>""" % (feed["feed_id"], self.mongo.nb_unread_articles(feed["feed_id"])) - if feed["mail"] == "0": - html += """<br />\n<a href="/mail_notification/1:%s" title="By e-mail">Stay tuned</a>""" % (feed["feed_id"],) - else: - html += """<br />\n<a href="/mail_notification/0:%s" title="By e-mail">Stop staying tuned</a>""" % (feed["feed_id"],) - html += """<h4><a href="/#top">Top</a></h4>""" - html += "<hr />\n" - html += htmlfooter - return html + 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 create_right_menu(self): - """ - Create the right menu. - """ - html = """<div class="right inner">\n""" - html += """<form method=get action="/search/"><input type="search" name="query" value="" placeholder="Search articles" maxlength=2048 autocomplete="on"></form>\n""" - html += "<hr />\n" - # insert the list of feeds in the menu - html += self.create_list_of_feeds() - html += "</div>\n" - - return html - - @require() - def create_list_of_feeds(self): - """ - Create the list of feeds. - """ - feeds = self.mongo.get_all_feeds() - html = """<div class="nav_container">Your feeds (%s):<br />\n""" % len(feeds) - for feed in feeds: - if self.mongo.nb_unread_articles(feed["feed_id"]) != 0: - # not readed articles are in bold - not_read_begin, not_read_end = "<b>", "</b>" - else: - not_read_begin, not_read_end = "", "" - html += """<div><a href="/#%s">%s</a> (<a href="/unread/%s" title="Unread article(s)">%s%s%s</a> / %s)</div>""" % \ - (feed["feed_id"], feed["feed_title"], feed["feed_id"], not_read_begin, \ - self.mongo.nb_unread_articles(feed["feed_id"]), not_read_end, self.mongo.nb_articles(feed["feed_id"])) - return html + "</div>" - - @require() def management(self): """ Management page. @@ -271,51 +163,10 @@ class pyAggr3g470r(object): nb_favorites = self.mongo.nb_favorites() nb_articles = self.mongo.nb_articles() nb_unread_articles = self.mongo.nb_unread_articles() - - html = htmlheader() - html += htmlnav - html += """<div class="left inner">\n""" - html += "<h1>Add Feeds</h1>\n" - # Form: add a feed - html += """<form method=get action="/add_feed/"><input type="url" name="url" placeholder="URL of a site" maxlength=2048 autocomplete="off">\n<input type="submit" value="OK"></form>\n""" - - if feeds: - # Form: delete a feed - html += "<h1>Delete Feeds</h1>\n" - html += """<form method=get action="/remove_feed/"><select name="feed_id">\n""" - for feed in feeds: - html += """\t<option value="%s">%s</option>\n""" % (feed["feed_id"], feed["feed_title"]) - html += """</select><input type="submit" value="OK"></form>\n""" - - html += """<p>Active e-mail notifications: <a href="/notifications/">%s</a></p>\n""" % \ - (nb_mail_notifications,) - html += """<p>You like <a href="/favorites/">%s</a> article(s).</p>\n""" % \ - (nb_favorites, ) - - html += "<hr />\n" - - # Informations about the data base of articles - html += """<p>%s article(s) are stored in the database with - <a href="/unread/">%s unread article(s)</a>.<br />\n""" % \ - (nb_articles, nb_unread_articles) - #html += """Database: %s.\n<br />Size: %s bytes.<br />\n""" % \ - #(os.path.abspath(utils.sqlite_base), os.path.getsize(utils.sqlite_base)) - html += '<a href="/statistics/">Advanced statistics.</a></p>\n' - - html += """<form method=get action="/fetch/">\n<input type="submit" value="Fetch all feeds"></form>\n""" - html += """<form method=get action="/drop_base">\n<input type="submit" value="Delete all articles"></form>\n""" - - # Export functions - html += "<h1>Export articles</h1>\n\n" - html += """<form method=get action="/export/"><select name="export_method">\n""" - html += """\t<option value="export_html" selected='selected'>HTML (simple Webzine)</option>\n""" - html += """\t<option value="export_epub">ePub</option>\n""" - html += """\t<option value="export_pdf">PDF</option>\n""" - html += """\t<option value="export_txt">Text</option>\n""" - html += """</select>\n\t<input type="submit" value="Export">\n</form>\n""" - html += "<hr />" - html += htmlfooter - return html + 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 @@ -324,26 +175,11 @@ class pyAggr3g470r(object): """ More advanced statistics. """ - articles = self.mongo.get_all_articles() - html = htmlheader() - html += htmlnav - html += """<div class="left inner">\n""" - - # Some statistics (most frequent word) - if articles: - top_words = utils.top_words(articles, n=50, size=int(word_size)) - html += "<h1>Statistics</h1>\n" - html += "<h3>Tag cloud</h3>\n" - # Tags cloud - html += '<form method=get action="/statistics/">\n' - html += "Minimum size of a word:\n" - html += """<input type="number" name="word_size" value="%s" min="2" max="15" step="1" size="2"></form>\n""" % (word_size) - html += '<div style="width: 35%; overflow:hidden; text-align: justify">' + \ - utils.tag_cloud(top_words) + '</div>' - html += "<hr />\n" - - html += htmlfooter - return html + 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 @@ -358,69 +194,10 @@ class pyAggr3g470r(object): feed_id = None if param == "Feed": feed_id, _, query = value.partition(':') - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" - html += """<h1>Articles containing the string <i>%s</i></h1><br />""" % (query,) - - if feed_id is not None: - for article in self.mongo.get_articles_from_collection(feed_id): - article_content = utils.clear_string(article.article_description) - if not article_content: - utils.clear_string(article.article_title) - if wordre.findall(article_content) != []: - if article.article_readed == "0": - # not readed articles are in bold - not_read_begin, not_read_end = "<b>", "</b>" - else: - not_read_begin, not_read_end = "", "" - - html += article.article_date + " - " + not_read_begin + \ - """<a href="/article/%s:%s" rel="noreferrer" target="_blank">%s</a>""" % \ - (feed_id, article.article_id, article.article_title) + \ - not_read_end + """<br />\n""" - else: - feeds = self.mongo.get_all_feeds() - for feed in feeds: - new_feed_section = True - for article in self.mongo.get_articles_from_collection(feed["feed_id"]): - article_content = utils.clear_string(article["article_content"]) - if not article_content: - utils.clear_string(article["article_title"]) - if wordre.findall(article_content) != []: - if new_feed_section is True: - new_feed_section = False - html += """<h2><a href="/articles/%s" rel="noreferrer" target="_blank">%s</a><a href="%s" rel="noreferrer" target="_blank"><img src="%s" width="28" height="28" /></a></h2>\n""" % \ - (feed["feed_id"], feed["feed_title"], feed["feed_link"], feed["feed_image"]) - - if article["article_readed"] == False: - # not readed articles are in bold - not_read_begin, not_read_end = "<b>", "</b>" - else: - not_read_begin, not_read_end = "", "" - - # display a heart for faved articles - if article["article_like"] == True: - like = """ <img src="/img/heart.png" title="I like this article!" />""" - else: - like = "" - - # descrition for the CSS ToolTips - article_content = utils.clear_string(article["article_content"]) - if article_content: - description = " ".join(article_content[:500].split(' ')[:-1]) - else: - description = "No description." - - # a description line per article (date, title of the article and - # CSS description tooltips on mouse over) - html += article["article_date"].strftime('%Y-%m-%d %H:%M') + " - " + \ - """<a class="tooltip" href="/article/%s:%s" rel="noreferrer" target="_blank">%s%s%s<span class="classic">%s</span></a>""" % \ - (feed["feed_id"], article["article_id"], not_read_begin, \ - article["article_title"][:150], not_read_end, description) + like + "<br />\n" - html += "<hr />" - html += htmlfooter - return html + 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 @@ -443,44 +220,25 @@ class pyAggr3g470r(object): try: feed_id, article_id = param.split(':') feed = self.mongo.get_feed(feed_id) - articles = self.mongo.get_articles_from_collection(feed_id) - article = self.mongo.get_article(feed_id, article_id) + articles = self.mongo.get_articles(feed_id) + article = self.mongo.get_articles(feed_id, article_id) except: - return self.error_page("Bad URL. This article do not exists.") - html = htmlheader(article["article_title"]) - html += htmlnav - html += """<div>""" + 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"]) - html += '\n<div style="width: 50%; overflow:hidden; text-align: justify; margin:0 auto">\n' - # Title of the article - html += """<h1><i>%s</i> from <a href="/feed/%s">%s</a></h1>\n<br />\n""" % \ - (article["article_title"], feed_id, feed["feed_title"]) - if article["article_like"] == True: - html += """<a href="/like/0:%s:%s"><img src="/img/heart.png" title="I like this article!" /></a>""" % \ - (feed_id, article["article_id"]) - else: - html += """<a href="/like/1:%s:%s"><img src="/img/heart_open.png" title="Click if you like this article." /></a>""" % \ - (feed_id, article["article_id"]) - html += """ <a href="/delete_article/%s:%s"><img src="/img/cross.png" title="Delete this article" /></a>""" % \ - (feed_id, article["article_id"]) - html += "<br /><br />" - # Description (full content) of the article description = article["article_content"] if description: p = re.compile(r'<code><') q = re.compile(r'></code>') - description = p.sub('<code><', description) description = q.sub('></code>', description) - - html += description + "\n<br /><br /><br />" + description = description + "\n<br /><br /><br />" else: - html += "No description available.\n<br /><br /><br />" + description += "No description available.\n<br /><br /><br />" """ # Generation of the QR Code for the current article try: @@ -500,8 +258,8 @@ class pyAggr3g470r(object): # Previous and following articles previous, following = None, None - liste = self.mongo.get_articles_from_collection(feed_id) - for current_article in self.mongo.get_articles_from_collection(feed_id): + liste = self.mongo.get_articles(feed_id) + for current_article in self.mongo.get_articles(feed_id): next(articles) if current_article["article_id"] == article_id: break @@ -513,70 +271,9 @@ class pyAggr3g470r(object): except StopIteration: previous = liste[0] - html += """<div style="float:right;"><a href="/article/%s:%s" title="%s"><img src="/img/following-article.png" /></a></div>\n""" % \ - (feed_id, following["article_id"], following["article_title"]) - html += """<div style="float:left;"><a href="/article/%s:%s" title="%s"><img src="/img/previous-article.png" /></a></div>\n""" % \ - (feed_id, previous["article_id"], previous["article_title"]) - - html += "\n</div>\n" - - # Footer menu - html += "<hr />\n" - html += """\n<a href="/plain_text/%s:%s">Plain text</a>\n""" % (feed_id, article["article_id"]) - html += """ - <a href="/epub/%s:%s">Export to EPUB</a>\n""" % (feed_id, article["article_id"]) - html += """<br />\n<a href="%s">Complete story</a>\n<br />\n""" % (article["article_link"],) - - # Share this article: - html += "Share this article:<br />\n" - # on Diaspora - html += """<a href="javascript:(function(){f='https://%s/bookmarklet?url=%s&title=%s&notes=%s&v=1&';a=function(){if(!window.open(f+'noui=1&jump=doclose','diasporav1','location=yes,links=no,scrollbars=no,toolbar=no,width=620,height=250'))location.href=f+'jump=yes'};if(/Firefox/.test(navigator.userAgent)){setTimeout(a,0)}else{a()}})()">\n\t - <img src="/img/diaspora.png" title="Share on Diaspora" /></a>\n""" % \ - (conf.DIASPORA_POD, article["article_link"], article["article_title"], "via pyAggr3g470r") - - # on Identi.ca - html += """\n\n<a href="http://identi.ca/index.php?action=newnotice&status_textarea=%s: %s" title="Share on Identi.ca" target="_blank"><img src="/img/identica.png" /></a>""" % \ - (article["article_title"], article["article_link"]) - - # on Hacker News - html += """\n\n<a href='javascript:window.location="http://news.ycombinator.com/submitlink?u="+encodeURIComponent("%s")+"&t="+encodeURIComponent("%s")'><img src="/img/hacker-news.png" title="Share on Hacker News" /></a>""" % \ - (article["article_link"], article["article_title"]) - - # on Pinboard - html += """\n\n\t<a href="https://api.pinboard.in/v1/posts/add?url=%s&description=%s" - rel="noreferrer" target="_blank">\n - <img src="/img/pinboard.png" title="Share on Pinboard" /></a>""" % \ - (article["article_link"], article["article_title"]) - - # on Digg - html += """\n\n\t<a href="http://digg.com/submit?url=%s&title=%s" - rel="noreferrer" target="_blank">\n - <img src="/img/digg.png" title="Share on Digg" /></a>""" % \ - (article["article_link"], article["article_title"]) - # on reddit - html += """\n\n\t<a href="http://reddit.com/submit?url=%s&title=%s" - rel="noreferrer" target="_blank">\n - <img src="/img/reddit.png" title="Share on reddit" /></a>""" % \ - (article["article_link"], article["article_title"]) - # on Scoopeo - html += """\n\n\t<a href="http://scoopeo.com/scoop/new?newurl=%s&title=%s" - rel="noreferrer" target="_blank">\n - <img src="/img/scoopeo.png" title="Share on Scoopeo" /></a>""" % \ - (article["article_link"], article["article_title"]) - # on Blogmarks - html += """\n\n\t<a href="http://blogmarks.net/my/new.php?url=%s&title=%s" - rel="noreferrer" target="_blank">\n - <img src="/img/blogmarks.png" title="Share on Blogmarks" /></a>""" % \ - (article["article_link"], article["article_title"]) - - # Google +1 button - html += """\n\n<g:plusone size="standard" count="true" href="%s"></g:plusone>""" % \ - (article["article_link"],) - - - # QRCode (for smartphone) - html += """<br />\n<a href="/var/qrcode/%s.png"><img src="/var/qrcode/%s.png" title="Share with your smartphone" width="500" height="500" /></a>""" % (article_id, article_id) - html += "<hr />\n" + htmlfooter - return html + tmpl = lookup.get_template("article.html") + return tmpl.render(header_text=article["article_title"], article=article, previous=previous, following=following, \ + diaspora=conf.DIASPORA_POD, feed=feed, description=description) article.exposed = True @@ -589,12 +286,12 @@ class pyAggr3g470r(object): """ try: feed = self.mongo.get_feed(feed_id) - articles = self.mongo.get_articles_from_collection(feed_id, limit=10) + articles = self.mongo.get_articles(feed_id, limit=10) nb_articles_feed = self.mongo.nb_articles(feed_id) nb_articles_total = self.mongo.nb_articles() nb_unread_articles_feed = self.mongo.nb_unread_articles(feed_id) except KeyError: - return self.error_page("This feed do not exists.") + return self.error("This feed do not exists.") html = htmlheader() html += htmlnav html += """<div class="left inner">""" @@ -696,7 +393,7 @@ class pyAggr3g470r(object): (feed["feed_id"],) dic = {} - top_words = utils.top_words(articles = self.mongo.get_articles_from_collection(feed_id), n=50, size=int(word_size)) + top_words = utils.top_words(articles = self.mongo.get_articles(feed_id), n=50, size=int(word_size)) html += "</br />\n<h1>Tag cloud</h1>\n" # Tags cloud html += """<form method=get action="/feed/%s">\n""" % (feed["feed_id"],) @@ -719,50 +416,11 @@ class pyAggr3g470r(object): """ try: feed = self.mongo.get_feed(feed_id) - articles = self.mongo.get_articles_from_collection(feed_id) + articles = self.mongo.get_articles(feed_id) except KeyError: - return self.error_page("This feed do not exists.") - html = htmlheader() - html += htmlnav - html += """<div class="right inner">\n""" - html += """<a href="/mark_as_read/Feed:%s">Mark all articles from this feed as read</a>""" % (feed_id,) - html += """<br />\n<form method=get action="/search/%s"><input type="search" name="query" value="" placeholder="Search this feed" maxlength=2048 autocomplete="on"></form>\n""" % ("Feed:"+feed_id,) - html += "<hr />\n" - html += self.create_list_of_feeds() - html += """</div> <div class="left inner">""" - html += """<h1>Articles of the feed <i><a href="/feed/%s">%s</a></i></h1><br />""" % (feed_id, feed["feed_title"]) - - for article in articles: - - if article["article_readed"] == False: - # not readed articles are in bold - not_read_begin, not_read_end = "<b>", "</b>" - else: - not_read_begin, not_read_end = "", "" - - if article["article_like"] == True: - like = """ <img src="/img/heart.png" title="I like this article!" />""" - else: - like = "" - - # descrition for the CSS ToolTips - article_content = utils.clear_string(article["article_content"]) - if article_content: - description = " ".join(article_content[:500].split(' ')[:-1]) - else: - description = "No description." - - # a description line per article (date, title of the article and - # CSS description tooltips on mouse over) - html += article["article_date"].strftime('%Y-%m-%d %H:%M') + " - " + \ - """<a class="tooltip" href="/article/%s:%s" rel="noreferrer" target="_blank">%s%s%s<span class="classic">%s</span></a>""" % \ - (feed_id, article["article_id"], not_read_begin, \ - article["article_title"][:150], not_read_end, description) + like + "<br />\n" - - html += """\n<h4><a href="/">All feeds</a></h4>""" - html += "<hr />\n" - html += htmlfooter - return html + return self.error("This feed do not exists.") + tmpl = lookup.get_template("articles.html") + return tmpl.render(articles=articles, feed=feed) articles.exposed = True @@ -786,7 +444,7 @@ class pyAggr3g470r(object): nb_unread = 0 # For all unread article of the current feed. - for article in self.mongo.get_articles_from_collection(feed["feed_id"], condition=("article_readed", False)): + for article in self.mongo.get_articles(feed["feed_id"], condition=("article_readed", False)): nb_unread += 1 if new_feed_section is True: new_feed_section = False @@ -816,12 +474,12 @@ class pyAggr3g470r(object): try: feed = self.mongo.get_feed(feed_id) except: - self.error_page("This feed do not exists.") + self.error("This feed do not exists.") html += """<h1>Unread article(s) of the feed <a href="/articles/%s">%s</a></h1> <br />""" % (feed_id, feed["feed_title"]) # For all unread article of the feed. - for article in self.mongo.get_articles_from_collection(feed_id, condition=("article_readed", False)): + for article in self.mongo.get_articles(feed_id, condition=("article_readed", False)): # descrition for the CSS ToolTips article_content = utils.clear_string(article["article_content"]) if article_content: @@ -877,7 +535,7 @@ class pyAggr3g470r(object): timeline = Counter() for feed in feeds: new_feed_section = True - for article in self.mongo.get_articles_from_collection(feed["feed_id"]): + for article in self.mongo.get_articles(feed["feed_id"]): if query == "all": timeline[str(article["article_date"]).split(' ')[0].split('-')[0]] += 1 @@ -944,37 +602,28 @@ class pyAggr3g470r(object): try: feed_id, article_id = target.split(':') feed = self.mongo.get_feed(feed_id) - article = self.mongo.get_article(feed_id, article_id) + article = self.mongo.get_articles(feed_id, article_id) except: - return self.error_page("Bad URL. This article do not exists.") - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" - html += """<h1><i>%s</i> from <a href="/articles/%s">%s</a></h1>\n<br />\n"""% \ - (article["article_title"], feed_id, feed["feed_title"]) + return self.error("Bad URL. This article do not exists.") description = utils.clear_string(article["article_content"]) - if description: - html += description - else: - html += "No description available." - html += "\n<hr />\n" + htmlfooter - return html + if not description: + description = "Unvailable" + tmpl = lookup.get_template("plain_text.html") + return tmpl.render(feed_title=feed["feed_title"], \ + article_title=article["article_title"], \ + description = description) plain_text.exposed = True @require() - def error_page(self, message): + def error(self, message): """ Display a message (bad feed id, bad article id, etc.) """ - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" - html += """%s""" % message - html += "\n<hr />\n" + htmlfooter - return html + tmpl = lookup.get_template("error.html") + return tmpl.render(message=message) - error_page.exposed = True + error.exposed = True @require() def mark_as_read(self, target=""): @@ -1002,21 +651,9 @@ class pyAggr3g470r(object): """ List all active e-mail notifications. """ - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" feeds = self.mongo.get_all_feeds(condition=("mail",True)) - if feeds != []: - html += "<h1>You are receiving e-mails for the following feeds:</h1>\n" - for feed in feeds: - html += """\t<a href="/articles/%s">%s</a> - <a href="/mail_notification/0:%s">Stop</a><br />\n""" % \ - (feed["feed_id"], feed["feed_title"], feed["feed_id"]) - else: - html += "<p>No active notifications.<p>\n" - html += """<p>Notifications are sent to: <a href="mail:%s">%s</a></p>""" % \ - (conf.mail_to, conf.mail_to) - html += "\n<hr />\n" + htmlfooter - return html + tmpl = lookup.get_template("notifications.html") + return tmpl.render(feeds=feeds, mail_to=conf.mail_to) notifications.exposed = True @@ -1028,8 +665,7 @@ class pyAggr3g470r(object): try: action, feed_id = param.split(':') except: - return self.error_page("Bad URL. This feed do not exists.") - + return self.error("Bad URL. This feed do not exists.") return self.index() mail_notification.exposed = True @@ -1041,9 +677,9 @@ class pyAggr3g470r(object): """ try: like, feed_id, article_id = param.split(':') - articles = self.mongo.get_article(feed_id, article_id) + articles = self.mongo.get_articles(feed_id, article_id) except: - return self.error_page("Bad URL. This article do not exists.") + return self.error("Bad URL. This article do not exists.") self.mongo.like_article("1"==like, feed_id, article_id) return self.article(feed_id+":"+article_id) @@ -1055,36 +691,33 @@ class pyAggr3g470r(object): List of favorites articles """ feeds = self.mongo.get_all_feeds() - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" - html += "<h1>Your favorites articles</h1>" + articles = {} for feed in feeds: - new_feed_section = True - for article in self.mongo.get_articles_from_collection(feed["feed_id"]): - if article["article_like"] == True: - if new_feed_section is True: - new_feed_section = False - html += """<h2><a name="%s"><a href="%s" rel="noreferrer"target="_blank">%s</a></a><a href="%s" rel="noreferrer" target="_blank"><img src="%s" width="28" height="28" /></a></h2>\n""" % \ - (feed["feed_id"], feed["site_link"], feed["feed_title"], feed["feed_link"], feed["feed_image"]) + articles[feed["feed_id"]] = self.mongo.get_favorites(feed["feed_id"]) + tmpl = lookup.get_template("favorites.html") + return tmpl.render(feeds=feeds, \ + articles=articles) - # descrition for the CSS ToolTips - article_content = utils.clear_string(article["article_content"]) - if article_content: - description = " ".join(article_content[:500].split(' ')[:-1]) - else: - description = "No description." + favorites.exposed = True - # a description line per article (date, title of the article and - # CSS description tooltips on mouse over) - html += article["article_date"].strftime('%Y-%m-%d %H:%M') + " - " + \ - """<a class="tooltip" href="/article/%s:%s" rel="noreferrer" target="_blank">%s<span class="classic">%s</span></a><br />\n""" % \ - (feed["feed_id"], article["article_id"], article["article_title"][:150], description) - html += "<hr />\n" - html += htmlfooter - return html + @require() + def inactives(self, nb_days=365): + """ + List of favorites articles + """ + feeds = self.mongo.get_all_feeds() + today = datetime.datetime.now() + inactives = [] + for feed in feeds: + more_recent_article = self.mongo.get_articles(feed["feed_id"], limit=1) + last_post = next(more_recent_article)["article_date"] + elapsed = today - last_post + if elapsed > datetime.timedelta(days=int(nb_days)): + inactives.append((feed, elapsed)) + tmpl = lookup.get_template("inactives.html") + return tmpl.render(inactives=inactives, nb_days=int(nb_days)) - favorites.exposed = True + inactives.exposed = True @require() def add_feed(self, url): @@ -1097,7 +730,7 @@ class pyAggr3g470r(object): # search the feed in the HTML page with BeautifulSoup feed_url = utils.search_feed(url) if feed_url is None: - return self.error_page("Impossible to find a feed at this URL.") + return self.error("Impossible to find a feed at this URL.") # if a feed exists else: result = utils.add_feed(feed_url) @@ -1118,20 +751,12 @@ class pyAggr3g470r(object): """ Remove a feed from the file feed.lst and from the MongoDB database. """ - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" - feed = self.mongo.get_feed(feed_id) self.mongo.delete_feed(feed_id) utils.remove_feed(feed["feed_link"]) - - html += """<p>All articles from the feed <i>%s</i> are now removed from the base.</p><br />""" % \ - (feed["feed_title"],) - html += """<a href="/management/">Back to the management page.</a><br />\n""" - html += "<hr />\n" - html += htmlfooter - return html + message = """All articles from the feed <i>%s</i> are now removed from the base.""" % (feed["feed_title"],) + tmpl = lookup.get_template("confirmation.html") + return tmpl.render(message=message) remove_feed.exposed = True @@ -1140,15 +765,10 @@ class pyAggr3g470r(object): """ Enables to change the URL of a feed already present in the database. """ - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" self.mongo.update_feed(feed_id, {"feed_link":new_feed_url}) utils.change_feed_url(old_feed_url, new_feed_url) - html += "<p>The URL of the feed has been changed.</p>" - html += "<hr />\n" - html += htmlfooter - return html + tmpl = lookup.get_template("confirmation.html") + return tmpl.render(message="The URL of the feed has been changed.") change_feed_url.exposed = True @@ -1157,14 +777,9 @@ class pyAggr3g470r(object): """ Enables to change the name of a feed. """ - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" self.mongo.update_feed(feed_id, {"feed_title":new_feed_name}) - html += "<p>The name of the feed has been changed.</p>" - html += "<hr />\n" - html += htmlfooter - return html + tmpl = lookup.get_template("confirmation.html") + return tmpl.render(message="The name of the feed has been changed.") change_feed_name.exposed = True @@ -1173,14 +788,9 @@ class pyAggr3g470r(object): """ Enables to change the name of a feed. """ - html = htmlheader() - html += htmlnav - html += """<div class="left inner">""" self.mongo.update_feed(feed_id, {"feed_image":new_feed_logo}) - html += "<p>The logo of the feed has been changed.</p>" - html += "<hr />\n" - html += htmlfooter - return html + tmpl = lookup.get_template("confirmation.html") + return tmpl.render(message="The logo of the feed has been changed.") change_feed_logo.exposed = True @@ -1193,7 +803,7 @@ class pyAggr3g470r(object): feed_id, article_id = param.split(':') self.mongo.delete_article(feed_id, article_id) except: - return self.error_page("Bad URL. This article do not exists.") + return self.error("Bad URL. This article do not exists.") return self.index() @@ -1220,7 +830,7 @@ class pyAggr3g470r(object): getattr(export, export_method)(self.mongo) except Exception as e: print(e) - return self.error_page(e) + return self.error(e) return self.management() export.exposed = True @@ -1233,18 +843,18 @@ class pyAggr3g470r(object): try: from epub import ez_epub except Exception as e: - return self.error_page(e) + return self.error(e) try: feed_id, article_id = param.split(':') except: - return self.error_page("Bad URL.") + return self.error("Bad URL.") try: feed_id, article_id = param.split(':') feed = self.mongo.get_feed(feed_id) - articles = self.mongo.get_articles_from_collection(feed_id) - article = self.mongo.get_article(feed_id, article_id) + articles = self.mongo.get_articles(feed_id) + article = self.mongo.get_articles(feed_id, article_id) except: - self.error_page("This article do not exists.") + self.error("This article do not exists.") try: folder = conf.path + "/var/export/epub/" os.makedirs(folder) @@ -1265,7 +875,5 @@ 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({ 'server.socket_port': 12556, 'server.socket_host': "0.0.0.0"}) - cherrypy.config.update({'error_page.404': error_page_404}) - + cherrypy.config.update({'error_page.404': error_404}) cherrypy.quickstart(root, "/" ,config=conf.path + "/cfg/cherrypy.cfg") |