account: ADD mot de passe oublié

This commit is contained in:
Darks 2020-07-21 22:12:18 +02:00
parent 16756f639f
commit 77bcb99ea1
Signed by: Darks
GPG Key ID: F61F10FA138E797C
9 changed files with 170 additions and 9 deletions

View File

@ -137,6 +137,35 @@ class DeleteAccountForm(FlaskForm):
)
class AskResetPasswordForm(FlaskForm):
email = EmailField(
'Adresse email',
validators=[
Optional(),
Email(message="Addresse email invalide."),
],
)
submit = SubmitField('Valider')
class ResetPasswordForm(FlaskForm):
password = PasswordField(
'Mot de passe',
validators=[
Optional(),
vd.password,
],
)
password2 = PasswordField(
'Répéter le mot de passe',
validators=[
Optional(),
EqualTo('password', message="Les mots de passe doivent être identiques."),
],
)
submit = SubmitField('Valider')
class AdminUpdateAccountForm(FlaskForm):
username = StringField(
'Pseudonyme',

View File

@ -1,10 +1,12 @@
from flask import redirect, url_for, request, flash, abort
from flask_login import login_required, current_user, logout_user
from app import app, db
from app.forms.account import UpdateAccountForm, RegistrationForm, DeleteAccountForm
from app.forms.account import UpdateAccountForm, RegistrationForm, \
DeleteAccountForm, AskResetPasswordForm, ResetPasswordForm
from app.models.users import Member
from app.utils.render import render
from app.utils.send_mail import send_validation_mail
from app.utils.send_mail import send_validation_mail, send_reset_password_mail
from app.utils.priv_required import guest_only
import app.utils.ldap as ldap
from itsdangerous import URLSafeTimedSerializer
from config import V5Config
@ -35,6 +37,45 @@ def edit_account():
return render('account/account.html', form=form)
@app.route('/compte/reinitialiser', methods=['GET', 'POST'])
@guest_only
def ask_reset_password():
form = AskResetPasswordForm()
if form.submit.data:
m = Member.query.filter_by(email=form.email.data).first()
if m is not None:
send_reset_password_mail(m.name, m.email)
flash('Un email a été envoyé à l\'adresse renseignée', 'ok')
return redirect(url_for('login'))
elif request.method == "POST":
flash('Une erreur est survenue', 'error')
return render('account/ask_reset_password.html', form=form)
@app.route('/compte/reinitialiser/<token>', methods=['GET', 'POST'])
@guest_only
def reset_password(token):
try:
ts = URLSafeTimedSerializer(app.config["SECRET_KEY"])
email = ts.loads(token, salt="email-confirm-key", max_age=86400)
except Exception as e:
print(f"Error: {e}")
abort(404)
form = ResetPasswordForm()
if form.submit.data:
if form.validate_on_submit():
m = Member.query.filter_by(email=email).first_or_404()
m.set_password(form.password.data)
db.session.merge(m)
db.session.commit()
flash('Modifications effectuées', 'ok')
return redirect(url_for('login'))
else:
flash('Erreur lors de la modification', 'error')
return render('account/reset_password.html', form=form)
@app.route('/compte/supprimer', methods=['GET', 'POST'])
@login_required
@ -54,9 +95,8 @@ def delete_account():
@app.route('/inscription', methods=['GET', 'POST'])
@guest_only
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
if form.validate_on_submit():
member = Member(form.username.data, form.email.data, form.password.data)
@ -77,6 +117,7 @@ def register():
@app.route('/inscription/validation', methods=['GET'])
@guest_only
def validation():
try:
mail = request.args['email']
@ -89,10 +130,8 @@ def validation():
return render('account/validation.html', mail=mail)
@app.route('/inscription/validation/<token>', methods=['GET'])
@guest_only
def activate_account(token):
if current_user.is_authenticated:
return redirect(url_for('index'))
try:
ts = URLSafeTimedSerializer(app.config["SECRET_KEY"])
email = ts.loads(token, salt="email-confirm-key", max_age=86400)

View File

@ -0,0 +1,22 @@
{% extends "base/base.html" %}
{% block content %}
<section class="form" style="width:40%;">
<h1>Réinitialiser le mot de passe</h1>
<p>Vous recevrez un mail contenant un lien pour réintialiser votre mot de passe.</p>
<form action="" method="post">
{{ form.hidden_tag() }}
<div>
{{ form.email.label }}
<div class=desc>{{ form.email.description }}</div>
{{ form.email() }}
{% for error in form.email.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>{{ form.submit(class_="bg-ok") }}</div>
</form>
</section>
{% endblock %}

View File

@ -23,5 +23,6 @@
<p>{{ form.submit(class_="bg-ok") }}</p>
</form>
<p>Pas encore de compte ? <a href="{{ url_for('register') }}">Créé-en un !</a></p>
</form>
<p><a href="{{ url_for('ask_reset_password') }}">Mot de passe oublié ?</a></p>
</section>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends "base/base.html" %}
{% block content %}
<section class="form" style="width:40%;">
<h1>Réinitialiser le mot de passe</h1>
<form action="" method="post">
{{ form.hidden_tag() }}
<div>
{{ form.password.label }}
<div class=desc>{{ form.password.description }}</div>
{{ form.password() }}
{% for error in form.password.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>
{{ form.password2.label }}
<div class=desc>{{ form.password2.description }}</div>
{{ form.password2() }}
{% for error in form.password2.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>{{ form.submit(class_="bg-ok") }}</div>
</form>
</section>
{% endblock %}

View File

@ -55,7 +55,7 @@
{{ login_form.remember_me.label }} {{ login_form.remember_me() }}
</form>
<hr />
<a href="{{ url_for('register') }}">Mot de passe oublié ?</a>
<a href="{{ url_for('register') }}">Inscription</a>
<a href="{{ url_for('ask_reset_password') }}">Mot de passe oublié ?</a>
</div>
{% endif %}

View File

@ -0,0 +1,16 @@
<html>
<body>
<div>Bonjour {{ name }},</div>
<div>Quelqu'un (probablement vous) a demandé a réinitialiser le mot de passe de ce compte.</div>
<div>Cliquez <a href="{{ confirm_url }}">ici</a> pour changer le mot de passe.</div>
<div>Si ça ne fonctionne pas, utilisez ce lien : <a href="{{ confirm_url }}">{{ reset_url }}</a></div>
<div>Si vous n'êtes pas à l'origine de cette opération, vous pouvez ignorer ce message.</div>
<div>À bientôt sur Planète Casio!</div>
<div>L'équipe du site.</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
Bonjour {{ name }}
Quelqu'un (probablement vous) a demandé a réinitialiser le mot de passe de ce compte.
Cliquez sur ce lien pour changer votre mot de passe : {{ reset_url }}
Si vous n'êtes pas à l'origine de cette opération, vous pouvez ignorer ce message.
À bientôt sur Planète Casio!
L'équipe du site.

View File

@ -8,6 +8,21 @@ def send_mail(dest, subject, html="", body=""):
m = Message(recipients=[dest], subject=subject, html=html, body=body)
mail.send(m)
def send_reset_password_mail(name, email):
ts = URLSafeTimedSerializer(app.config["SECRET_KEY"])
token = ts.dumps(email, salt='email-confirm-key')
reset_url = f"https://{V5Config.DOMAIN}" \
+ url_for('reset_password', token=token)
subject = "Confirmez votre email pour compléter l'inscription"
html = render_template('email/reset_password.html', reset_url=reset_url,
name=name)
body = render_template('email/reset_password.md', reset_url=reset_url,
name=name)
if V5Config.SEND_MAILS:
send_mail(member.email, subject, html=html, body=body)
else:
print(f"Reset password url: {reset_url}")
def send_validation_mail(name, email):
ts = URLSafeTimedSerializer(app.config["SECRET_KEY"])
token = ts.dumps(email, salt='email-confirm-key')