aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCédric Bonhomme <cedric@cedricbonhomme.org>2014-04-07 23:49:54 +0200
committerCédric Bonhomme <cedric@cedricbonhomme.org>2014-04-07 23:49:54 +0200
commit738b45556935d4e0075de5831b6f333ddcbd4647 (patch)
tree8279bb087f56af95912b0ba79757fc791e719c9a
parentTesting access keys. (diff)
downloadnewspipe-738b45556935d4e0075de5831b6f333ddcbd4647.tar.gz
newspipe-738b45556935d4e0075de5831b6f333ddcbd4647.tar.bz2
newspipe-738b45556935d4e0075de5831b6f333ddcbd4647.zip
Beginning of the port to PostgreSQL.
-rw-r--r--conf.py21
-rw-r--r--pyaggr3g470r/__init__.py11
-rw-r--r--pyaggr3g470r/feedgetter.py44
-rw-r--r--pyaggr3g470r/forms.py11
-rw-r--r--pyaggr3g470r/models.py129
-rw-r--r--pyaggr3g470r/templates/feed.html12
-rw-r--r--pyaggr3g470r/templates/home.html16
-rw-r--r--pyaggr3g470r/views.py170
8 files changed, 246 insertions, 168 deletions
diff --git a/conf.py b/conf.py
index 3b723f76..d3beebce 100644
--- a/conf.py
+++ b/conf.py
@@ -15,6 +15,27 @@ except:
config = confparser.SafeConfigParser()
config.read("./conf/conf.cfg")
+
+
+
+
+basedir = os.path.abspath(os.path.dirname(__file__))
+
+CSRF_ENABLED = True
+
+SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
+
+# slow database query threshold (in seconds)
+DATABASE_QUERY_TIMEOUT = 0.5
+
+
+
+
+
+
+
+
+
PATH = os.path.abspath(".")
DATABASE_NAME = config.get('database', 'name')
diff --git a/pyaggr3g470r/__init__.py b/pyaggr3g470r/__init__.py
index 16bdc57f..d29b1373 100644
--- a/pyaggr3g470r/__init__.py
+++ b/pyaggr3g470r/__init__.py
@@ -2,12 +2,10 @@
# -*- coding: utf-8 -*-
import os
-
from flask import Flask
-from flask.ext.mongoengine import MongoEngine
+from flask.ext.sqlalchemy import SQLAlchemy
import conf
-from models import *
# Create Flask application
app = Flask(__name__)
@@ -15,8 +13,9 @@ app.debug = True
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = os.urandom(12)
+app.config['SQLALCHEMY_DATABASE_URI'] = conf.SQLALCHEMY_DATABASE_URI
+db = SQLAlchemy(app)
-app.config['MONGODB_SETTINGS'] = {'DB': conf.DATABASE_NAME}
app.config["MAIL_SERVER"] = conf.MAIL_HOST
app.config["MAIL_PORT"] = conf.MAIL_PORT
app.config["MAIL_USE_TLS"] = conf.MAIL_TLS
@@ -24,10 +23,6 @@ app.config["MAIL_USE_SSL"] = conf.MAIL_SSL
app.config["MAIL_USERNAME"] = conf.MAIL_USERNAME
app.config["MAIL_PASSWORD"] = conf.MAIL_PASSWORD
-# Initializes the database
-db = MongoEngine(app)
-db.init_app(app)
-
from flask.ext.mail import Message, Mail
mail = Mail(app)
diff --git a/pyaggr3g470r/feedgetter.py b/pyaggr3g470r/feedgetter.py
index 2325a26e..1c834b88 100644
--- a/pyaggr3g470r/feedgetter.py
+++ b/pyaggr3g470r/feedgetter.py
@@ -34,9 +34,10 @@ from datetime import datetime
from urllib import urlencode
from urlparse import urlparse, parse_qs, urlunparse
from BeautifulSoup import BeautifulSoup
-from mongoengine.queryset import NotUniqueError
+
from requests.exceptions import Timeout
+from sqlalchemy.exc import IntegrityError
import models
import conf
@@ -44,7 +45,8 @@ import search
import utils
from flask.ext.mail import Message
-from pyaggr3g470r import app, mail
+from pyaggr3g470r import app, db, mail
+from pyaggr3g470r.models import User, Feed, Article
import log
pyaggr3g470r_log = log.Log("feedgetter")
@@ -73,7 +75,7 @@ class FeedGetter(object):
"https": "http://" + conf.HTTP_PROXY
}
feedparser.USER_AGENT = conf.USER_AGENT
- self.user = models.User.objects(email=email).first()
+ self.user = User.query.filter(User.email == email).first()
def retrieve_feed(self, feed_id=None):
"""
@@ -81,7 +83,7 @@ class FeedGetter(object):
"""
feeds = [feed for feed in self.user.feeds if feed.enabled]
if feed_id != None:
- feeds = [feed for feed in feeds if str(feed.oid) == feed_id]
+ feeds = [feed for feed in feeds if str(feed.id) == feed_id]
for current_feed in feeds:
try:
# launch a new thread for the RSS feed
@@ -96,8 +98,6 @@ class FeedGetter(object):
for th in list_of_threads:
th.join()
- self.user.save()
-
def process(self, feed):
"""
Retrieves articles form the feed and add them to the database.
@@ -170,24 +170,17 @@ class FeedGetter(object):
post_date = datetime(*article.updated_parsed[:6])
# save the article
- article = models.Article(post_date, nice_url, article_title, description, False, False)
- try:
- article.save()
- articles.append(article)
- pyaggr3g470r_log.info("New article %s (%s) added." % (article_title, nice_url))
- except NotUniqueError:
- pyaggr3g470r_log.error("Article %s (%s) already in the database." % (article_title, nice_url))
- continue
- except Exception as e:
- pyaggr3g470r_log.error("Error when inserting article in database: " + str(e))
- continue
+ article = Article(link=nice_url, title=article_title,
+ content=description, readed=False, like=False, date=post_date)
+ articles.append(article)
# add the article to the Whoosh index
+ """
try:
search.add_to_index([article], feed)
except Exception as e:
pyaggr3g470r_log.error("Whoosh error.")
- pass
+ pass"""
# email notification
if conf.MAIL_ENABLED and feed.email_notification:
@@ -199,8 +192,19 @@ class FeedGetter(object):
mail.send(msg)
# add the articles to the list of articles for the current feed
- feed.articles.extend(articles)
- feed.articles = sorted(feed.articles, key=lambda t: t.date, reverse=True)
+ for article in articles:
+ try:
+ feed.articles.append(article)
+ db.session.merge(article)
+ db.session.commit()
+ pyaggr3g470r_log.info("New article %s (%s) added." % (article_title, nice_url))
+ except IntegrityError:
+ pyaggr3g470r_log.error("Article %s (%s) already in the database." % (article_title, nice_url))
+ db.session.rollback()
+ continue
+ except Exception as e:
+ pyaggr3g470r_log.error("Error when inserting article in database: " + str(e))
+ continue
return True
diff --git a/pyaggr3g470r/forms.py b/pyaggr3g470r/forms.py
index f9bb5a7a..7439c34b 100644
--- a/pyaggr3g470r/forms.py
+++ b/pyaggr3g470r/forms.py
@@ -27,11 +27,15 @@ __copyright__ = "Copyright (c) Cedric Bonhomme"
__license__ = "GPLv3"
from flask.ext.wtf import Form
+from flask import flash
from wtforms import TextField, TextAreaField, PasswordField, BooleanField, SubmitField, validators
-import models
+from pyaggr3g470r.models import User
class SigninForm(Form):
+ """
+ Sign in form.
+ """
email = TextField("Email", [validators.Required("Please enter your email address."), validators.Email("Please enter your email address.")])
password = PasswordField('Password', [validators.Required("Please enter a password.")])
submit = SubmitField("Log In")
@@ -43,11 +47,12 @@ class SigninForm(Form):
if not Form.validate(self):
return False
- user = models.User.objects(email = self.email.data).first()
+ user = User.query.filter(User.email == self.email.data).first()
if user and user.check_password(self.password.data):
return True
else:
- self.email.errors.append("Invalid e-mail or password")
+ flash('Invalid email or password', 'danger')
+ #self.email.errors.append("Invalid email or password")
return False
class AddFeedForm(Form):
diff --git a/pyaggr3g470r/models.py b/pyaggr3g470r/models.py
index cbd49350..0fd9eb73 100644
--- a/pyaggr3g470r/models.py
+++ b/pyaggr3g470r/models.py
@@ -26,86 +26,97 @@ __revision__ = "$Date: 2013/11/16 $"
__copyright__ = "Copyright (c) Cedric Bonhomme"
__license__ = "GPLv3"
-from mongoengine import *
from datetime import datetime
-
from werkzeug import generate_password_hash, check_password_hash
from flask.ext.login import UserMixin
+from pyaggr3g470r import db
-import bson.objectid
-
-class User(Document, UserMixin):
+class User(db.Model, UserMixin):
"""
- Defines the model for a user.
+ Represent a user.
"""
- firstname = StringField(required=True)
- lastname = StringField(required = True)
- email = EmailField(required=True, unique=True)
- pwdhash = StringField(required=True)
- feeds = ListField(EmbeddedDocumentField('Feed'))
- created_at = DateTimeField(required=True, default=datetime.now)
+ id = db.Column(db.Integer, primary_key = True)
+ firstname = db.Column(db.String())
+ lastname = db.Column(db.String())
+ email = db.Column(db.String(), index = True, unique = True)
+ pwdhash = db.Column(db.String())
+ roles = db.relationship('Role', backref = 'user', lazy = 'dynamic')
+ date_created = db.Column(db.DateTime(), default=datetime.now)
+ last_seen = db.Column(db.DateTime(), default=datetime.now)
+ feeds = db.relationship('Feed', backref = 'subscriber', lazy = 'dynamic', cascade='all,delete-orphan')
def get_id(self):
+ """
+ Return the id (email) of the user.
+ """
return self.email
def set_password(self, password):
+ """
+ Hash the password of the user.
+ """
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
+ """
+ Check the password of the user.
+ """
return check_password_hash(self.pwdhash, password)
- #required for administrative interface
- def __unicode__(self):
- return self.email
-
-class Feed(EmbeddedDocument):
- """
- Defines the model for a feed.
- """
- oid = ObjectIdField(default=bson.objectid.ObjectId , primary_key=True)
- title = StringField(required=True)
- description = StringField(default="")
- link = StringField(required=True, unique=True)
- site_link = StringField()
- email_notification = BooleanField(default=False)
- enabled = BooleanField(default=True)
- articles = ListField(ReferenceField('Article', dbref = False))
- created_date = DateTimeField(required=True, default=datetime.now)
-
- meta = {
- 'ordering': ['+title']
- }
+ def is_admin(self):
+ """
+ Return True if the user has administrator rights.
+ """
+ return len([role for role in self.roles if role.name == "admin"]) != 0
def __eq__(self, other):
- return self.oid == other.oid
+ return self.id == other.id
- def __str__(self):
- return 'Feed: %s' % self.title
+ def __repr__(self):
+ return '<User %r>' % (self.firstname)
-class Article(Document):
+class Role(db.Model):
"""
- Defines the model for an article.
+ Represent a role.
"""
- date = DateTimeField(required=True)
- link = StringField(required=True, unique=True)
- title = StringField(required=True)
- content = StringField(required=True)
- readed = BooleanField()
- like = BooleanField()
- retrieved_date = DateTimeField(required=True, default=datetime.now)
-
- meta = {
- 'ordering': ['-date'],
- 'indexes': [
- {'fields': ['-date'],
- 'sparse': True, 'types': False },
- {'fields': ['link'],
- 'sparse': True, 'unique': True, 'types': False }
- ]
- }
+ id = db.Column(db.Integer, primary_key = True)
+ name = db.Column(db.String(), unique = True)
- def __eq__(self, other):
- return self.link == other
+ user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
- def __str__(self):
- return 'Article: %s' % self.title
+class Feed(db.Model):
+ """
+ Represent a station.
+ """
+ id = db.Column(db.Integer, primary_key = True)
+ title = db.Column(db.String(), default="New station")
+ description = db.Column(db.String(), default="FR")
+ link = db.Column(db.String())
+ site_link = db.Column(db.String(), default="New station")
+ email_notification = db.Column(db.Boolean(), default=False)
+ enabled = db.Column(db.Boolean(), default=True)
+ created_date = db.Column(db.DateTime(), default=datetime.now)
+ articles = db.relationship('Article', backref = 'feed', lazy = 'dynamic', cascade='all,delete-orphan')
+
+ user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
+
+ def __repr__(self):
+ return '<Feed %r>' % (self.title)
+
+class Article(db.Model):
+ """
+ Represent an article from a feed.
+ """
+ id = db.Column(db.Integer, primary_key = True)
+ link = db.Column(db.String(), unique = True)
+ title = db.Column(db.String())
+ content = db.Column(db.String())
+ readed = db.Column(db.Boolean(), default=False)
+ like = db.Column(db.Boolean(), default=False)
+ date = db.Column(db.DateTime(), default=datetime.now)
+ retrieved_date = db.Column(db.DateTime(), default=datetime.now)
+
+ station_id = db.Column(db.Integer, db.ForeignKey('feed.id'))
+
+ def __repr__(self):
+ return '<Article %r>' % (self.title)
diff --git a/pyaggr3g470r/templates/feed.html b/pyaggr3g470r/templates/feed.html
index 95465170..849dba49 100644
--- a/pyaggr3g470r/templates/feed.html
+++ b/pyaggr3g470r/templates/feed.html
@@ -4,14 +4,14 @@
<div class="jumbotron">
<h2>{{ feed.title }}</h2>
{% if feed.description %} <p>{{ feed.description }}</p> {% endif %}
- <a href="/delete_feed/{{ feed.oid }}"><i class="glyphicon glyphicon-remove" title="Delete this feed"></i></a>
- <a href="/edit_feed/{{ feed.oid }}"><i class="glyphicon glyphicon-edit" title="Edit this feed"></i></a>
+ <a href="/delete_feed/{{ feed.id }}"><i class="glyphicon glyphicon-remove" title="Delete this feed"></i></a>
+ <a href="/edit_feed/{{ feed.id }}"><i class="glyphicon glyphicon-edit" title="Edit this feed"></i></a>
</div>
<div class="jumbotron">
<p>
- This feed contains {{ feed.articles|count }} <a href="/articles/{{ feed.oid }}/100">articles</a>
+ This feed contains {{ feed.articles.all()|count }} <a href="/articles/{{ feed.id }}/100">articles</a>
{% if nb_articles != 0 %}
- ({{ ((feed.articles|count * 100 ) / nb_articles) | round(2, 'floor') }}% of the database)
+ ({{ ((feed.articles.all()|count * 100 ) / nb_articles) | round(2, 'floor') }}% of the database)
{% endif %}
.<br />
Address of the feed: <a href="{{ feed.link }}">{{ feed.link }}</a><br />
@@ -19,14 +19,14 @@
Address of the site: <a href="{{ feed.site_link }}">{{ feed.site_link }}</a>
{% endif %}
<br />
- {% if feed.articles|count != 0 %}
+ {% if feed.articles.all()|count != 0 %}
The last article was posted {{ elapsed.days }} day(s) ago.<br />
Daily average: {{ average }}, between the {{ first_post_date.strftime('%Y-%m-%d') }} and the {{ end_post_date.strftime('%Y-%m-%d') }}.
{% endif %}
</p>
</div>
<div class="jumbotron">
- {% if feed.articles|count != 0 %}
+ {% if feed.articles.all()|count != 0 %}
<div>{{ tag_cloud|safe }}</div>
{% endif %}
</div>
diff --git a/pyaggr3g470r/templates/home.html b/pyaggr3g470r/templates/home.html
index 9117bce9..8a4e429d 100644
--- a/pyaggr3g470r/templates/home.html
+++ b/pyaggr3g470r/templates/home.html
@@ -8,16 +8,16 @@
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>{{ feed.title|safe }}</h1>
- <a href="/articles/{{ feed.oid }}/100"><i class="glyphicon glyphicon-th-list" title="More articles"></i></a>
- <a href="/feed/{{ feed.oid }}"><i class="glyphicon glyphicon-info-sign" title="Details"></i></a>
- <a href="/edit_feed/{{ feed.oid }}"><i class="glyphicon glyphicon-edit" title="Edit this feed"></i></a>
+ <a href="/articles/{{ feed.id }}/100"><i class="glyphicon glyphicon-th-list" title="More articles"></i></a>
+ <a href="/feed/{{ feed.id }}"><i class="glyphicon glyphicon-info-sign" title="Details"></i></a>
+ <a href="/edit_feed/{{ feed.id }}"><i class="glyphicon glyphicon-edit" title="Edit this feed"></i></a>
{% if feed.enabled %}
- <a href="/fetch/{{ feed.oid }}"><i class="glyphicon glyphicon-cloud-download" title="Fetch this feed"></i></a>
+ <a href="/fetch/{{ feed.id }}"><i class="glyphicon glyphicon-cloud-download" title="Fetch this feed"></i></a>
{% endif %}
- <a href="/mark_as_read/{{ feed.oid }}"><i class="glyphicon glyphicon-check" title="Mark all as read"></i></a>
+ <a href="/mark_as_read/{{ feed.id }}"><i class="glyphicon glyphicon-check" title="Mark all as read"></i></a>
</div>
</div>
- {% for number in range(0, feed.articles|length-(feed.articles|length % 3), 3) %}
+ {% for number in range(0, feed.articles.all()|count-(feed.articles.all()|count % 3), 3) %}
<div class="row">
{% for n in range(number, number+3) %}
<div class="col-xs-6 col-sm-4 col-md-4">
@@ -29,9 +29,9 @@
{% endfor %}
</div>
{% endfor %}
- {% if feed.articles|length % 3 != 0 %}
+ {% if feed.articles.all()|count % 3 != 0 %}
<div class="row">
- {% for n in range(feed.articles|length-(feed.articles|length % 3), feed.articles|length) %}
+ {% for n in range(feed.articles.all()|count-(feed.articles.all()|count % 3), feed.articles.all()|count) %}
<div class="col-xs-6 col-sm-4 col-md-4">
{% if feed.articles[n].readed %}<h3>{% else %}<h1>{% endif %}
<a href="/article/{{ feed.articles[n].id }}">{{ feed.articles[n].title|safe }}</a>
diff --git a/pyaggr3g470r/views.py b/pyaggr3g470r/views.py
index 8dc4c7c7..b2811b66 100644
--- a/pyaggr3g470r/views.py
+++ b/pyaggr3g470r/views.py
@@ -27,9 +27,10 @@ __copyright__ = "Copyright (c) Cedric Bonhomme"
__license__ = "GPLv3"
import os
-import datetime
-from flask import render_template, request, make_response, flash, session, url_for, redirect, g
+from datetime import datetime
+from flask import render_template, jsonify, request, flash, session, 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, identity_changed, identity_loaded, Permission, RoleNeed, UserNeed
import conf
import utils
@@ -39,10 +40,29 @@ import models
import search as fastsearch
from forms import SigninForm, AddFeedForm, ProfileForm
from pyaggr3g470r import app, db
+from pyaggr3g470r.models import User, Feed, Article, Role
login_manager = LoginManager()
login_manager.init_app(app)
+#
+# Management of the user's session.
+#
+@identity_loaded.connect_via(app)
+def on_identity_loaded(sender, identity):
+ # Set the identity user object
+ identity.user = current_user
+
+ # Add the UserNeed to the identity
+ if hasattr(current_user, 'id'):
+ identity.provides.add(UserNeed(current_user.id))
+
+ # Assuming the User model has a list of roles, update the
+ # identity with the roles that the user provides
+ if hasattr(current_user, 'roles'):
+ for role in current_user.roles:
+ identity.provides.add(RoleNeed(role.name))
+
@app.before_request
def before_request():
g.user = current_user
@@ -65,17 +85,32 @@ def authentication_failed(e):
@login_manager.user_loader
def load_user(email):
# Return an instance of the User model
- return models.User.objects(email=email).first()
+ return User.query.filter(User.email == email).first()
+
+def redirect_url(default='index'):
+ return request.args.get('next') or \
+ request.referrer or \
+ url_for(default)
+
+
+
+#
+# Views.
+#
@app.route('/login/', methods=['GET', 'POST'])
def login():
+ """
+ Log in view.
+ """
g.user = AnonymousUserMixin()
form = SigninForm()
if form.validate_on_submit():
- user = models.User.objects(email=form.email.data).first()
+ user = User.query.filter(User.email == form.email.data).first()
login_user(user)
g.user = user
+ identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
flash("Logged in successfully.", 'success')
return redirect(url_for('home'))
return render_template('login.html', form=form)
@@ -84,19 +119,25 @@ def login():
@login_required
def logout():
"""
- Remove the user information from the session.
+ Log out view. Removes the user information from the session.
"""
- logout_user()
- flash("Logged out successfully.", 'success')
- return redirect(url_for('home'))
+ # Update last_seen field
+ g.user.last_seen = datetime.utcnow()
+ db.session.add(g.user)
+ db.session.commit()
-def redirect_url(default='index'):
- return request.args.get('next') or \
- request.referrer or \
- url_for(default)
+ # Remove the user information from the session
+ logout_user()
+ # Remove session keys set by Flask-Principal
+ for key in ('identity.name', 'identity.auth_type'):
+ session.pop(key, None)
+ # Tell Flask-Principal the user is anonymous
+ identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity())
+ flash("Logged out successfully.", 'success')
+ return redirect(url_for('map_view'))
@app.route('/')
@login_required
@@ -104,10 +145,13 @@ def home():
"""
The home page lists most recent articles of all feeds.
"""
- user = g.user
- feeds = models.User.objects(email=g.user.email).fields(slice__feeds__articles=9).first().feeds
+ user = User.query.filter(User.email == g.user.email).first()
+ feeds = []
+ for feed in user.feeds:
+ feed.articles = feed.articles[:8]
+ feeds.append(feed)
return render_template('home.html', user=user, feeds=feeds, \
- head_title=models.Article.objects(readed=False).count())
+ head_title="nb unread")
@app.route('/fetch/', methods=['GET'])
@app.route('/fetch/<feed_id>', methods=['GET'])
@@ -135,60 +179,58 @@ def feeds():
"""
Lists the subscribed feeds in a table.
"""
- feeds = models.User.objects(email=g.user.email).first().feeds
+ user = User.query.filter(User.email == g.user.email).first()
+ feeds = user.feeds
return render_template('feeds.html', feeds=feeds)
-@app.route('/feed/<feed_id>', methods=['GET'])
+@app.route('/feed/<int:feed_id>', methods=['GET'])
@login_required
def feed(feed_id=None):
"""
Presents detailed information about a feed.
"""
- word_size = 6
- nb_articles = models.Article.objects().count()
- user = models.User.objects(email=g.user.email, feeds__oid=feed_id).first()
- if user == None:
- return redirect(url_for('feeds'))
- for feed in user.feeds:
- if str(feed.oid) == feed_id:
- articles = feed.articles
- top_words = utils.top_words(articles, n=50, size=int(word_size))
- tag_cloud = utils.tag_cloud(top_words)
-
- today = datetime.datetime.now()
- try:
- last_article = articles[0].date
- first_article = articles[-1].date
- delta = last_article - first_article
- average = round(float(len(articles)) / abs(delta.days), 2)
- except:
- last_article = datetime.datetime.fromtimestamp(0)
- first_article = datetime.datetime.fromtimestamp(0)
- delta = last_article - first_article
- average = 0
- elapsed = today - last_article
-
- return render_template('feed.html', head_title=utils.clear_string(feed.title), 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)
+ feed = Feed.query.filter(Feed.id == feed_id).first()
+ if feed.subscriber.id == g.user.id:
+ word_size = 6
+ articles = feed.articles
+ nb_articles = len(feed.articles.all())
+ top_words = utils.top_words(articles, n=50, size=int(word_size))
+ tag_cloud = utils.tag_cloud(top_words)
+
+ today = datetime.now()
+ try:
+ last_article = articles[0].date
+ first_article = articles[-1].date
+ delta = last_article - first_article
+ average = round(float(len(articles)) / abs(delta.days), 2)
+ except:
+ last_article = datetime.fromtimestamp(0)
+ first_article = datetime.fromtimestamp(0)
+ delta = last_article - first_article
+ average = 0
+ elapsed = today - last_article
+
+ return render_template('feed.html', head_title=utils.clear_string(feed.title), 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)
else:
flash("This feed do not exist.", 'warning')
return redirect(redirect_url())
-@app.route('/article/<article_id>', methods=['GET'])
+@app.route('/article/<int:article_id>', methods=['GET'])
@login_required
def article(article_id=None):
"""
Presents the content of an article.
"""
- #user = models.User.objects(email=g.user.email, feeds__oid=feed_id).first()
- article = models.Article.objects(id=article_id).first()
- if article == None:
- flash("This article do not exist.", 'warning')
- return redirect(redirect_url())
- if not article.readed:
- article.readed = True
- article.save()
+ article = Article.query.filter(Article.id == article_id).first()
+ if article.feed.subscriber.id == g.user.id:
+ if article == None:
+ flash("This article do not exist.", 'warning')
+ return redirect(redirect_url())
+ if not article.readed:
+ article.readed = True
+ db.session.commit()
return render_template('article.html', head_title=utils.clear_string(article.title), article=article)
@app.route('/mark_as_read/', methods=['GET'])
@@ -494,22 +536,22 @@ def delete_feed(feed_id=None):
@login_required
def profile():
"""
- Edit the profile of the user.
+ Edit the profile of the currently logged user.
"""
- user = models.User.objects(email=g.user.email).first()
+ user = User.query.filter(User.email == g.user.email).first()
form = ProfileForm()
if request.method == 'POST':
- if form.validate() == False:
+ if form.validate():
+ form.populate_obj(user)
+ if form.password.data != "":
+ user.set_password(form.password.data)
+ db.session.commit()
+ flash('User "' + user.firstname + '" successfully updated.', 'success')
+ return redirect(url_for('profile'))
+ else:
return render_template('profile.html', form=form)
- form.populate_obj(user)
- if form.password.data != "":
- user.set_password(form.password.data)
- user.save()
- flash('User "' + user.firstname + '" successfully updated', 'success')
- return redirect('/profile/')
-
if request.method == 'GET':
form = ProfileForm(obj=user)
- return render_template('profile.html', form=form)
+ return render_template('profile.html', user=user, form=form)
bgstack15