diff options
Diffstat (limited to 'pyaggr3g470r')
-rw-r--r-- | pyaggr3g470r/emails.py | 35 | ||||
-rw-r--r-- | pyaggr3g470r/forms.py | 22 | ||||
-rw-r--r-- | pyaggr3g470r/templates/login.html | 2 | ||||
-rw-r--r-- | pyaggr3g470r/templates/recover.html | 22 | ||||
-rw-r--r-- | pyaggr3g470r/views.py | 34 |
5 files changed, 108 insertions, 7 deletions
diff --git a/pyaggr3g470r/emails.py b/pyaggr3g470r/emails.py index ae73c0e1..aba0e3e6 100644 --- a/pyaggr3g470r/emails.py +++ b/pyaggr3g470r/emails.py @@ -1,6 +1,24 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- +# pyAggr3g470r - A Web based news aggregator. +# Copyright (C) 2010-2014 Cédric Bonhomme - http://cedricbonhomme.org/ +# +# For more information : https://bitbucket.org/cedricbonhomme/pyaggr3g470r/ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + import logging import smtplib from email.mime.multipart import MIMEMultipart @@ -14,7 +32,6 @@ from decorators import async logger = logging.getLogger(__name__) - @async def send_async_email(mfrom, mto, msg): try: @@ -26,7 +43,6 @@ def send_async_email(mfrom, mto, msg): s.sendmail(mfrom, mto, msg.as_string()) s.quit() - def send_email(mfrom, mto, feed, article): """ Send the article via mail. @@ -62,7 +78,6 @@ def send_email(mfrom, mto, feed, article): s.quit() - # # Notifications # @@ -85,7 +100,6 @@ def send_heroku(user=None, bcc="", subject="", plaintext=""): logger.exception("send_heroku raised:") raise e - def information_message(subject, plaintext): """ Send an information message to the users of the platform. @@ -105,7 +119,6 @@ def information_message(subject, plaintext): else: pass - def new_account_notification(user): """ Account creation notification. @@ -117,7 +130,6 @@ def new_account_notification(user): else: pass - def new_account_activation(user): """ Account activation notification. @@ -129,6 +141,17 @@ def new_account_activation(user): else: pass +def new_password_notification(user, password): + """ + """ + plaintext = """Hello,\n\nA new password has been generated at your request:\n\n%s""" % \ + (password, ) + plaintext += "\n\nIt is advised to replace it as soon as connected to pyAggr3g470r.\n\nSee you," + + if conf.ON_HEROKU: + send_heroku(user=user, subject="[pyAggr3g470r] New password", plaintext=plaintext) + else: + pass def new_article_notification(user, feed, article): if conf.ON_HEROKU: diff --git a/pyaggr3g470r/forms.py b/pyaggr3g470r/forms.py index 5e977071..e35d8b2a 100644 --- a/pyaggr3g470r/forms.py +++ b/pyaggr3g470r/forms.py @@ -116,3 +116,25 @@ class InformationMessageForm(Form): subject = TextField(lazy_gettext("Subject"), [validators.Required(lazy_gettext("Please enter a subject."))]) message = TextAreaField(lazy_gettext("Message"), [validators.Required(lazy_gettext("Please enter a content."))]) submit = SubmitField(lazy_gettext("Send")) + +class RecoverPasswordForm(Form): + email = EmailField("Email", [validators.Length(min=6, max=35), validators.Required(lazy_gettext("Please enter your email address."))]) + submit = SubmitField(lazy_gettext("Save")) + + def __init__(self, *args, **kwargs): + Form.__init__(self, *args, **kwargs) + + def validate(self): + if not Form.validate(self): + return False + + user = User.query.filter(User.email == self.email.data).first() + if user and user.activation_key == "": + return True + elif user and user.activation_key != "": + flash(lazy_gettext('Account not confirmed.'), 'danger') + return False + else: + flash(lazy_gettext('Invalid email.'), 'danger') + #self.email.errors.append("Invalid email") + return False diff --git a/pyaggr3g470r/templates/login.html b/pyaggr3g470r/templates/login.html index 0a3bec2e..e58b5d83 100644 --- a/pyaggr3g470r/templates/login.html +++ b/pyaggr3g470r/templates/login.html @@ -27,5 +27,7 @@ </form> </div> <a href="/signup/" class="btn btn-default">{{ _('Sign up') }}</a> + + <a href="/recover" class="btn btn-default">{{ _('Forgot password') }}</a> </div><!-- /.container --> {% endblock %}
\ No newline at end of file diff --git a/pyaggr3g470r/templates/recover.html b/pyaggr3g470r/templates/recover.html new file mode 100644 index 00000000..8e690bdb --- /dev/null +++ b/pyaggr3g470r/templates/recover.html @@ -0,0 +1,22 @@ +{% extends "layout.html" %} +{% block content %} +<div class="container"> + <div class="jumbotron"> + <h2>{{ _('Recover your account') }}</h2> + + {% for message in form.email.errors %} + <div class="flash">{{ message }}</div> + {% endfor %} + + <form action="{{ url_for('recover') }}" method=post> + {{ form.hidden_tag() }} + + <div class="form-group"> + {{ form.email(class_="form-control", placeholder=_('Your email')) }} + </div> + + {{ form.submit(class_="btn") }} + </form> + </div> +</div><!-- /.container --> +{% endblock %}
\ No newline at end of file diff --git a/pyaggr3g470r/views.py b/pyaggr3g470r/views.py index 178188d6..daf1d84e 100644 --- a/pyaggr3g470r/views.py +++ b/pyaggr3g470r/views.py @@ -46,7 +46,8 @@ import export import emails if not conf.ON_HEROKU: import search as fastsearch -from forms import SignupForm, SigninForm, AddFeedForm, ProfileForm, InformationMessageForm +from forms import SignupForm, SigninForm, AddFeedForm, \ + ProfileForm, InformationMessageForm, RecoverPasswordForm from pyaggr3g470r import app, db, allowed_file, babel from pyaggr3g470r.models import User, Feed, Article, Role from pyaggr3g470r.decorators import feed_access_required @@ -740,6 +741,37 @@ def confirm_account(activation_key=None): 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. + """ + import string + import random + 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: + emails.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. # |