diff options
author | François Schmidts <francois.schmidts@gmail.com> | 2015-04-06 10:37:13 +0200 |
---|---|---|
committer | François Schmidts <francois.schmidts@gmail.com> | 2015-04-06 10:37:13 +0200 |
commit | 29bb2a36f0b5d1781ab05f1976aa0c5017351807 (patch) | |
tree | 52b2dd87f4d36f6a9c518cc14f96e523b1dea045 /pyaggr3g470r/views | |
parent | misc update (diff) | |
parent | Minor changes to the CSS. (diff) | |
download | newspipe-29bb2a36f0b5d1781ab05f1976aa0c5017351807.tar.gz newspipe-29bb2a36f0b5d1781ab05f1976aa0c5017351807.tar.bz2 newspipe-29bb2a36f0b5d1781ab05f1976aa0c5017351807.zip |
Merge remote-tracking branch 'upstream/master'
Conflicts:
pyaggr3g470r/controllers/feed.py
pyaggr3g470r/templates/home.html
Diffstat (limited to 'pyaggr3g470r/views')
-rw-r--r-- | pyaggr3g470r/views/api/article.py | 3 | ||||
-rw-r--r-- | pyaggr3g470r/views/api/common.py | 26 | ||||
-rw-r--r-- | pyaggr3g470r/views/api/feed.py | 9 | ||||
-rw-r--r-- | pyaggr3g470r/views/article.py | 10 | ||||
-rw-r--r-- | pyaggr3g470r/views/feed.py | 11 | ||||
-rw-r--r-- | pyaggr3g470r/views/views.py | 45 |
6 files changed, 61 insertions, 43 deletions
diff --git a/pyaggr3g470r/views/api/article.py b/pyaggr3g470r/views/api/article.py index 17881412..c3ec2d34 100644 --- a/pyaggr3g470r/views/api/article.py +++ b/pyaggr3g470r/views/api/article.py @@ -1,3 +1,6 @@ +#! /usr/bin/env python +# -*- coding: utf-8 - + from flask import g import dateutil.parser diff --git a/pyaggr3g470r/views/api/common.py b/pyaggr3g470r/views/api/common.py index 48a0d0ac..b8477d4b 100644 --- a/pyaggr3g470r/views/api/common.py +++ b/pyaggr3g470r/views/api/common.py @@ -1,7 +1,10 @@ +#! /usr/bin/env python +# -*- coding: utf-8 - + """For a given resources, classes in the module intend to create the following routes : GET resource/<id> - -> to retreive one + -> to retrieve one POST resource -> to create one PUT resource/<id> @@ -10,7 +13,7 @@ routes : -> to delete one GET resources - -> to retreive several + -> to retrieve several POST resources -> to create several PUT resources @@ -21,7 +24,6 @@ routes : import json import logging import dateutil.parser -from copy import deepcopy from functools import wraps from werkzeug.exceptions import Unauthorized, BadRequest from flask import request, g, session, Response @@ -54,13 +56,11 @@ def authenticate(func): and user.activation_key == "": g.user = user logged_in = True - if logged_in: return func(*args, **kwargs) raise Unauthorized({'WWWAuthenticate': 'Basic realm="Login Required"'}) return wrapper - def to_response(func): """Will cast results of func as a result, and try to extract a status_code for the Response object""" @@ -146,12 +146,16 @@ class PyAggResourceExisting(PyAggAbstractResource): class PyAggResourceMulti(PyAggAbstractResource): def get(self): - """retreive several objects. filters can be set in the payload on the + """retrieve several objects. filters can be set in the payload on the different fields of the object, and a limit can be set in there as well """ - if 'application/json' != request.headers.get('Content-Type'): + if 'application/json' not in request.headers.get('Content-Type'): raise BadRequest("Content-Type must be application/json") - limit = request.json.pop('limit', 10) + limit = 10 + try: + limit = request.json.pop('limit', 10) + except: + return [res for res in self.controller.read().limit(limit)] if not limit: return [res for res in self.controller.read(**request.json).all()] return [res for res in self.controller.read(**request.json).limit(limit)] @@ -159,7 +163,7 @@ class PyAggResourceMulti(PyAggAbstractResource): def post(self): """creating several objects. payload should be a list of dict. """ - if 'application/json' != request.headers.get('Content-Type'): + if 'application/json' not in request.headers.get('Content-Type'): raise BadRequest("Content-Type must be application/json") status = 201 results = [] @@ -180,7 +184,7 @@ class PyAggResourceMulti(PyAggAbstractResource): [[obj_id1, {attr1: val1, attr2: val2}] [obj_id2, {attr1: val1, attr2: val2}]] """ - if 'application/json' != request.headers.get('Content-Type'): + if 'application/json' not in request.headers.get('Content-Type'): raise BadRequest("Content-Type must be application/json") status = 200 results = [] @@ -201,7 +205,7 @@ class PyAggResourceMulti(PyAggAbstractResource): def delete(self): """will delete several objects, a list of their ids should be in the payload""" - if 'application/json' != request.headers.get('Content-Type'): + if 'application/json' not in request.headers.get('Content-Type'): raise BadRequest("Content-Type must be application/json") status = 204 results = [] diff --git a/pyaggr3g470r/views/api/feed.py b/pyaggr3g470r/views/api/feed.py index 0d83ea43..7d0e2862 100644 --- a/pyaggr3g470r/views/api/feed.py +++ b/pyaggr3g470r/views/api/feed.py @@ -1,3 +1,6 @@ +#! /usr/bin/env python +# -*- coding: utf-8 - + from flask import g from pyaggr3g470r.controllers.feed import FeedController, \ @@ -8,7 +11,6 @@ from pyaggr3g470r.views.api.common import PyAggAbstractResource, \ PyAggResourceExisting, \ PyAggResourceMulti - FEED_ATTRS = {'title': {'type': str}, 'description': {'type': str}, 'link': {'type': str}, @@ -20,25 +22,21 @@ FEED_ATTRS = {'title': {'type': str}, 'last_error': {'type': str}, 'error_count': {'type': int, 'default': 0}} - class FeedNewAPI(PyAggResourceNew): controller_cls = FeedController attrs = FEED_ATTRS to_date = ['date', 'last_retrieved'] - class FeedAPI(PyAggResourceExisting): controller_cls = FeedController attrs = FEED_ATTRS to_date = ['date', 'last_retrieved'] - class FeedsAPI(PyAggResourceMulti): controller_cls = FeedController attrs = FEED_ATTRS to_date = ['date', 'last_retrieved'] - class FetchableFeedAPI(PyAggAbstractResource): controller_cls = FeedController to_date = ['date', 'last_retrieved'] @@ -49,7 +47,6 @@ class FetchableFeedAPI(PyAggAbstractResource): return [feed for feed in self.controller.list_fetchable( **self.reqparse_args())] - g.api.add_resource(FeedNewAPI, '/feed', endpoint='feed_new.json') g.api.add_resource(FeedAPI, '/feed/<int:obj_id>', endpoint='feed.json') g.api.add_resource(FeedsAPI, '/feeds', endpoint='feeds.json') diff --git a/pyaggr3g470r/views/article.py b/pyaggr3g470r/views/article.py index 66cc0f37..08c92686 100644 --- a/pyaggr3g470r/views/article.py +++ b/pyaggr3g470r/views/article.py @@ -1,3 +1,6 @@ +#! /usr/bin/env python +# -*- coding: utf-8 - + from flask import Blueprint, g, render_template, redirect from sqlalchemy import desc @@ -18,10 +21,9 @@ def articles(feed_id=None, nb_articles=-1): feed.articles = controllers.ArticleController(g.user.id)\ .read(feed_id=feed.id)\ .order_by(desc("Article.date")) - if len(feed.articles.all()) <= nb_articles: - nb_articles = -1 - if nb_articles == -1: - feed.articles = feed.articles.limit(nb_articles) + if len(feed.articles.all()) <= nb_articles or nb_articles == -1: + nb_articles = int(1e9) + feed.articles = feed.articles.limit(nb_articles) return render_template('articles.html', feed=feed, nb_articles=nb_articles) diff --git a/pyaggr3g470r/views/feed.py b/pyaggr3g470r/views/feed.py index 2af502a7..4fe4e5da 100644 --- a/pyaggr3g470r/views/feed.py +++ b/pyaggr3g470r/views/feed.py @@ -1,5 +1,9 @@ +#! /usr/bin/env python +# -*- coding: utf-8 - + from datetime import datetime from flask import Blueprint, g, render_template +from sqlalchemy import desc from pyaggr3g470r import controllers, utils from pyaggr3g470r.decorators import pyagg_default_decorator, \ @@ -22,9 +26,9 @@ def feed(feed_id=None): "Presents detailed information about a feed." feed = controllers.FeedController(g.user.id).get(id=feed_id) word_size = 6 - articles = controllers.ArticleController(g.user.id)\ - .read(feed_id=feed_id).all() - nb_articles = controllers.ArticleController(g.user.id).read().count() + articles = controllers.ArticleController(g.user.id) \ + .read(feed_id=feed_id) \ + .order_by(desc("Article.date")).all() top_words = utils.top_words(articles, n=50, size=int(word_size)) tag_cloud = utils.tag_cloud(top_words) @@ -46,5 +50,4 @@ def feed(feed_id=None): feed=feed, tag_cloud=tag_cloud, first_post_date=first_article, end_post_date=last_article, - nb_articles=nb_articles, average=average, delta=delta, elapsed=elapsed) diff --git a/pyaggr3g470r/views/views.py b/pyaggr3g470r/views/views.py index 7934eef8..e202ad4d 100644 --- a/pyaggr3g470r/views/views.py +++ b/pyaggr3g470r/views/views.py @@ -27,14 +27,13 @@ __copyright__ = "Copyright (c) Cedric Bonhomme" __license__ = "AGPLv3" import os -import json import string import random import hashlib import datetime from collections import namedtuple from bootstrap import application as app, db -from flask import render_template, request, flash, session, Response, \ +from flask import render_template, request, flash, session, \ url_for, redirect, g, current_app, make_response, jsonify from flask.ext.login import LoginManager, login_user, logout_user, \ login_required, current_user, AnonymousUserMixin @@ -47,7 +46,8 @@ from sqlalchemy.exc import IntegrityError from werkzeug import generate_password_hash import conf -from pyaggr3g470r import utils, notifications, export, duplicate +from pyaggr3g470r import utils, notifications, export +from pyaggr3g470r import controllers from pyaggr3g470r.models import User, Feed, Article, Role from pyaggr3g470r.decorators import feed_access_required from pyaggr3g470r.forms import SignupForm, SigninForm, AddFeedForm, \ @@ -93,7 +93,7 @@ def before_request(): @login_manager.user_loader def load_user(email): # Return an instance of the User model - return User.query.filter(User.email == email).first() + return controllers.UserController(email).get(email=email) # @@ -153,7 +153,7 @@ def login(): form = SigninForm() if form.validate_on_submit(): - user = User.query.filter(User.email == form.email.data).first() + user = controllers.UserController(form.email.data).get(email=form.email.data) login_user(user) g.user = user session['email'] = form.email.data @@ -265,8 +265,12 @@ def fetch(feed_id=None): Triggers the download of news. News are downloaded in a separated process, mandatory for Heroku. """ - utils.fetch(g.user.id, feed_id) - flash(gettext("Downloading articles..."), 'info') + if not conf.ON_HEROKU or g.user.is_admin(): + utils.fetch(g.user.id, feed_id) + flash(gettext("Downloading articles..."), "info") + else: + flash(gettext("The manual retrieving of news is only available " + + "for administrator, on the Heroku platform."), "info") return redirect(redirect_url()) @app.route('/about', methods=['GET']) @@ -378,7 +382,7 @@ def inactives(): List of inactive feeds. """ nb_days = int(request.args.get('nb_days', 365)) - user = User.query.filter(User.id == g.user.id).first() + user = controllers.UserController(g.user.email).get(email=g.user.email) today = datetime.datetime.now() inactives = [] for feed in user.feeds: @@ -399,7 +403,7 @@ def duplicates(feed_id=None): """ feed = Feed.query.filter(Feed.user_id == g.user.id, Feed.id == feed_id).first() duplicates = [] - duplicates = duplicate.compare_documents(feed) + duplicates = utils.compare_documents(feed) return render_template('duplicates.html', duplicates=duplicates, feed=feed) @app.route('/index_database', methods=['GET']) @@ -425,7 +429,7 @@ def export_articles(): """ Export all articles to HTML or JSON. """ - user = User.query.filter(User.id == g.user.id).first() + user = controllers.UserController(g.user.email).get(id=g.user.id) if request.args.get('format') == "HTML": # Export to HTML try: @@ -457,7 +461,7 @@ def export_opml(): """ Export all feeds to OPML. """ - user = User.query.filter(User.id == g.user.id).first() + user = controllers.UserController(g.user.email).get(id=g.user.id) response = make_response(render_template('opml.xml', user=user, now=datetime.datetime.now())) response.headers['Content-Type'] = 'application/xml' response.headers['Content-Disposition'] = 'attachment; filename=feeds.opml' @@ -506,7 +510,7 @@ def management(): if None != request.files.get('opmlfile', None): # Import an OPML file data = request.files.get('opmlfile', None) - if not g.allowed_file(data.filename): + if not utils.allowed_file(data.filename): flash(gettext('File not allowed.'), 'danger') else: try: @@ -519,7 +523,7 @@ def management(): elif None != request.files.get('jsonfile', None): # Import an account data = request.files.get('jsonfile', None) - if not g.allowed_file(data.filename): + if not utils.allowed_file(data.filename): flash(gettext('File not allowed.'), 'danger') else: try: @@ -540,10 +544,15 @@ def management(): not_on_heroku = not conf.ON_HEROKU) @app.route('/history', methods=['GET']) +@app.route('/history/<int:year>', methods=['GET']) +@app.route('/history/<int:year>/<int:month>', methods=['GET']) @login_required -def history(): - #user = User.query.filter(User.id == g.user.id).first() - return render_template('history.html') +def history(year=None, month=None): + articles_counter, articles = utils.history(g.user.id, year, month) + return render_template('history.html', + articles_counter=articles_counter, + articles=articles, + year=year, month=month) @app.route('/bookmarklet', methods=['GET']) @app.route('/create_feed', methods=['GET', 'POST']) @@ -628,7 +637,7 @@ def profile(): """ Edit the profile of the currently logged user. """ - user = User.query.filter(User.email == g.user.email).first() + user = controllers.UserController(g.user.email).get(id=g.user.id) form = ProfileForm() if request.method == 'POST': @@ -654,7 +663,7 @@ def delete_account(): """ Delete the account of the user (with all its data). """ - user = User.query.filter(User.email == g.user.email).first() + user = controllers.UserController(g.user.email).get(id=g.user.id) if user is not None: db.session.delete(user) db.session.commit() |