diff options
Diffstat (limited to 'pyaggr3g470r/views')
-rw-r--r-- | pyaggr3g470r/views/__init__.py | 1 | ||||
-rw-r--r-- | pyaggr3g470r/views/api/feed.py | 4 | ||||
-rw-r--r-- | pyaggr3g470r/views/article.py | 2 | ||||
-rw-r--r-- | pyaggr3g470r/views/feed.py | 21 | ||||
-rw-r--r-- | pyaggr3g470r/views/icon.py | 14 | ||||
-rw-r--r-- | pyaggr3g470r/views/views.py | 26 |
6 files changed, 34 insertions, 34 deletions
diff --git a/pyaggr3g470r/views/__init__.py b/pyaggr3g470r/views/__init__.py index 029dcb7d..36d382bd 100644 --- a/pyaggr3g470r/views/__init__.py +++ b/pyaggr3g470r/views/__init__.py @@ -3,3 +3,4 @@ from .api import * from .article import article_bp, articles_bp from .feed import feed_bp, feeds_bp +from .icon import icon_bp diff --git a/pyaggr3g470r/views/api/feed.py b/pyaggr3g470r/views/api/feed.py index 530f3fef..7d8cdf38 100644 --- a/pyaggr3g470r/views/api/feed.py +++ b/pyaggr3g470r/views/api/feed.py @@ -20,7 +20,7 @@ FEED_ATTRS = {'title': {'type': str}, 'site_link': {'type': str}, 'enabled': {'type': bool, 'default': True}, 'etag': {'type': str, 'default': ''}, - 'icon': {'type': str, 'default': ''}, + 'icon_url': {'type': str, 'default': ''}, 'last_modified': {'type': str}, 'last_retrieved': {'type': str}, 'last_error': {'type': str}, @@ -54,7 +54,7 @@ class FetchableFeedAPI(PyAggAbstractResource): if g.user.refresh_rate: args['refresh_rate'] = g.user.refresh_rate - if args.pop('retreive_all'): + if args.pop('retreive_all', False): contr = self.wider_controller else: contr = self.controller diff --git a/pyaggr3g470r/views/article.py b/pyaggr3g470r/views/article.py index 6de07ad3..524bf6dd 100644 --- a/pyaggr3g470r/views/article.py +++ b/pyaggr3g470r/views/article.py @@ -4,6 +4,7 @@ from flask import Blueprint, g, render_template, redirect from pyaggr3g470r import controllers, utils +from pyaggr3g470r.lib.view_utils import etag_match from pyaggr3g470r.decorators import pyagg_default_decorator articles_bp = Blueprint('articles', __name__, url_prefix='/articles') @@ -19,6 +20,7 @@ def redirect_to_article(article_id): @article_bp.route('/<int:article_id>', methods=['GET']) @pyagg_default_decorator +@etag_match def article(article_id=None): """ Presents the content of an article. diff --git a/pyaggr3g470r/views/feed.py b/pyaggr3g470r/views/feed.py index fb3ea4c7..afb51903 100644 --- a/pyaggr3g470r/views/feed.py +++ b/pyaggr3g470r/views/feed.py @@ -14,6 +14,7 @@ from flask.ext.login import login_required import conf from pyaggr3g470r import utils +from pyaggr3g470r.lib.view_utils import etag_match from pyaggr3g470r.lib.feed_utils import construct_feed_from from pyaggr3g470r.forms import AddFeedForm from pyaggr3g470r.controllers import FeedController, ArticleController @@ -24,6 +25,7 @@ feed_bp = Blueprint('feed', __name__, url_prefix='/feed') @feeds_bp.route('/', methods=['GET']) @login_required +@etag_match def feeds(): "Lists the subscribed feeds in a table." art_contr = ArticleController(g.user.id) @@ -35,6 +37,7 @@ def feeds(): @feed_bp.route('/<int:feed_id>', methods=['GET']) @login_required +@etag_match def feed(feed_id=None): "Presents detailed information about a feed." feed = FeedController(g.user.id).get(id=feed_id) @@ -138,6 +141,7 @@ def update(action, feed_id=None): @feed_bp.route('/create', methods=['GET']) @feed_bp.route('/edit/<int:feed_id>', methods=['GET']) @login_required +@etag_match def form(feed_id=None): action = gettext("Add a feed") head_titles = [action] @@ -196,20 +200,3 @@ def process_form(feed_id=None): flash(gettext("Downloading articles for the new feed..."), 'info') return redirect(url_for('feed.form', feed_id=new_feed.id)) - - -@feed_bp.route('/icon/<int:feed_id>', methods=['GET']) -@login_required -def icon(feed_id): - icon = FeedController(None if g.user.is_admin() else g.user.id)\ - .get(id=feed_id).icon - etag = md5(icon.encode('utf8')).hexdigest() - headers = {'Cache-Control': 'max-age=86400', 'etag': etag} - if request.headers.get('if-none-match') == etag: - return Response(status=304, headers=headers) - if '\n' in icon: - content_type, *_, icon = icon.split() - headers['content-type'] = content_type - else: - headers['content-type'] = 'application/image' - return Response(base64.b64decode(icon), headers=headers) diff --git a/pyaggr3g470r/views/icon.py b/pyaggr3g470r/views/icon.py new file mode 100644 index 00000000..2f51304a --- /dev/null +++ b/pyaggr3g470r/views/icon.py @@ -0,0 +1,14 @@ +import base64 +from flask import Blueprint, Response, request +from pyaggr3g470r.controllers import IconController +from pyaggr3g470r.lib.view_utils import etag_match + +icon_bp = Blueprint('icon', __name__, url_prefix='/icon') + +@icon_bp.route('/', methods=['GET']) +@etag_match +def icon(): + icon = IconController().get(url=request.args['url']) + headers = {'Cache-Control': 'max-age=86400', + 'Content-Type': icon.mimetype} + return Response(base64.b64decode(icon.content), headers=headers) diff --git a/pyaggr3g470r/views/views.py b/pyaggr3g470r/views/views.py index 0071f887..b649d5c6 100644 --- a/pyaggr3g470r/views/views.py +++ b/pyaggr3g470r/views/views.py @@ -36,7 +36,7 @@ from collections import OrderedDict from bootstrap import application as app, db from flask import render_template, request, flash, session, \ - url_for, redirect, g, current_app, make_response, Response + url_for, redirect, g, current_app, make_response from flask.ext.login import LoginManager, login_user, logout_user, \ login_required, current_user, AnonymousUserMixin from flask.ext.principal import Principal, Identity, AnonymousIdentity, \ @@ -48,8 +48,8 @@ from sqlalchemy.exc import IntegrityError from werkzeug import generate_password_hash import conf -from pyaggr3g470r.lib.utils import to_hash from pyaggr3g470r import utils, notifications, export +from pyaggr3g470r.lib.view_utils import etag_match from pyaggr3g470r.models import User, Feed, Article, Role from pyaggr3g470r.decorators import feed_access_required from pyaggr3g470r.forms import SignupForm, SigninForm, InformationMessageForm,\ @@ -229,6 +229,7 @@ def signup(): return render_template('signup.html', form=form) +@etag_match def render_home(filters=None, head_titles=None, page_to_render='home', **kwargs): if filters is None: @@ -292,19 +293,12 @@ def render_home(filters=None, head_titles=None, and filter_ != 'all' and not articles: return redirect(gen_url(filter_='all')) - etag = to_hash("".join([str(filters[key]) for key in sorted(filters)]) - + "".join([str(art.id) for art in articles])) - if request.headers.get('if-none-match') == etag: - return Response(status=304, headers={'etag': etag, - 'Cache-Control': 'pragma: no-cache'}) - response = make_response(render_template('home.html', gen_url=gen_url, - feed_id=feed_id, page_to_render=page_to_render, - filter_=filter_, limit=limit, feeds=feeds, - unread=arti_contr.count_by_feed(readed=False), - articles=articles, in_error=in_error, - head_titles=head_titles, sort_=sort_, **kwargs)) - response.headers['etag'] = etag - return response + return render_template('home.html', gen_url=gen_url, + feed_id=feed_id, page_to_render=page_to_render, + filter_=filter_, limit=limit, feeds=feeds, + unread=arti_contr.count_by_feed(readed=False), + articles=articles, in_error=in_error, + head_titles=head_titles, sort_=sort_, **kwargs) @app.route('/') @@ -362,7 +356,9 @@ def fetch(feed_id=None): "for administrator, on the Heroku platform."), "info") return redirect(redirect_url()) + @app.route('/about', methods=['GET']) +@etag_match def about(): """ 'About' page. |