aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pyaggr3g470r/views/admin.py166
-rw-r--r--pyaggr3g470r/views/user.py152
-rwxr-xr-xsrc/runserver.py3
-rw-r--r--src/web/controllers/abstract.py2
-rw-r--r--src/web/controllers/user.py25
-rw-r--r--src/web/models/user.py10
-rw-r--r--src/web/templates/admin/dashboard.html18
-rw-r--r--src/web/templates/home.html2
-rw-r--r--src/web/templates/layout.html6
-rwxr-xr-xsrc/web/utils.py2
-rw-r--r--src/web/views/__init__.py2
-rw-r--r--src/web/views/views.py274
12 files changed, 368 insertions, 294 deletions
diff --git a/pyaggr3g470r/views/admin.py b/pyaggr3g470r/views/admin.py
new file mode 100644
index 00000000..744f3523
--- /dev/null
+++ b/pyaggr3g470r/views/admin.py
@@ -0,0 +1,166 @@
+from flask import (Blueprint, g, render_template, redirect,
+ flash, url_for, request)
+from flask.ext.babel import gettext
+from flask.ext.login import login_required
+
+from flask.ext.principal import Permission, RoleNeed
+
+from pyaggr3g470r.lib.utils import redirect_url
+from pyaggr3g470r.models import Role
+from pyaggr3g470r.controllers import UserController, ArticleController
+
+from pyaggr3g470r.forms import InformationMessageForm, UserForm
+from pyaggr3g470r import notifications
+
+admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
+admin_permission = Permission(RoleNeed('admin'))
+
+
+@admin_bp.route('/dashboard', methods=['GET', 'POST'])
+@login_required
+@admin_permission.require(http_exception=403)
+def dashboard():
+ """
+ Adminstrator's dashboard.
+ """
+ form = InformationMessageForm()
+
+ if request.method == 'POST':
+ if form.validate():
+ try:
+ notifications.information_message(form.subject.data,
+ form.message.data)
+ except Exception as error:
+ flash(gettext(
+ 'Problem while sending email: %(error)s', error=error),
+ 'danger')
+
+ users = UserController().read()
+ return render_template('admin/dashboard.html',
+ users=users, current_user=g.user, form=form)
+
+
+@admin_bp.route('/user/create', methods=['GET'])
+@admin_bp.route('/user/edit/<int:user_id>', methods=['GET'])
+@login_required
+@admin_permission.require(http_exception=403)
+def user_form(user_id=None):
+ if user_id is not None:
+ user = UserController().get(id=user_id)
+ form = UserForm(obj=user)
+ message = gettext('Edit the user <i>%(nick)s</i>', nick=user.nickname)
+ else:
+ form = UserForm()
+ message = gettext('Add a new user')
+ return render_template('/admin/create_user.html',
+ form=form, message=message)
+
+
+@admin_bp.route('/user/create', methods=['POST'])
+@admin_bp.route('/user/edit/<int:user_id>', methods=['POST'])
+@login_required
+@admin_permission.require(http_exception=403)
+def process_user_form(user_id=None):
+ """
+ Create or edit a user.
+ """
+ form = UserForm()
+ user_contr = UserController()
+
+ if not form.validate():
+ return render_template('/admin/create_user.html', form=form,
+ message=gettext('Some errors were found'))
+
+ role_user = Role.query.filter(Role.name == "user").first()
+ if user_id is not None:
+ # Edit a user
+ user_contr.update({'id': user_id},
+ {'nickname': form.nickname.data,
+ 'email': form.email.data,
+ 'password': form.password.data,
+ 'refresh_rate': form.refresh_rate.data})
+ user = user_contr.get(id=user_id)
+ flash(gettext('User %(nick)s successfully updated',
+ nick=user.nickname), 'success')
+ else:
+ # Create a new user
+ user = user_contr.create(nickname=form.nickname.data,
+ email=form.email.data,
+ password=form.password.data,
+ roles=[role_user],
+ refresh_rate=form.refresh_rate.data,
+ activation_key="")
+ flash(gettext('User %(nick)s successfully created',
+ nick=user.nickname), 'success')
+ return redirect(url_for('admin.user_form', user_id=user.id))
+
+
+@admin_bp.route('/user/<int:user_id>', methods=['GET'])
+@login_required
+@admin_permission.require(http_exception=403)
+def user(user_id=None):
+ """
+ See information about a user (stations, etc.).
+ """
+ user = UserController().get(id=user_id)
+ if user is not None:
+ article_contr = ArticleController(user_id)
+ return render_template('/admin/user.html', user=user, feeds=user.feeds,
+ article_count=article_contr.count_by_feed(),
+ unread_article_count=article_contr.count_by_feed(readed=False))
+
+ else:
+ flash(gettext('This user does not exist.'), 'danger')
+ return redirect(redirect_url())
+
+
+@admin_bp.route('/delete_user/<int:user_id>', methods=['GET'])
+@login_required
+@admin_permission.require(http_exception=403)
+def delete_user(user_id=None):
+ """
+ Delete a user (with all its data).
+ """
+ try:
+ user = UserController().delete(user_id)
+ flash(gettext('User %(nick)s successfully deleted',
+ nick=user.nickname), 'success')
+ except Exception as error:
+ flash(gettext('An error occured while trying to delete a user: '
+ '%(error)', error=error), 'danger')
+ return redirect(redirect_url())
+
+
+@admin_bp.route('/toggle_user/<int:user_id>', methods=['GET'])
+@login_required
+@admin_permission.require()
+def toggle_user(user_id=None):
+ """
+ Enable or disable the account of a user.
+ """
+ user_contr = UserController()
+ user = user_contr.get(id=user_id)
+
+ if user is None:
+ flash(gettext('This user does not exist.'), 'danger')
+ return redirect(url_for('admin.dashboard'))
+
+ if user.activation_key != "":
+
+ # Send the confirmation email
+ try:
+ notifications.new_account_activation(user)
+ user_contr.unset_activation_key(user.id)
+ message = gettext('Account of the user %(nick)s successfully '
+ 'activated.', nick=user.nickname)
+ except Exception as error:
+ flash(gettext('Problem while sending activation email %(error)s:',
+ error=error), 'danger')
+ return redirect(url_for('admin.dashboard'))
+
+ else:
+ user_contr.set_activation_key(user.id)
+ message = gettext('Account of the user %(nick)s successfully disabled',
+ nick=user.nickname)
+ flash(message, 'success')
+ return redirect(url_for('admin.dashboard'))
diff --git a/pyaggr3g470r/views/user.py b/pyaggr3g470r/views/user.py
new file mode 100644
index 00000000..cb416b5d
--- /dev/null
+++ b/pyaggr3g470r/views/user.py
@@ -0,0 +1,152 @@
+import string
+import random
+from flask import (Blueprint, g, render_template, redirect,
+ flash, url_for, request)
+from flask.ext.babel import gettext
+from flask.ext.login import login_required
+
+import conf
+from pyaggr3g470r import utils, notifications
+from pyaggr3g470r.controllers import (UserController, FeedController,
+ ArticleController)
+
+from pyaggr3g470r.forms import ProfileForm, RecoverPasswordForm
+
+users_bp = Blueprint('users', __name__, url_prefix='/users')
+user_bp = Blueprint('user', __name__, url_prefix='/user')
+
+
+@user_bp.route('/management', methods=['GET', 'POST'])
+@login_required
+def management():
+ """
+ Display the management page.
+ """
+ if request.method == 'POST':
+ if None != request.files.get('opmlfile', None):
+ # Import an OPML file
+ data = request.files.get('opmlfile', None)
+ if not utils.allowed_file(data.filename):
+ flash(gettext('File not allowed.'), 'danger')
+ else:
+ try:
+ nb = utils.import_opml(g.user.email, data.read())
+ if conf.CRAWLING_METHOD == "classic":
+ utils.fetch(g.user.email, None)
+ flash(str(nb) + ' ' + gettext('feeds imported.'),
+ "success")
+ flash(gettext("Downloading articles..."), 'info')
+ except:
+ flash(gettext("Impossible to import the new feeds."),
+ "danger")
+ elif None != request.files.get('jsonfile', None):
+ # Import an account
+ data = request.files.get('jsonfile', None)
+ if not utils.allowed_file(data.filename):
+ flash(gettext('File not allowed.'), 'danger')
+ else:
+ try:
+ nb = utils.import_json(g.user.email, data.read())
+ flash(gettext('Account imported.'), "success")
+ except:
+ flash(gettext("Impossible to import the account."),
+ "danger")
+ else:
+ flash(gettext('File not allowed.'), 'danger')
+
+ nb_feeds = FeedController(g.user.id).read().count()
+ art_contr = ArticleController(g.user.id)
+ nb_articles = art_contr.read().count()
+ nb_unread_articles = art_contr.read(readed=False).count()
+ return render_template('management.html', user=g.user,
+ nb_feeds=nb_feeds, nb_articles=nb_articles,
+ nb_unread_articles=nb_unread_articles)
+
+
+@user_bp.route('/profile', methods=['GET', 'POST'])
+@login_required
+def profile():
+ """
+ Edit the profile of the currently logged user.
+ """
+ user_contr = UserController(g.user.id)
+ user = user_contr.get(id=g.user.id)
+ form = ProfileForm()
+
+ if request.method == 'POST':
+ if form.validate():
+ user_contr.update({'id': g.user.id},
+ {'nickname': form.nickname.data,
+ 'email': form.email.data,
+ 'password': form.password.data,
+ 'refresh_rate': form.refresh_rate.data})
+
+ flash(gettext('User %(nick)s successfully updated',
+ nick=user.nickname), 'success')
+ return redirect(url_for('user.profile'))
+ else:
+ return render_template('profile.html', user=user, form=form)
+
+ if request.method == 'GET':
+ form = ProfileForm(obj=user)
+ return render_template('profile.html', user=user, form=form)
+
+
+@user_bp.route('/delete_account', methods=['GET'])
+@login_required
+def delete_account():
+ """
+ Delete the account of the user (with all its data).
+ """
+ UserController(g.user.id).delete(g.user.id)
+ flash(gettext('Your account has been deleted.'), 'success')
+ return redirect(url_for('login'))
+
+
+@user_bp.route('/confirm_account/<string:activation_key>', methods=['GET'])
+def confirm_account(activation_key=None):
+ """
+ Confirm the account of a user.
+ """
+ user_contr = UserController()
+ if activation_key != "":
+ user = user_contr.read(activation_key=activation_key).first()
+ if user is not None:
+ user_contr.update({'id': user.id}, {'activation_key': ''})
+ flash(gettext('Your account has been confirmed.'), 'success')
+ else:
+ flash(gettext('Impossible to confirm this account.'), 'danger')
+ return redirect(url_for('login'))
+
+
+@user_bp.route('/recover', methods=['GET', 'POST'])
+def recover():
+ """
+ Enables the user to recover its account when he has forgotten
+ its password.
+ """
+ form = RecoverPasswordForm()
+ user_contr = UserController()
+
+ if request.method == 'POST':
+ if form.validate():
+ user = user_contr.get(email=form.email.data)
+ characters = string.ascii_letters + string.digits
+ password = "".join(random.choice(characters)
+ for x in range(random.randint(8, 16)))
+ user.set_password(password)
+ user_contr.update({'id': user.id}, {'password': password})
+
+ # Send the confirmation email
+ try:
+ notifications.new_password_notification(user, password)
+ flash(gettext('New password sent to your address.'), 'success')
+ except Exception as error:
+ flash(gettext('Problem while sending your new password: '
+ '%(error)s', error=error), 'danger')
+
+ return redirect(url_for('login'))
+ return render_template('recover.html', form=form)
+
+ if request.method == 'GET':
+ return render_template('recover.html', form=form)
diff --git a/src/runserver.py b/src/runserver.py
index b355d7d1..d0bfa533 100755
--- a/src/runserver.py
+++ b/src/runserver.py
@@ -54,6 +54,9 @@ with application.app_context():
application.register_blueprint(views.categories_bp)
application.register_blueprint(views.category_bp)
application.register_blueprint(views.icon_bp)
+ application.register_blueprint(views.admin_bp)
+ application.register_blueprint(views.users_bp)
+ application.register_blueprint(views.user_bp)
if __name__ == '__main__':
diff --git a/src/web/controllers/abstract.py b/src/web/controllers/abstract.py
index f33d241e..99d92ff3 100644
--- a/src/web/controllers/abstract.py
+++ b/src/web/controllers/abstract.py
@@ -84,7 +84,7 @@ class AbstractController(object):
def create(self, **attrs):
assert self._user_id_key is None or self._user_id_key in attrs \
- or self.user_id is not None, \
+ or self.user_id is None, \
"You must provide user_id one way or another"
if self._user_id_key is not None and self._user_id_key not in attrs:
diff --git a/src/web/controllers/user.py b/src/web/controllers/user.py
index 3f96b185..d8bf1fa1 100644
--- a/src/web/controllers/user.py
+++ b/src/web/controllers/user.py
@@ -1,3 +1,6 @@
+import random
+import hashlib
+from werkzeug import generate_password_hash
from .abstract import AbstractController
from web.models import User
@@ -5,3 +8,25 @@ from web.models import User
class UserController(AbstractController):
_db_cls = User
_user_id_key = 'id'
+
+ def unset_activation_key(self, obj_id):
+ self.update({'id': obj_id}, {'activation_key': ""})
+
+ def set_activation_key(self, obj_id):
+ key = str(random.getrandbits(256)).encode("utf-8")
+ key = hashlib.sha512(key).hexdigest()[:86]
+ self.update({'id': obj_id}, {'activation_key': key})
+
+ def _handle_password(self, attrs):
+ if attrs.get('password'):
+ attrs['pwdhash'] = generate_password_hash(attrs.pop('password'))
+ elif 'password' in attrs:
+ del attrs['password']
+
+ def create(self, **attrs):
+ self._handle_password(attrs)
+ return super().create(**attrs)
+
+ def update(self, filters, attrs):
+ self._handle_password(attrs)
+ return super().update(filters, attrs)
diff --git a/src/web/models/user.py b/src/web/models/user.py
index c5e70036..d1b9c568 100644
--- a/src/web/models/user.py
+++ b/src/web/models/user.py
@@ -30,7 +30,7 @@ import re
import random
import hashlib
from datetime import datetime
-from werkzeug import generate_password_hash, check_password_hash
+from werkzeug import check_password_hash
from flask.ext.login import UserMixin
from bootstrap import db
@@ -63,12 +63,6 @@ class User(db.Model, UserMixin):
"""
return self.id
- 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.
@@ -79,7 +73,7 @@ class User(db.Model, UserMixin):
"""
Return True if the user has administrator rights.
"""
- return len([role for role in self.roles if role.name == "admin"]) != 0
+ return "admin" in [role.name for role in self.roles]
def __eq__(self, other):
return self.id == other.id
diff --git a/src/web/templates/admin/dashboard.html b/src/web/templates/admin/dashboard.html
index 25bd3883..2436c955 100644
--- a/src/web/templates/admin/dashboard.html
+++ b/src/web/templates/admin/dashboard.html
@@ -20,29 +20,31 @@
<tr {% if user.activation_key != "" %}class="warning"{% endif %}>
<td>{{ loop.index }}</td>
{% if user.id == current_user.id %}
- <td><a href="/management">{{ user.nickname }}</a> (It's you!)</td>
+ <td><a href="{{ url_for("user.management") }}">{{ user.nickname }}</a> (It's you!)</td>
{% else %}
- <td><a href="/admin/user/{{ user.id }}">{{ user.nickname }}</a></td>
+ <td><a href="{{ url_for("admin.user", user_id=user.id) }}">{{ user.nickname }}</a></td>
{% endif %}
<td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td>
<td class="date">{{ user.last_seen }}</td>
<td>
- <a href="/admin/user/{{ user.id }}"><i class="glyphicon glyphicon-user" title="{{ _('View this user') }}"></i></a>
- <a href="/admin/edit_user/{{ user.id }}"><i class="glyphicon glyphicon-edit" title="{{ _('Edit this user') }}"></i></a>
+ <a href="{{ url_for("admin.user", user_id=user.id) }}"><i class="glyphicon glyphicon-user" title="{{ _('View this user') }}"></i></a>
+ <a href="{{ url_for("admin.user_form", user_id=user.id) }}"><i class="glyphicon glyphicon-edit" title="{{ _('Edit this user') }}"></i></a>
{% if user.id != current_user.id %}
+ <a href="{{ url_for("admin.toggle_user", user_id=user.id) }}">
{% if user.activation_key == "" %}
- <a href="/admin/disable_user/{{ user.id }}"><i class="glyphicon glyphicon-ban-circle" title="Disable this account"></i></a>
+ <i class="glyphicon glyphicon-ban-circle" title="{{ _("Disable this account") }}"></i>
{% else %}
- <a href="/admin/enable_user/{{ user.id }}"><i class="glyphicon glyphicon-ok-circle" title="Enable this account"></i></a>
+ <i class="glyphicon glyphicon-ok-circle" title="{{ _("Enable this account") }}"></i>
{% endif %}
- <a href="/admin/delete_user/{{ user.id }}"><i class="glyphicon glyphicon-remove" title="{{ _('Delete this user') }}" onclick="return confirm('{{ _('You are going to delete this account.') }}');"></i></a>
+ </a>
+ <a href="{{ url_for("admin.delete_user", user_id=user.id) }}"><i class="glyphicon glyphicon-remove" title="{{ _('Delete this user') }}" onclick="return confirm('{{ _('You are going to delete this account.') }}');"></i></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
-<a href="/admin/create_user" class="btn btn-default">{{ _('Add a new user') }}</a>
+<a href="{{ url_for("admin.user_form") }}" class="btn btn-default">{{ _('Add a new user') }}</a>
<h1>{{ _('Send notification messages') }}</h1>
<form action="" method="post">
{{ form.hidden_tag() }}
diff --git a/src/web/templates/home.html b/src/web/templates/home.html
index 86d96e94..6b136870 100644
--- a/src/web/templates/home.html
+++ b/src/web/templates/home.html
@@ -3,7 +3,7 @@
{% if feeds|count == 0 %}
<div class="col-md-4 col-md-offset-4">
<h1>{{ _("You don't have any feeds.") }}</h1>
- <h1><a href="{{ url_for("feed.form") }}">{{ _('Add some') }}</a>, {{ _('or') }} <a href="/management">{{ _('upload an OPML file.') }}</a></h1>
+ <h1><a href="{{ url_for("feed.form") }}">{{ _('Add some') }}</a>, {{ _('or') }} <a href="{{ url_for("user.management") }}">{{ _('upload an OPML file.') }}</a></h1>
</div>
{% else %}
<div class="container-fluid">
diff --git a/src/web/templates/layout.html b/src/web/templates/layout.html
index cf2498e2..eb213ca5 100644
--- a/src/web/templates/layout.html
+++ b/src/web/templates/layout.html
@@ -81,12 +81,12 @@
<div><span class="glyphicon glyphicon-user"></span>&nbsp;<b class="caret"></b></div>
</a>
<ul class="dropdown-menu">
- <li><a href="{{ url_for("profile") }}"><span class="glyphicon glyphicon-user"></span> {{ _('Profile') }}</a></li>
- <li><a href="{{ url_for("management") }}"><span class="glyphicon glyphicon-cog"></span> {{ _('Your data') }}</a></li>
+ <li><a href="{{ url_for("user.profile") }}"><span class="glyphicon glyphicon-user"></span> {{ _('Profile') }}</a></li>
+ <li><a href="{{ url_for("user.management") }}"><span class="glyphicon glyphicon-cog"></span> {{ _('Your data') }}</a></li>
<li><a href="{{ url_for("about") }}"><span class="glyphicon glyphicon-question-sign"></span> {{ _('About') }}</a></li>
{% if g.user.is_admin() %}
<li role="presentation" class="divider"></li>
- <li><a href="{{ url_for("dashboard") }}"><span class="glyphicon glyphicon-dashboard"></span> {{ _('Dashboard') }}</a></li>
+ <li><a href="{{ url_for("admin.dashboard") }}"><span class="glyphicon glyphicon-dashboard"></span> {{ _('Dashboard') }}</a></li>
<li role="presentation" class="divider"></li>
{% endif %}
<li><a href="{{ url_for("logout") }}"><span class="glyphicon glyphicon-log-out"></span> {{ _('Logout') }}</a></li>
diff --git a/src/web/utils.py b/src/web/utils.py
index 38d15f25..6182eb0e 100755
--- a/src/web/utils.py
+++ b/src/web/utils.py
@@ -112,7 +112,7 @@ def fetch(id, feed_id=None):
"""
cmd = [sys.executable, conf.BASE_DIR+'/manager.py', 'fetch_asyncio', str(id),
str(feed_id)]
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ return subprocess.Popen(cmd, stdout=subprocess.PIPE)
def history(user_id, year=None, month=None):
"""
diff --git a/src/web/views/__init__.py b/src/web/views/__init__.py
index 1da9205b..f02e86e6 100644
--- a/src/web/views/__init__.py
+++ b/src/web/views/__init__.py
@@ -5,3 +5,5 @@ from .article import article_bp, articles_bp
from .feed import feed_bp, feeds_bp
from .category import category_bp, categories_bp
from .icon import icon_bp
+from .admin import admin_bp
+from .user import user_bp, users_bp
diff --git a/src/web/views/views.py b/src/web/views/views.py
index 1e7b7539..f543c6fa 100644
--- a/src/web/views/views.py
+++ b/src/web/views/views.py
@@ -53,8 +53,7 @@ from web import utils, notifications, export
from web.lib.view_utils import etag_match
from web.models import User, Feed, Article, Role
from web.decorators import feed_access_required
-from web.forms import SignupForm, SigninForm, InformationMessageForm,\
- ProfileForm, UserForm, RecoverPasswordForm \
+from web.forms import SignupForm, SigninForm
from web.controllers import UserController, FeedController, \
ArticleController
@@ -130,11 +129,6 @@ def internal_server_error(e):
return render_template('errors/500.html'), 500
-def redirect_url(default='home'):
- return request.args.get('next') or \
- request.referrer or \
- url_for(default)
-
@g.babel.localeselector
def get_locale():
"""
@@ -196,6 +190,7 @@ def logout():
flash(gettext("Logged out successfully."), 'success')
return redirect(url_for('login'))
+
@app.route('/signup', methods=['GET', 'POST'])
def signup():
"""
@@ -423,94 +418,6 @@ def export_opml():
return response
-@app.route('/management', methods=['GET', 'POST'])
-@login_required
-def management():
- """
- Display the management page.
- """
- if request.method == 'POST':
- if None != request.files.get('opmlfile', None):
- # Import an OPML file
- data = request.files.get('opmlfile', None)
- if not utils.allowed_file(data.filename):
- flash(gettext('File not allowed.'), 'danger')
- else:
- try:
- nb = utils.import_opml(g.user.email, data.read())
- if conf.CRAWLING_METHOD == "classic":
- utils.fetch(g.user.email, None)
- flash(str(nb) + ' ' + gettext('feeds imported.'),
- "success")
- flash(gettext("Downloading articles..."), 'info')
- except:
- flash(gettext("Impossible to import the new feeds."),
- "danger")
- elif None != request.files.get('jsonfile', None):
- # Import an account
- data = request.files.get('jsonfile', None)
- if not utils.allowed_file(data.filename):
- flash(gettext('File not allowed.'), 'danger')
- else:
- try:
- nb = utils.import_json(g.user.email, data.read())
- flash(gettext('Account imported.'), "success")
- except:
- flash(gettext("Impossible to import the account."),
- "danger")
- else:
- flash(gettext('File not allowed.'), 'danger')
-
- nb_feeds = len(g.user.feeds.all())
- articles = Article.query.filter(Article.user_id == g.user.id)
- nb_articles = articles.count()
- nb_unread_articles = articles.filter(Article.readed == False).count()
- return render_template('management.html', user=g.user,
- nb_feeds=nb_feeds, nb_articles=nb_articles,
- nb_unread_articles=nb_unread_articles)
-
-
-@app.route('/profile', methods=['GET', 'POST'])
-@login_required
-def profile():
- """
- Edit the profile of the currently logged user.
- """
- user = UserController(g.user.id).get(id=g.user.id)
- form = ProfileForm()
-
- if request.method == 'POST':
- if form.validate():
- form.populate_obj(user)
- if form.password.data != "":
- user.set_password(form.password.data)
- db.session.commit()
- flash("%s %s %s" % (gettext('User'), user.nickname,
- gettext('successfully updated.')),
- 'success')
- return redirect(url_for('profile'))
- else:
- return render_template('profile.html', user=user, form=form)
-
- if request.method == 'GET':
- form = ProfileForm(obj=user)
- return render_template('profile.html', user=user, form=form)
-
-@app.route('/delete_account', methods=['GET'])
-@login_required
-def delete_account():
- """
- Delete the account of the user (with all its data).
- """
- user = UserController(g.user.id).get(id=g.user.id)
- if user is not None:
- db.session.delete(user)
- db.session.commit()
- flash(gettext('Your account has been deleted.'), 'success')
- else:
- flash(gettext('This user does not exist.'), 'danger')
- return redirect(url_for('login'))
-
@app.route('/expire_articles', methods=['GET'])
@login_required
def expire_articles():
@@ -526,180 +433,3 @@ def expire_articles():
flash(gettext('Articles deleted.'), 'info')
db.session.commit()
return redirect(redirect_url())
-
-@app.route('/confirm_account/<string:activation_key>', methods=['GET'])
-def confirm_account(activation_key=None):
- """
- Confirm the account of a user.
- """
- if activation_key != "":
- user = User.query.filter(User.activation_key == activation_key).first()
- if user is not None:
- user.activation_key = ""
- db.session.commit()
- flash(gettext('Your account has been confirmed.'), 'success')
- else:
- flash(gettext('Impossible to confirm this account.'), 'danger')
- return redirect(url_for('login'))
-
-@app.route('/recover', methods=['GET', 'POST'])
-def recover():
- """
- Enables the user to recover its account when he has forgotten
- its password.
- """
- form = RecoverPasswordForm()
-
- if request.method == 'POST':
- if form.validate():
- user = User.query.filter(User.email == form.email.data).first()
- characters = string.ascii_letters + string.digits
- password = "".join(random.choice(characters) for x in range(random.randint(8, 16)))
- user.set_password(password)
- db.session.commit()
-
- # Send the confirmation email
- try:
- notifications.new_password_notification(user, password)
- flash(gettext('New password sent to your address.'), 'success')
- except Exception as e:
- flash(gettext('Problem while sending your new password.') + ': ' + str(e), 'danger')
-
- return redirect(url_for('login'))
- return render_template('recover.html', form=form)
-
- if request.method == 'GET':
- return render_template('recover.html', form=form)
-
-#
-# Views dedicated to administration tasks.
-#
-@app.route('/admin/dashboard', methods=['GET', 'POST'])
-@login_required
-@admin_permission.require(http_exception=403)
-def dashboard():
- """
- Adminstrator's dashboard.
- """
- form = InformationMessageForm()
-
- if request.method == 'POST':
- if form.validate():
- try:
- notifications.information_message(form.subject.data, form.message.data)
- except Exception as e:
- flash(gettext('Problem while sending email') + ': ' + str(e), 'danger')
-
- users = User.query.all()
- return render_template('admin/dashboard.html', users=users, current_user=g.user, form=form)
-
-@app.route('/admin/create_user', methods=['GET', 'POST'])
-@app.route('/admin/edit_user/<int:user_id>', methods=['GET', 'POST'])
-@login_required
-@admin_permission.require(http_exception=403)
-def create_user(user_id=None):
- """
- Create or edit a user.
- """
- form = UserForm()
-
- if request.method == 'POST':
- if form.validate():
- role_user = Role.query.filter(Role.name == "user").first()
- if user_id is not None:
- # Edit a user
- user = User.query.filter(User.id == user_id).first()
- form.populate_obj(user)
- if form.password.data != "":
- user.set_password(form.password.data)
- db.session.commit()
- flash(gettext('User') + ' ' + user.nickname + ' ' + gettext('successfully updated.'), 'success')
- else:
- # Create a new user
- user = User(nickname=form.nickname.data,
- email=form.email.data,
- pwdhash=generate_password_hash(form.password.data))
- user.roles.extend([role_user])
- user.activation_key = ""
- db.session.add(user)
- db.session.commit()
- flash("%s %s %s" % (gettext('User'), user.nickname,
- gettext('successfully created.')),
- 'success')
- return redirect(url_for('create_user', user_id=user.id))
- else:
- return redirect(url_for('create_user'))
-
- if request.method == 'GET':
- if user_id is not None:
- user = User.query.filter(User.id == user_id).first()
- form = UserForm(obj=user)
- message = "%s <i>%s</i>" % (gettext('Edit the user'),
- user.nickname)
- else:
- form = UserForm()
- message = gettext('Add a new user')
- return render_template('/admin/create_user.html',
- form=form, message=message)
-
-@app.route('/admin/user/<int:user_id>', methods=['GET'])
-@login_required
-@admin_permission.require(http_exception=403)
-def user(user_id=None):
- """
- See information about a user (stations, etc.).
- """
- user = UserController().get(id=user_id)
- if user is not None:
- article_contr = ArticleController(user_id)
- return render_template('/admin/user.html', user=user, feeds=user.feeds,
- article_count=article_contr.count_by_feed(),
- unread_article_count=article_contr.count_by_feed(readed=False))
-
- else:
- flash(gettext('This user does not exist.'), 'danger')
- return redirect(redirect_url())
-
-@app.route('/admin/delete_user/<int:user_id>', methods=['GET'])
-@login_required
-@admin_permission.require(http_exception=403)
-def delete_user(user_id=None):
- """
- Delete a user (with all its data).
- """
- user = User.query.filter(User.id == user_id).first()
- if user is not None:
- db.session.delete(user)
- db.session.commit()
- flash(gettext('User') + ' ' + user.nickname + ' ' + gettext('successfully deleted.'), 'success')
- else:
- flash(gettext('This user does not exist.'), 'danger')
- return redirect(redirect_url())
-
-@app.route('/admin/enable_user/<int:user_id>', methods=['GET'])
-@app.route('/admin/disable_user/<int:user_id>', methods=['GET'])
-@login_required
-@admin_permission.require()
-def disable_user(user_id=None):
- """
- Enable or disable the account of a user.
- """
- user = User.query.filter(User.id == user_id).first()
- if user is not None:
- if user.activation_key != "":
-
- # Send the confirmation email
- try:
- notifications.new_account_activation(user)
- user.activation_key = ""
- flash(gettext('Account of the user') + ' ' + user.nickname + ' ' + gettext('successfully activated.'), 'success')
- except Exception as e:
- flash(gettext('Problem while sending activation email') + ': ' + str(e), 'danger')
-
- else:
- user.activation_key = hashlib.sha512(str(random.getrandbits(256)).encode("utf-8")).hexdigest()[:86]
- flash(gettext('Account of the user') + ' ' + user.nickname + ' ' + gettext('successfully disabled.'), 'success')
- db.session.commit()
- else:
- flash(gettext('This user does not exist.'), 'danger')
- return redirect(redirect_url())
bgstack15