mirror of
https://github.com/YunoHost-Apps/ihatemoney_ynh.git
synced 2024-09-03 19:26:15 +02:00
Add a password recovery feature. Fix #32
This commit is contained in:
parent
1338653bd2
commit
75209aeed0
9 changed files with 80 additions and 7 deletions
|
@ -87,6 +87,16 @@ class AuthenticationForm(Form):
|
||||||
submit = SubmitField("Get in")
|
submit = SubmitField("Get in")
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordReminder(Form):
|
||||||
|
id = TextField("Project identifier", validators=[Required()])
|
||||||
|
submit = SubmitField("Send me the code by email")
|
||||||
|
|
||||||
|
def validate_id(form, field):
|
||||||
|
if not Project.query.get(field.data):
|
||||||
|
raise ValidationError("This project does not exists")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BillForm(Form):
|
class BillForm(Form):
|
||||||
date = DateField("Date", validators=[Required()], default=datetime.now)
|
date = DateField("Date", validators=[Required()], default=datetime.now)
|
||||||
what = TextField("What?", validators=[Required()])
|
what = TextField("What?", validators=[Required()])
|
||||||
|
|
|
@ -98,3 +98,9 @@ div.topbar ul.secondary-nav { padding-right: 75px; }
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-top: -15px;
|
margin-top: -15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.password-reminder{
|
||||||
|
float: right;
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Authentication</h2>
|
<h2>Authentication</h2>
|
||||||
|
|
||||||
{% for errors in form.errors.values() %}
|
|
||||||
<p class=error>{{ ", ".join(errors) }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if create_project %}
|
{% if create_project %}
|
||||||
<p class="info">The project you are trying to access do not exist, do you want
|
<p class="info">The project you are trying to access do not exist, do you want
|
||||||
to <a href="{{ url_for(".create_project", project_id=create_project) }}">create it</a>?
|
to <a href="{{ url_for(".create_project", project_id=create_project) }}">create it</a>?
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button type="submit" class="btn primary">{{ field.name }}</button>
|
<button type="submit" class="btn primary">{{ field.name }}</button>
|
||||||
{% if home %}
|
{% if home %}
|
||||||
<a href="{{ url_for(".home") }}">Go back Home</a>
|
<a href="{{ url_for(".remind_password") }}">Can't remember the password?</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if cancel %}
|
{% if cancel %}
|
||||||
<button id="cancel-form" type="reset" class="btn">Cancel</button>
|
<button id="cancel-form" type="reset" class="btn">Cancel</button>
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
{% macro authenticate(form, home=False) %}
|
{% macro authenticate(form, home=False) %}
|
||||||
|
|
||||||
{% include "display_errors.html" %}
|
{% include "display_errors.html" %}
|
||||||
|
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ input(form.id) }}
|
{{ input(form.id) }}
|
||||||
{{ input(form.password) }}
|
{{ input(form.password) }}
|
||||||
|
@ -111,3 +112,12 @@
|
||||||
<button class="btn">Create the archive</button>
|
<button class="btn">Create the archive</button>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro remind_password(form) %}
|
||||||
|
|
||||||
|
{% include "display_errors.html" %}
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ input(form.id) }}
|
||||||
|
{{ submit(form.submit) }}
|
||||||
|
|
||||||
|
{% endmacro %}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<h3>Log to an existing project...</h3>
|
<h3>Log to an existing project...</h3>
|
||||||
{{ forms.authenticate(auth_form, home=True) }}
|
{{ forms.authenticate(auth_form, home=True) }}
|
||||||
<button class="btn">log in</button>
|
<button class="btn">log in</button>
|
||||||
|
<a class="password-reminder" href="{{ url_for(".remind_password") }}">can't remember your password?</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="span8 columns">
|
<div class="span8 columns">
|
||||||
|
|
8
budget/templates/password_reminder
Normal file
8
budget/templates/password_reminder
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Hi,
|
||||||
|
|
||||||
|
You requested to be reminded about your password for "{{ project.name }}".
|
||||||
|
|
||||||
|
You can access it here: {{ config['SITE_URL'] }}{{ url_for(".list_bills", project_id=project.id) }}, the private code is "{{ project.password }}".
|
||||||
|
|
||||||
|
Hope this helps,
|
||||||
|
Some weird guys (with beards)
|
8
budget/templates/password_reminder.html
Normal file
8
budget/templates/password_reminder.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h2>Password reminder</h2>
|
||||||
|
<form method="post">
|
||||||
|
{{ forms.remind_password(form) }}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -96,6 +96,24 @@ class BudgetTestCase(TestCase):
|
||||||
self.assertEqual(len(outbox), 0)
|
self.assertEqual(len(outbox), 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_password_reminder(self):
|
||||||
|
# test that it is possible to have an email cotaining the password of a
|
||||||
|
# project in case people forget it (and it happens!)
|
||||||
|
|
||||||
|
self.create_project("raclette")
|
||||||
|
|
||||||
|
with run.mail.record_messages() as outbox:
|
||||||
|
# a nonexisting project should not send an email
|
||||||
|
self.app.post("/password-reminder", data={"id": "unexisting"})
|
||||||
|
self.assertEqual(len(outbox), 0)
|
||||||
|
|
||||||
|
# a mail should be sent when a project exists
|
||||||
|
self.app.post("/password-reminder", data={"id": "raclette"})
|
||||||
|
self.assertEqual(len(outbox), 1)
|
||||||
|
self.assertIn("raclette", outbox[0].body)
|
||||||
|
self.assertIn("raclette@notmyidea.org", outbox[0].recipients)
|
||||||
|
|
||||||
|
|
||||||
def test_project_creation(self):
|
def test_project_creation(self):
|
||||||
with run.app.test_client() as c:
|
with run.app.test_client() as c:
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ import werkzeug
|
||||||
|
|
||||||
# local modules
|
# local modules
|
||||||
from models import db, Project, Person, Bill
|
from models import db, Project, Person, Bill
|
||||||
from forms import (get_billform_for, ProjectForm, AuthenticationForm, BillForm,
|
from forms import *
|
||||||
MemberForm, InviteForm, CreateArchiveForm, EditProjectForm)
|
|
||||||
from utils import Redirect303
|
from utils import Redirect303
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -149,6 +148,23 @@ def create_project():
|
||||||
|
|
||||||
return render_template("create_project.html", form=form)
|
return render_template("create_project.html", form=form)
|
||||||
|
|
||||||
|
@main.route("/password-reminder", methods=["GET", "POST"])
|
||||||
|
def remind_password():
|
||||||
|
form = PasswordReminder()
|
||||||
|
if request.method == "POST":
|
||||||
|
if form.validate():
|
||||||
|
# get the project
|
||||||
|
project = Project.query.get(form.id.data)
|
||||||
|
|
||||||
|
# send the password reminder
|
||||||
|
mail.send(Message("password recovery",
|
||||||
|
body=render_template("password_reminder", project=project),
|
||||||
|
recipients=[project.contact_email]))
|
||||||
|
flash("a mail has been sent to you with the password")
|
||||||
|
|
||||||
|
return render_template("password_reminder.html", form=form)
|
||||||
|
|
||||||
|
|
||||||
@main.route("/<project_id>/edit", methods=["GET", "POST"])
|
@main.route("/<project_id>/edit", methods=["GET", "POST"])
|
||||||
def edit_project():
|
def edit_project():
|
||||||
form = EditProjectForm()
|
form = EditProjectForm()
|
||||||
|
|
Loading…
Reference in a new issue