Mercurial > hg > ltpdarepo
changeset 91:5c1c7f2d6469
Implement user password reset.
Use the same mechanism used for account activation for password reset.
author | Daniele Nicolodi <daniele@grinta.net> |
---|---|
date | Sun, 21 Aug 2011 18:17:27 +0200 |
parents | c55432c9600b |
children | 6e9ba2b64d1f |
files | src/ltpdarepo/templates/mail/reset.txt src/ltpdarepo/templates/users/reset.html src/ltpdarepo/templates/users/view.html src/ltpdarepo/user.py src/ltpdarepo/views/profile.py src/ltpdarepo/views/users.py |
diffstat | 6 files changed, 92 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /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 }}
--- /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 %} +<h2>Reset password for user «{{ user.username }}»</h2> +<p class="discrete">A password reset token will be sent to the user email address.</p> +<form action="" method="post" enctype="multipart/form-data" > + <fieldset> + {% for field in form %} + {{ forms.render_form_field(field) }} + {% endfor %} + <input id="ok" name="ok" type="submit" value="ok"></input> + <input id="cancel" name="cancel" type="submit" value="cancel"></input> + </fieldset> +</form> +{% endblock %}
--- 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 @@ <ul class="actions"> <li><a href="{{ url_for('manage.users.edit', username=username) }}">Edit</a></li> <li><a href="{{ url_for('manage.users.drop', username=username) }}">Drop</a></li> + <li><a href="{{ url_for('manage.users.reset', username=username) }}">Reset password</a></li> </ul> {% endblock %}
--- 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()
--- 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('/<username>/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('/<username>/password', methods=('GET', 'POST')) @require('user') def password(username):
--- 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('/<username>/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: <a href="%s"><tt>%s</tt></a>' % (url, token)) + + return redirect(url_for('manage.users.index')) + return render_template('users/reset.html', form=form, user=user) + + @app.route('/<username>/drop', methods=('GET', 'POST')) @require('admin') def drop(username):