# HG changeset patch # User Daniele Nicolodi # Date 1313943447 -7200 # Node ID 5c1c7f2d6469c4016eee8a868e30d2570602e10c # Parent c55432c9600b3d44606667996abb88d627b6de67 Implement user password reset. Use the same mechanism used for account activation for password reset. diff -r c55432c9600b -r 5c1c7f2d6469 src/ltpdarepo/templates/mail/reset.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ltpdarepo/templates/mail/reset.txt Sun Aug 21 18:17:27 2011 +0200 @@ -0,0 +1,8 @@ +Dear {{ user.name or user.username }}, + +your password has ben reset. To choose a new one visit + +{{ url }} + +Regards, +The LTPDA Repository Admin at {{ request.host }} diff -r c55432c9600b -r 5c1c7f2d6469 src/ltpdarepo/templates/users/reset.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ltpdarepo/templates/users/reset.html Sun Aug 21 18:17:27 2011 +0200 @@ -0,0 +1,16 @@ +{% import 'forms.html' as forms %} +{% extends "layout.html" %} +{% block title %}User {{ user.username }}{% endblock%} +{% block body %} +

Reset password for user «{{ user.username }}»

+

A password reset token will be sent to the user email address.

+
+
+ {% for field in form %} + {{ forms.render_form_field(field) }} + {% endfor %} + + +
+
+{% endblock %} diff -r c55432c9600b -r 5c1c7f2d6469 src/ltpdarepo/templates/users/view.html --- a/src/ltpdarepo/templates/users/view.html Sun Aug 21 18:17:27 2011 +0200 +++ b/src/ltpdarepo/templates/users/view.html Sun Aug 21 18:17:27 2011 +0200 @@ -36,5 +36,6 @@ {% endblock %} diff -r c55432c9600b -r 5c1c7f2d6469 src/ltpdarepo/user.py --- a/src/ltpdarepo/user.py Sun Aug 21 18:17:27 2011 +0200 +++ b/src/ltpdarepo/user.py Sun Aug 21 18:17:27 2011 +0200 @@ -111,6 +111,17 @@ g.db.commit() + def reset(self): + curs = g.db.cursor() + + curs.execute("""SELECT Host FROM mysql.user WHERE User=%s""", self.username) + hosts = [row[0] for row in curs.fetchall()] + for host in hosts: + curs.execute("""SET PASSWORD FOR %s@%s = %s""", + (self.username, host, INVALIDPASSWORD)) + + g.db.commit() + def save(self): curs = g.db.cursor() diff -r c55432c9600b -r 5c1c7f2d6469 src/ltpdarepo/views/profile.py --- a/src/ltpdarepo/views/profile.py Sun Aug 21 18:17:27 2011 +0200 +++ b/src/ltpdarepo/views/profile.py Sun Aug 21 18:17:27 2011 +0200 @@ -79,6 +79,29 @@ return render_template('users/activate.html', username=username, form=form) +@app.route('//reset', methods=['GET', 'POST']) +def reset(username): + user = User.load(username) + if user is None: + # not found + abort(404) + + # validate token + _validate_request(request, username) + + form = IPassword() + if request.method == 'POST' and form.validate(): + # set password + user.passwd(form.password.data) + flash('Password set.') + # login if not already logged in + if 'username' not in session: + session['username'] = username + return redirect(url_for('index')) + + return render_template('users/password.html', username=username, form=form) + + @app.route('//password', methods=('GET', 'POST')) @require('user') def password(username): diff -r c55432c9600b -r 5c1c7f2d6469 src/ltpdarepo/views/users.py --- a/src/ltpdarepo/views/users.py Sun Aug 21 18:17:27 2011 +0200 +++ b/src/ltpdarepo/views/users.py Sun Aug 21 18:17:27 2011 +0200 @@ -91,6 +91,39 @@ return render_template('users/create.html', form=form) +@app.route('//reset', methods=['GET', 'POST']) +@require('admin') +def reset(username): + user = User.load(username) + if user is None: + # not found + abort(404) + # use an empty form for CSRF protection + form = Form() + if request.method == 'POST' and form.validate(): + if request.form.get('ok'): + user.reset() + + # generate password reset token + token = Signer().dumps(user.username) + + # activation url + url = url_for('user.reset', username=user.username, token=token, _external=True) + + # send activation token + mailer = Mailer() + message = MIMEText(render_template('mail/reset.txt', user=user, url=url)) + message['Subject'] = 'LTPDA Repository password reset' + message['From'] = mailer.admin_email_addr + message['To'] = user.emailaddr + mailer.send(message) + + flash('Password reset token: %s' % (url, token)) + + return redirect(url_for('manage.users.index')) + return render_template('users/reset.html', form=form, user=user) + + @app.route('//drop', methods=('GET', 'POST')) @require('admin') def drop(username):