diff options
-rw-r--r-- | accounts/__init__.py | 253 | ||||
-rw-r--r-- | accounts/forms.py | 4 | ||||
-rw-r--r-- | accounts/templates/base.html | 8 | ||||
-rw-r--r-- | accounts/templates/index.html | 10 | ||||
-rw-r--r-- | accounts/templates/lost_password.html | 2 | ||||
-rw-r--r-- | accounts/templates/lost_password_complete.html | 2 | ||||
-rw-r--r-- | accounts/templates/mail/change_mail.txt | 2 | ||||
-rw-r--r-- | accounts/templates/mail/register.txt | 2 | ||||
-rw-r--r-- | accounts/templates/register.html | 2 | ||||
-rw-r--r-- | accounts/templates/register_complete.html | 2 | ||||
-rw-r--r-- | accounts/templates/settings.html | 2 | ||||
-rw-r--r-- | accounts/utils.py | 2 | ||||
-rw-r--r-- | accounts/views/default/__init__.py | 246 |
13 files changed, 269 insertions, 268 deletions
diff --git a/accounts/__init__.py b/accounts/__init__.py index a75010b..35c0475 100644 --- a/accounts/__init__.py +++ b/accounts/__init__.py @@ -3,13 +3,14 @@ import account import ldap import os -from copy import deepcopy -from flask import flash, Flask, g, redirect, request, session +from flask import Flask, g, session from utils import * -from views import admin +from views import default, admin + app = Flask(__name__) +app.register_blueprint(default.bp) app.register_blueprint(admin.bp, url_prefix='/admin') app.config.from_object('accounts.default_settings') if 'SPLINE_ACCOUNT_WEB_SETTINGS' in os.environ: @@ -51,249 +52,3 @@ def template_default_context(): return { 'app': app } - - -@app.route('/', methods=['GET', 'POST']) -@templated('index.html') -def index(): - if not g.user: - form = LoginForm(request.form) - if form.validate_on_submit(): - if login_user(form.username.data, form.password.data): - flash(u'Erfolgreich eingeloggt', 'success') - return redirect(url_for('settings')) - else: - flash(u'Ungültiger Benutzername und/oder Passwort', 'error') - else: - return redirect(url_for('settings')) - - return {'form': form} - - -@app.route('/register', methods=['GET', 'POST']) -@templated('register.html') -@logout_required -def register(): - form = RegisterForm(request.form) - if form.validate_on_submit(): - send_register_confirmation_mail(form.username.data, form.mail.data) - - flash(u'Es wurde eine E-Mail an die angegebene Adresse geschickt, ' - u'um diese zu überprüfen. Bitte folge den Anweisungen in der ' - u'E-Mail.', 'success') - - return redirect(url_for('index')) - - return {'form': form} - - -@app.route('/register/<token>', methods=['GET', 'POST']) -@templated('register_complete.html') -@logout_required -def register_complete(token): - #TODO: check for double uids and mail - username, mail = http_verify_confirmation('register', token.encode('ascii'), timeout=3*24*60*60) - - try: - app.user_backend.get_by_uid(username) - app.user_backend.get_by_mail(mail) - except app.user_backend.NoSuchUserError: - pass - else: - flash(u'Du hast den Benutzer bereits angelegt! Du kannst dich jetzt einfach einloggen:') - return redirect(url_for('index')) - - form = RegisterCompleteForm(request.form) - if form.validate_on_submit(): - password = form.password.data - - user = account.Account(username, mail, password=form.password.data) - app.user_backend.register(user) - - # populate request context and session - assert login_user(user.uid, user.password) - - if app.config.get('MAIL_REGISTER_NOTIFY'): - app.mail_backend.send( - app.config['MAIL_REGISTER_NOTIFY'], - u'[accounts] Neuer Benutzer %s erstellt' % username, - u'Benutzername: %s\nE-Mail: %s\n\nSpammer? Deaktivieren: ' - u'%s\n' % (username, mail, - url_for('admin_disable_account', uid=username, _external=True)) - ) - - flash(u'Benutzer erfolgreich angelegt.', 'success') - return redirect(url_for('settings')) - - return { - 'form': form, - 'token': token, - 'username': username, - 'mail': mail, - } - - -@app.route('/lost_password', methods=['GET', 'POST']) -@templated('lost_password.html') -@logout_required -def lost_password(): - form = LostPasswordForm(request.form) - if form.validate_on_submit(): - #TODO: make the link only usable once (e.g include a hash of the old pw) - # atm the only thing we do is make the link valid for only little time - confirm_token = make_confirmation('lost_password', (form.user.uid,)) - confirm_link = url_for('lost_password_complete', token=confirm_token, _external=True) - - body = render_template('mail/lost_password.txt', username=form.user.uid, - link=confirm_link) - - app.mail_backend.send( - form.user.attributes['mail'], u'Passwort vergessen', body, - sender=app.config.get('MAIL_CONFIRM_SENDER')) - - flash(u'Wir haben dir eine E-Mail mit einem Link zum Passwort ändern ' - u'geschickt. Bitte folge den Anweisungen in der E-Mail.', 'success') - - return redirect(url_for('index')) - - return {'form': form} - - -@app.route('/lost_password/<token>', methods=['GET', 'POST']) -@templated('lost_password_complete.html') -@logout_required -def lost_password_complete(token): - username, = http_verify_confirmation('lost_password', token.encode('ascii'), timeout=4*60*60) - - form = RegisterCompleteForm(request.form) - if form.validate_on_submit(): - user = app.user_backend.get_by_uid(username) - user.change_password(form.password.data) - app.user_backend.update(user, as_admin=True) - - session['username'] = username - session['password'] = encrypt_password(form.password.data) - flash(u'Passwort geändert.', 'success') - - return redirect(url_for('settings')) - - return { - 'form': form, - 'token': token, - 'username': username, - } - - -@app.route('/settings', methods=['GET', 'POST']) -@templated('settings.html') -@login_required -def settings(): - form = SettingsForm(request.form, mail=g.user.attributes['mail']) - if form.validate_on_submit(): - changed = False - - if request.form.get('submit_services'): - for service in app.all_services: - field = form.get_servicedelete(service.id) - if(field.data): - g.user.reset_password(service.id) - changed = True - - elif request.form.get('submit_main'): - if form.mail.data and form.mail.data != g.user.attributes['mail']: - confirm_token = make_confirmation('change_mail', (g.user.uid, form.mail.data)) - confirm_link = url_for('change_mail', token=confirm_token, _external=True) - - body = render_template('mail/change_mail.txt', username=g.user.uid, - mail=form.mail.data, link=confirm_link) - - app.mail_backend.send( - form.mail.data, u'E-Mail-Adresse bestätigen', body, - sender=app.config.get('MAIL_CONFIRM_SENDER')) - - flash(u'Es wurde eine E-Mail an die angegebene Adresse geschickt, ' - u'um diese zu überprüfen. Bitte folge den Anweisungen in der ' - u'E-Mail.', 'success') - changed = True - - if form.password.data: - g.user.change_password(form.password.data, form.old_password.data) - session['password'] = encrypt_password(form.password.data) - - flash(u'Passwort geändert', 'success') - changed = True - - for service in app.all_services: - field = form.get_servicepassword(service.id) - if field.data: - changed = True - g.user.change_password(field.data, None, service.id) - - if changed: - app.user_backend.update(g.user, as_admin=True) #XXX: as_admin wieder wegmachen sobald ACLs richtig gesetzt sind - return redirect(url_for('settings')) - else: - flash(u'Nichts geändert.') - - - services = deepcopy(app.all_services) - for s in services: - s.changed = s.id in g.user.services - - return { - 'form': form, - 'services': services, - } - -@app.route('/settings/change_mail/<token>') -@login_required -def change_mail(token): - username, mail = http_verify_confirmation('change_mail', token.encode('ascii'), timeout=3*24*60*60) - - if g.user.uid != username: - raise Forbidden(u'Bitte logge dich als der Benutzer ein, dessen E-Mail-Adresse du ändern willst.') - - results = app.user_backend.find_by_mail(mail) - for user in results: - if user.uid != g.user.uid: - raise Forbidden(u'Diese E-Mail-Adresse wird schon von einem anderen account benutzt!') - - g.user.change_email(mail) - app.user_backend.update(g.user) - - flash(u'E-Mail-Adresse geändert.', 'success') - return redirect(url_for('settings')) - - -@app.route('/logout') -def logout(): - logout_user() - flash(u'Erfolgreich ausgeloggt.', 'success') - return redirect(url_for('index')) - - -@app.route('/about') -@templated('about.html') -def about(): - return {} - - -@app.errorhandler(403) -@app.errorhandler(404) -def errorhandler(e): - return render_template('error.html', error=e), e.code - - -@app.route('/debug') -def debug(): - raise Exception() - - -# we need the app to exist before initializing the forms -from forms import RegisterForm, RegisterCompleteForm, LoginForm, SettingsForm,\ - LostPasswordForm, AdminCreateAccountForm,\ - AdminDisableAccountForm - - -if __name__ == '__main__': - app.run() diff --git a/accounts/forms.py b/accounts/forms.py index c374ef6..4385e7a 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -31,7 +31,7 @@ class RegisterForm(Form): if field.data.lower() in current_app.username_blacklist: raise ValidationError(Markup(u'Dieser Benutzername ist momentan nicht erlaubt. ' - u'<a href="%s">Weitere Informationen</a>' % url_for('about'))) + u'<a href="%s">Weitere Informationen</a>' % url_for('default.about'))) else: raise ValidationError(u'Dieser Benutzername ist schon vergeben.') @@ -44,7 +44,7 @@ class RegisterForm(Form): raise ValidationError(Markup(u'Ein Benutzername mit dieser Adresse existiert bereits. ' u'Falls du deinen Benutzernamen vergessen hast, kannst du die ' u'<a href="%s">Passwort-vergessen-Funktion</a> benutzen.' - % url_for('lost_password'))) + % url_for('default.lost_password'))) class AdminCreateAccountForm(RegisterForm): def validate_username(form, field): diff --git a/accounts/templates/base.html b/accounts/templates/base.html index d6a1726..1eeda55 100644 --- a/accounts/templates/base.html +++ b/accounts/templates/base.html @@ -15,7 +15,7 @@ <div id="header-background"> </div> <header> - <h1><a href="{{ url_for('settings') if g.user else url_for('index') }}"> + <h1><a href="{{ url_for('default.settings') if g.user else url_for('default.index') }}"> <img src="{{ url_for('static', filename='logo.png') }}" alt="spline accounts" /> </a></h1> <span id="roundcornerb"> </span> @@ -24,7 +24,7 @@ <nav id="mainnav"> <ul> <li><a href="http://spline.de">spline.de</a></li> - <li><a href="{{ url_for('about') }}">FAQ</a></li> + <li><a href="{{ url_for('default.about') }}">FAQ</a></li> </ul> </nav> @@ -36,10 +36,10 @@ {%- if g.user.uid in config.get('ADMIN_USERS', []) %} <li><a href="{{ url_for('admin.index') }}">Admin</a></li> {%- endif %} - <li><a href="{{ url_for('logout') }}">Abmelden</a></li> + <li><a href="{{ url_for('default.logout') }}">Abmelden</a></li> {%- else %} <li>Nicht angemeldet</li> - <li><a href="{{ url_for('index') }}">Login</a></li> + <li><a href="{{ url_for('default.index') }}">Login</a></li> {%- endif %} </ul> </nav> diff --git a/accounts/templates/index.html b/accounts/templates/index.html index 4d398de..075e7c9 100644 --- a/accounts/templates/index.html +++ b/accounts/templates/index.html @@ -5,17 +5,17 @@ <p> Willkommen bei <strong>spline accounts</strong>. Melde dich an, - <a href="{{ url_for('about') }}">informier dich</a>, oder - <a href="{{ url_for('register') }}">leg einen Account an</a>. + <a href="{{ url_for('.about') }}">informier dich</a>, oder + <a href="{{ url_for('.register') }}">leg einen Account an</a>. </p> -<form action="{{ url_for('index') }}" method="post" class="form-horizontal"> +<form action="{{ url_for('.index') }}" method="post" class="form-horizontal"> {% for field in form %} {{ render_field(field) }} {% endfor %} {{ render_submit(value='Login') }} - <p class="form-actions"><a href="{{ url_for('register') }}">Account erstellen</a></div> - <p class="form-actions"><a href="{{ url_for('lost_password') }}">Passwort oder Benutzername vergessen</a></div> + <p class="form-actions"><a href="{{ url_for('.register') }}">Account erstellen</a></div> + <p class="form-actions"><a href="{{ url_for('.lost_password') }}">Passwort oder Benutzername vergessen</a></div> </form> {%- endblock %} diff --git a/accounts/templates/lost_password.html b/accounts/templates/lost_password.html index 11021f1..5940973 100644 --- a/accounts/templates/lost_password.html +++ b/accounts/templates/lost_password.html @@ -10,7 +10,7 @@ In dieser Mail steht dann auch dein Benutzername. </p> -<form action="{{ url_for('lost_password') }}" method="post" class="form-horizontal"> +<form action="{{ url_for('.lost_password') }}" method="post" class="form-horizontal"> {% for field in form %} {{ render_field(field) }} {% endfor %} diff --git a/accounts/templates/lost_password_complete.html b/accounts/templates/lost_password_complete.html index 78ef512..e14d650 100644 --- a/accounts/templates/lost_password_complete.html +++ b/accounts/templates/lost_password_complete.html @@ -6,7 +6,7 @@ <p> Hier kannst du jetzt ein neues Passwort setzen. </p> -<form action="{{ url_for('lost_password_complete', token=token) }}" method="post" class="form-horizontal"> +<form action="{{ url_for('.lost_password_complete', token=token) }}" method="post" class="form-horizontal"> <div class="control-group"> <div class="control-label">Benutzername</div> <div class="controls"><input readonly="readonly" value="{{ username }}" /></div> diff --git a/accounts/templates/mail/change_mail.txt b/accounts/templates/mail/change_mail.txt index 2319672..64cda14 100644 --- a/accounts/templates/mail/change_mail.txt +++ b/accounts/templates/mail/change_mail.txt @@ -13,4 +13,4 @@ Wenn du dies nicht möchtest, brauchst du nichts weiter zu tun. Ohne deine Bestätigung wird die Adresse nicht geändert. -[1] {{ url_for('index', _external=True) }} +[1] {{ url_for('default.index', _external=True) }} diff --git a/accounts/templates/mail/register.txt b/accounts/templates/mail/register.txt index 1f837d6..c5af422 100644 --- a/accounts/templates/mail/register.txt +++ b/accounts/templates/mail/register.txt @@ -16,4 +16,4 @@ Wenn du diesen Account nicht anlegen möchtest, brauchst du nichts weiter zu tun. Ohne deine Bestätigung wird der Account nicht erstellt. -[1] {{ url_for('index', _external=True) }} +[1] {{ url_for('default.index', _external=True) }} diff --git a/accounts/templates/register.html b/accounts/templates/register.html index c317396..162cc20 100644 --- a/accounts/templates/register.html +++ b/accounts/templates/register.html @@ -13,7 +13,7 @@ Bitte such dir deinen Benutzernamen gut aus. Er kann später nicht mehr geändert werden. </p> -<form action="{{ url_for('register') }}" method="post" class="form-horizontal"> +<form action="{{ url_for('.register') }}" method="post" class="form-horizontal"> {% for field in form %} {{ render_field(field) }} {% endfor %} diff --git a/accounts/templates/register_complete.html b/accounts/templates/register_complete.html index d5cec72..1fb69de 100644 --- a/accounts/templates/register_complete.html +++ b/accounts/templates/register_complete.html @@ -7,7 +7,7 @@ Deine E-Mail-Adresse wurde erfolgreich bestätigt. Bitte setze nun ein Passwort, um die Registrierung abzuschließen. </p> -<form action="{{ url_for('register_complete', token=token) }}" method="post" class="form-horizontal"> +<form action="{{ url_for('.register_complete', token=token) }}" method="post" class="form-horizontal"> <div class="control-group"> <div class="control-label">Benutzername</div> <div class="controls"><input readonly="readonly" value="{{ username }}" /></div> diff --git a/accounts/templates/settings.html b/accounts/templates/settings.html index 58f2079..6591026 100644 --- a/accounts/templates/settings.html +++ b/accounts/templates/settings.html @@ -2,7 +2,7 @@ {%- from '_macros.html' import render_field, render_submit %} {%- set title = 'Einstellungen' %} {%- block content %} -<form action="{{ url_for('settings') }}" method="post" class="form-horizontal"> +<form action="{{ url_for('.settings') }}" method="post" class="form-horizontal"> <h2>Globale Einstellungen ändern</h2> {{ render_field(form.mail) }} <p></p> diff --git a/accounts/utils.py b/accounts/utils.py index 3b313d8..8f68733 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -210,7 +210,7 @@ def ensure_utf8(s): def send_register_confirmation_mail(username, mail): confirm_token = make_confirmation('register', (username, mail)) - confirm_link = url_for('register_complete', token=confirm_token, _external=True) + confirm_link = url_for('default.register_complete', token=confirm_token, _external=True) body = render_template('mail/register.txt', username=username, mail=mail, link=confirm_link) diff --git a/accounts/views/default/__init__.py b/accounts/views/default/__init__.py new file mode 100644 index 0000000..e2db8b2 --- /dev/null +++ b/accounts/views/default/__init__.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +from copy import deepcopy +from flask import Blueprint +from flask import current_app, redirect, request, g, flash, url_for + +from accounts.forms import LoginForm, RegisterForm, RegisterCompleteForm, \ + LostPasswordForm, SettingsForm +from accounts.utils import * +from accounts.account import Account + + +bp = Blueprint('default', __name__) + + +@bp.route('/', methods=['GET', 'POST']) +@templated('index.html') +def index(): + if not g.user: + form = LoginForm(request.form) + if form.validate_on_submit(): + if login_user(form.username.data, form.password.data): + flash(u'Erfolgreich eingeloggt', 'success') + return redirect(url_for('.settings')) + else: + flash(u'Ungültiger Benutzername und/oder Passwort', 'error') + else: + return redirect(url_for('.settings')) + + return {'form': form} + + +@bp.route('/register', methods=['GET', 'POST']) +@templated('register.html') +@logout_required +def register(): + form = RegisterForm(request.form) + if form.validate_on_submit(): + send_register_confirmation_mail(form.username.data, form.mail.data) + + flash(u'Es wurde eine E-Mail an die angegebene Adresse geschickt, ' + u'um diese zu überprüfen. Bitte folge den Anweisungen in der ' + u'E-Mail.', 'success') + + return redirect(url_for('.index')) + + return {'form': form} + + +@bp.route('/register/<token>', methods=['GET', 'POST']) +@templated('register_complete.html') +@logout_required +def register_complete(token): + #TODO: check for double uids and mail + username, mail = http_verify_confirmation('register', token.encode('ascii'), timeout=3*24*60*60) + + try: + current_app.user_backend.get_by_uid(username) + current_app.user_backend.get_by_mail(mail) + except current_app.user_backend.NoSuchUserError: + pass + else: + flash(u'Du hast den Benutzer bereits angelegt! Du kannst dich jetzt einfach einloggen:') + return redirect(url_for('.index')) + + form = RegisterCompleteForm(request.form) + if form.validate_on_submit(): + password = form.password.data + + user = Account(username, mail, password=form.password.data) + current_app.user_backend.register(user) + + # populate request context and session + assert login_user(user.uid, user.password) + + if current_app.config.get('MAIL_REGISTER_NOTIFY'): + current_app.mail_backend.send( + current_app.config['MAIL_REGISTER_NOTIFY'], + u'[accounts] Neuer Benutzer %s erstellt' % username, + u'Benutzername: %s\nE-Mail: %s\n\nSpammer? Deaktivieren: ' + u'%s\n' % (username, mail, + url_for('admin.disable_account', uid=username, _external=True)) + ) + + flash(u'Benutzer erfolgreich angelegt.', 'success') + return redirect(url_for('.settings')) + + return { + 'form': form, + 'token': token, + 'username': username, + 'mail': mail, + } + + +@bp.route('/lost_password', methods=['GET', 'POST']) +@templated('lost_password.html') +@logout_required +def lost_password(): + form = LostPasswordForm(request.form) + if form.validate_on_submit(): + #TODO: make the link only usable once (e.g include a hash of the old pw) + # atm the only thing we do is make the link valid for only little time + confirm_token = make_confirmation('lost_password', (form.user.uid,)) + confirm_link = url_for('.lost_password_complete', token=confirm_token, _external=True) + + body = render_template('mail/lost_password.txt', username=form.user.uid, + link=confirm_link) + + current_app.mail_backend.send( + form.user.attributes['mail'], u'Passwort vergessen', body, + sender=current_app.config.get('MAIL_CONFIRM_SENDER')) + + flash(u'Wir haben dir eine E-Mail mit einem Link zum Passwort ändern ' + u'geschickt. Bitte folge den Anweisungen in der E-Mail.', 'success') + + return redirect(url_for('.index')) + + return {'form': form} + + +@bp.route('/lost_password/<token>', methods=['GET', 'POST']) +@templated('lost_password_complete.html') +@logout_required +def lost_password_complete(token): + username, = http_verify_confirmation('lost_password', token.encode('ascii'), timeout=4*60*60) + + form = RegisterCompleteForm(request.form) + if form.validate_on_submit(): + user = current_app.user_backend.get_by_uid(username) + user.change_password(form.password.data) + current_app.user_backend.update(user, as_admin=True) + + session['username'] = username + session['password'] = encrypt_password(form.password.data) + flash(u'Passwort geändert.', 'success') + + return redirect(url_for('.settings')) + + return { + 'form': form, + 'token': token, + 'username': username, + } + + +@bp.route('/settings', methods=['GET', 'POST']) +@templated('settings.html') +@login_required +def settings(): + form = SettingsForm(request.form, mail=g.user.attributes['mail']) + if form.validate_on_submit(): + changed = False + + if request.form.get('submit_services'): + for service in current_app.all_services: + field = form.get_servicedelete(service.id) + if(field.data): + g.user.reset_password(service.id) + changed = True + + elif request.form.get('submit_main'): + if form.mail.data and form.mail.data != g.user.attributes['mail']: + confirm_token = make_confirmation('change_mail', (g.user.uid, form.mail.data)) + confirm_link = url_for('.change_mail', token=confirm_token, _external=True) + + body = render_template('mail/change_mail.txt', username=g.user.uid, + mail=form.mail.data, link=confirm_link) + + current_app.mail_backend.send( + form.mail.data, u'E-Mail-Adresse bestätigen', body, + sender=current_app.config.get('MAIL_CONFIRM_SENDER')) + + flash(u'Es wurde eine E-Mail an die angegebene Adresse geschickt, ' + u'um diese zu überprüfen. Bitte folge den Anweisungen in der ' + u'E-Mail.', 'success') + changed = True + + if form.password.data: + g.user.change_password(form.password.data, form.old_password.data) + session['password'] = encrypt_password(form.password.data) + + flash(u'Passwort geändert', 'success') + changed = True + + for service in current_app.all_services: + field = form.get_servicepassword(service.id) + if field.data: + changed = True + g.user.change_password(field.data, None, service.id) + + if changed: + current_app.user_backend.update(g.user, as_admin=True) #XXX: as_admin wieder wegmachen sobald ACLs richtig gesetzt sind + return redirect(url_for('.settings')) + else: + flash(u'Nichts geändert.') + + + services = deepcopy(current_app.all_services) + for s in services: + s.changed = s.id in g.user.services + + return { + 'form': form, + 'services': services, + } + + +@bp.route('/settings/change_mail/<token>') +@login_required +def change_mail(token): + username, mail = http_verify_confirmation('change_mail', token.encode('ascii'), timeout=3*24*60*60) + + if g.user.uid != username: + raise Forbidden(u'Bitte logge dich als der Benutzer ein, dessen E-Mail-Adresse du ändern willst.') + + results = current_app.user_backend.find_by_mail(mail) + for user in results: + if user.uid != g.user.uid: + raise Forbidden(u'Diese E-Mail-Adresse wird schon von einem anderen account benutzt!') + + g.user.change_email(mail) + current_app.user_backend.update(g.user) + + flash(u'E-Mail-Adresse geändert.', 'success') + return redirect(url_for('.settings')) + + +@bp.route('/logout') +def logout(): + logout_user() + flash(u'Erfolgreich ausgeloggt.', 'success') + return redirect(url_for('.index')) + + +@bp.route('/about') +@templated('about.html') +def about(): + return {} + + +@bp.app_errorhandler(403) +@bp.app_errorhandler(404) +def errorhandler(e): + return render_template('error.html', error=e), e.code |