aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pyaggr3g470r/emails.py35
-rw-r--r--pyaggr3g470r/forms.py22
-rw-r--r--pyaggr3g470r/templates/login.html2
-rw-r--r--pyaggr3g470r/templates/recover.html22
-rw-r--r--pyaggr3g470r/views.py34
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>
+ &nbsp;
+ <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.
#
bgstack15