HTML password recovery email. Fixes #14

This commit is contained in:
Éloi Rivard 2020-10-29 12:00:19 +01:00
parent 78db589d61
commit 552728a04e
10 changed files with 228 additions and 79 deletions

View file

@ -3,9 +3,10 @@ import os
import toml import toml
import canaille.admin import canaille.admin
import canaille.admin.tokens
import canaille.admin.authorizations import canaille.admin.authorizations
import canaille.admin.clients import canaille.admin.clients
import canaille.admin.mail
import canaille.admin.tokens
import canaille.consents import canaille.consents
import canaille.commands import canaille.commands
import canaille.oauth import canaille.oauth
@ -141,6 +142,7 @@ def setup_app(app):
canaille.admin.authorizations.bp, url_prefix="/admin/authorization" canaille.admin.authorizations.bp, url_prefix="/admin/authorization"
) )
app.register_blueprint(canaille.admin.clients.bp, url_prefix="/admin/client") app.register_blueprint(canaille.admin.clients.bp, url_prefix="/admin/client")
app.register_blueprint(canaille.admin.mail.bp, url_prefix="/admin/mail")
babel = Babel(app) babel = Babel(app)

View file

@ -104,20 +104,32 @@ def forgotten():
recipient = user.mail recipient = user.mail
base_url = current_app.config.get("URL") or request.url_root base_url = current_app.config.get("URL") or request.url_root
url = base_url + url_for( reset_url = base_url + url_for(
"canaille.account.reset", "canaille.account.reset",
uid=user.uid[0], uid=user.uid[0],
hash=profile_hash(user.uid[0], user.userPassword[0]), hash=profile_hash(user.uid[0], user.userPassword[0]),
)[1:] )[1:]
subject = _("Password reset on {website_name}").format( subject = _("Password reset on {website_name}").format(
website_name=current_app.config.get("NAME", url) website_name=current_app.config.get("NAME", reset_url)
)
text_body = render_template(
"mail/reset.txt",
site_name=current_app.config.get("NAME", reset_url),
site_url=current_app.config.get("URL", base_url),
reset_url=reset_url,
)
html_body = render_template(
"mail/reset.html",
site_name=current_app.config.get("NAME", reset_url),
site_url=current_app.config.get("URL", base_url),
reset_url=reset_url,
logo=current_app.config.get("LOGO"),
) )
text_body = _(
"To reset your password on {website_name}, visit the following link :\n{url}"
).format(website_name=current_app.config.get("NAME", url), url=url)
msg = email.message.EmailMessage() msg = email.message.EmailMessage()
msg.set_content(text_body) msg.set_content(text_body)
msg.add_alternative(html_body, subtype="html")
msg["Subject"] = subject msg["Subject"] = subject
msg["From"] = current_app.config["SMTP"]["FROM_ADDR"] msg["From"] = current_app.config["SMTP"]["FROM_ADDR"]
msg["To"] = recipient msg["To"] = recipient

43
canaille/admin/mail.py Normal file
View file

@ -0,0 +1,43 @@
from flask import Blueprint, render_template, current_app, request, url_for
from canaille.flaskutils import admin_needed
from canaille.account import profile_hash
bp = Blueprint(__name__, "clients")
@bp.route("/reset.html")
@admin_needed()
def reset_html(user):
base_url = current_app.config.get("URL") or request.url_root
reset_url = base_url + url_for(
"canaille.account.reset",
uid=user.uid[0],
hash=profile_hash(user.uid[0], user.userPassword[0]),
)[1:]
return render_template(
"mail/reset.html",
site_name=current_app.config.get("NAME", reset_url),
site_url=current_app.config.get("URL", base_url),
reset_url=reset_url,
logo=current_app.config.get("LOGO"),
)
@bp.route("/reset.txt")
@admin_needed()
def reset_txt(user):
base_url = current_app.config.get("URL") or request.url_root
reset_url = base_url + url_for(
"canaille.account.reset",
uid=user.uid[0],
hash=profile_hash(user.uid[0], user.userPassword[0]),
)[1:]
return render_template(
"mail/reset.txt",
site_name=current_app.config.get("NAME", reset_url),
site_url=current_app.config.get("URL", base_url),
reset_url=reset_url,
)

View file

@ -0,0 +1,44 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width"/>
<style type="text/css" style="font-weight: 300">
@import url({{ url_for('static', filename='fonts/lato.css', _external=True) }});
</style>
<!-- <link href="/static/fomanticui/semantic.min.css" rel="stylesheet">
<style>
body {
background: #F8F8F8;
padding: 1em;
margin: auto;
max-width: 800px;
font-family: 'Lato', sans-serif;
font-weight: 400;
}
</style>-->
</head>
<body style="box-sizing: inherit; height: 100%; overflow-x: hidden; min-width: 320px; font-size: 14px; line-height: 1.4285em; color: rgba(0,0,0,.87); background: #F8F8F8; padding: 1em; margin: auto; max-width: 800px; font-family: 'Lato', sans-serif; font-weight: 400;">
<div class="ui segment" style="line-height: 1.4285em; color: rgba(0,0,0,.87); font-family: 'Lato', sans-serif; font-weight: 400; box-sizing: inherit; position: relative; background: #fff; box-shadow: 0 1px 2px 0 rgba(34,36,38,.15); margin: 1rem 0; padding: 1em 1em; border-radius: .28571429rem; border: 1px solid rgba(34,36,38,.15); font-size: 1rem; margin-top: 0; margin-bottom: 0;">
<h3 class="ui top attached header" style="box-sizing: inherit; font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; font-weight: 700; line-height: 1.28571429em; text-transform: none; color: rgba(0,0,0,.87); font-size: 1.28571429rem; background: #fff; padding: .78571429rem 1rem; margin: 0 -1px 0 -1px; box-shadow: none; border: 1px solid #d4d4d5; border-radius: .28571429rem .28571429rem 0 0;">
{% if logo %}
<img class="ui image" src="{{ logo }}" alt="{{ site_name }}" style="font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; font-weight: 700; line-height: 1.28571429em; text-transform: none; color: rgba(0,0,0,.87); font-size: 1.28571429rem; box-sizing: inherit; border-style: none; position: relative; max-width: 50px; max-height:50px; background-color: transparent; display: inline-block; margin-top: .14285714em; width: 2.5em; height: auto; vertical-align: middle;">
{% endif %}
<div class="content" style="font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; font-weight: 700; line-height: 1.28571429em; text-transform: none; color: rgba(0,0,0,.87); font-size: 1.28571429rem; box-sizing: inherit; display: inline-block; padding-left: .75rem; vertical-align: middle;">
{% trans %}Password reinitialisation{% endtrans %}
</div>
</h3>
<div class="ui attached message" style="font-family: 'Lato', sans-serif; font-weight: 400; box-sizing: inherit; position: relative; min-height: 1em; background: #f8f8f9; padding: 1em 1.5em; line-height: 1.4285em; color: rgba(0,0,0,.87); transition: opacity .1s ease,color .1s ease,background .1s ease,box-shadow .1s ease,-webkit-box-shadow .1s ease; font-size: 1em; margin-bottom: -1px; box-shadow: 0 0 0 1px rgba(34,36,38,.15) inset; margin-left: -1px; margin-right: -1px; margin-top: -1px; border-radius: 0;">
{% trans %}
Someone, probably you, asked for a password reinitialization link at {{ site_name }}. If you did not asked for this email, please ignore it. I you need to reset your password, please click on the blue button below and follow the instructions.
{% endtrans %}
</div>
<div class="ui attached stackable buttons" style="line-height: 1.4285em; color: rgba(0,0,0,.87); font-family: 'Lato', sans-serif; font-weight: 400; box-sizing: inherit; -webkit-box-orient: horizontal; -webkit-box-direction: normal; flex-direction: row; font-size: 0; vertical-align: baseline; margin: 0 .25em 0 0; position: relative; display: flex; border-radius: 0; width: auto!important; z-index: auto; margin-left: -1px; margin-right: -1px; box-shadow: none;">
<a class="ui button" href="{{ site_url }}" style="-webkit-box-direction: normal; box-sizing: inherit; cursor: pointer; display: inline-block; min-height: 1em; outline: 0; border: none; vertical-align: baseline; background: #e0e1e2 none; color: rgba(0,0,0,.6); font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; padding: .78571429em 1.5em .78571429em; text-transform: none; text-shadow: none; font-weight: 700; line-height: 1em; font-style: normal; text-align: center; text-decoration: none; user-select: none; transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease; will-change: auto; -webkit-tap-highlight-color: transparent; font-size: 1rem; -webkit-box-flex: 1; flex: 1 0 auto; margin: 0; border-left: none; margin-left: 0; border-radius: 0; box-shadow: 0 0 0 1px transparent inset,0 0 0 0 rgba(34,36,38,.15) inset;">{{ site_name }}</a>
<a class="ui primary button" href="{{ reset_url }}" style="-webkit-box-direction: normal; box-sizing: inherit; cursor: pointer; display: inline-block; min-height: 1em; outline: 0; border: none; vertical-align: baseline; background: #e0e1e2 none; font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; padding: .78571429em 1.5em .78571429em; text-transform: none; font-weight: 700; line-height: 1em; font-style: normal; text-align: center; text-decoration: none; user-select: none; transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease; will-change: auto; -webkit-tap-highlight-color: transparent; font-size: 1rem; background-color: #2185d0; color: #fff; text-shadow: none; background-image: none; -webkit-box-flex: 1; flex: 1 0 auto; margin: 0; border-radius: 0; box-shadow: 0 0 0 1px transparent inset,0 0 0 0 rgba(34,36,38,.15) inset;">{% trans %}Reset password{% endtrans %}</a>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,6 @@
# {% trans %}Password reinitialisation{% endtrans %}
{% trans %}Someone, probably you, asked for a password reinitialization link at {{ site_name }}. If you did not asked for this email, please ignore it. I you need to reset your password, please click on the link below and follow the instructions.{% endtrans %}
{% trans %}Reset password{% endtrans %}: {{ reset_url }}
{{ site_name }}: {{ site_url }}

View file

@ -1,3 +1,4 @@
[python: **.py] [python: **.py]
[jinja2: **/templates/**.html] [jinja2: **/templates/**.html]
[jinja2: **/templates/**.txt]
extensions=jinja2.ext.autoescape,jinja2.ext.with_ extensions=jinja2.ext.autoescape,jinja2.ext.with_

View file

@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: contact@yaal.fr\n" "Report-Msgid-Bugs-To: contact@yaal.fr\n"
"POT-Creation-Date: 2020-10-29 08:31+0100\n" "POT-Creation-Date: 2020-10-29 11:50+0100\n"
"PO-Revision-Date: 2020-10-29 08:32+0100\n" "PO-Revision-Date: 2020-10-29 11:50+0100\n"
"Last-Translator: Éloi Rivard <eloi@yaal.fr>\n" "Last-Translator: Éloi Rivard <eloi@yaal.fr>\n"
"Language: fr_FR\n" "Language: fr_FR\n"
"Language-Team: French - France <equipe@yaal.fr>\n" "Language-Team: French - France <equipe@yaal.fr>\n"
@ -36,7 +36,7 @@ msgstr "Le profil a été mis à jour avec succès."
msgid "Could not send the password reset link." msgid "Could not send the password reset link."
msgstr "Impossible d'envoyer le lien de réinitialisation." msgstr "Impossible d'envoyer le lien de réinitialisation."
#: canaille/account.py:101 canaille/account.py:149 #: canaille/account.py:101 canaille/account.py:161
msgid "A password reset link has been sent at your email address." msgid "A password reset link has been sent at your email address."
msgstr "Un lien de réinitialisation vous a été envoyé à votre adresse." msgstr "Un lien de réinitialisation vous a été envoyé à votre adresse."
@ -44,31 +44,23 @@ msgstr "Un lien de réinitialisation vous a été envoyé à votre adresse."
msgid "Password reset on {website_name}" msgid "Password reset on {website_name}"
msgstr "Réinitialisation du mot de passe sur {website_name}" msgstr "Réinitialisation du mot de passe sur {website_name}"
#: canaille/account.py:115 #: canaille/account.py:156
msgid ""
"To reset your password on {website_name}, visit the following link :\n"
"{url}"
msgstr ""
"Pour réinitialiser votre mot de passe sur {website_name}, veuillez vous "
"rendre sur le lien suivant : {url}"
#: canaille/account.py:144
msgid "Could not reset your password" msgid "Could not reset your password"
msgstr "Impossible de réinitialiser votre mot de passe" msgstr "Impossible de réinitialiser votre mot de passe"
#: canaille/account.py:162 #: canaille/account.py:174
msgid "The password reset link that brought you here was invalid." msgid "The password reset link that brought you here was invalid."
msgstr "Le lien de réinitialisation qui vous a amené ici est invalide." msgstr "Le lien de réinitialisation qui vous a amené ici est invalide."
#: canaille/account.py:171 #: canaille/account.py:183
msgid "Your password has been updated successfuly" msgid "Your password has been updated successfuly"
msgstr "Votre mot de passe a correctement été mis à jour." msgstr "Votre mot de passe a correctement été mis à jour."
#: canaille/consents.py:28 canaille/tokens.py:29 #: canaille/consents.py:28
msgid "Could not delete this access" msgid "Could not delete this access"
msgstr "Impossible de supprimer cet accès." msgstr "Impossible de supprimer cet accès."
#: canaille/consents.py:32 canaille/tokens.py:34 #: canaille/consents.py:32
msgid "The access has been revoked" msgid "The access has been revoked"
msgstr "L'accès a été révoqué." msgstr "L'accès a été révoqué."
@ -238,37 +230,31 @@ msgstr "Mon profil"
msgid "My consents" msgid "My consents"
msgstr "Mes autorisations" msgstr "Mes autorisations"
#: canaille/templates/base.html:47 canaille/templates/token_list.html:18 #: canaille/templates/base.html:51
msgid "My tokens"
msgstr "Mes jetons"
#: canaille/templates/base.html:56
msgid "Clients" msgid "Clients"
msgstr "Clients" msgstr "Clients"
#: canaille/templates/base.html:60 #: canaille/templates/base.html:55
msgid "Tokens" msgid "Tokens"
msgstr "Jetons" msgstr "Jetons"
#: canaille/templates/base.html:64 #: canaille/templates/base.html:59
msgid "Codes" msgid "Codes"
msgstr "Codes" msgstr "Codes"
#: canaille/templates/base.html:68 #: canaille/templates/base.html:63
msgid "Consents" msgid "Consents"
msgstr "Autorisations" msgstr "Autorisations"
#: canaille/templates/base.html:75 #: canaille/templates/base.html:70
msgid "Log out" msgid "Log out"
msgstr "Déconnexion" msgstr "Déconnexion"
#: canaille/templates/consent_list.html:21 #: canaille/templates/consent_list.html:21
#: canaille/templates/token_list.html:21
msgid "Consult and revoke the authorization you gave to websites." msgid "Consult and revoke the authorization you gave to websites."
msgstr "Consultez et révoquez les autorisation que vous avez données." msgstr "Consultez et révoquez les autorisation que vous avez données."
#: canaille/templates/consent_list.html:47 #: canaille/templates/consent_list.html:47
#: canaille/templates/token_list.html:47
msgid "From:" msgid "From:"
msgstr "À partir de :" msgstr "À partir de :"
@ -277,7 +263,6 @@ msgid "Revoked:"
msgstr "Révoqué le :" msgstr "Révoqué le :"
#: canaille/templates/consent_list.html:52 #: canaille/templates/consent_list.html:52
#: canaille/templates/token_list.html:51
msgid "Has access to:" msgid "Has access to:"
msgstr "A accès à :" msgstr "A accès à :"
@ -286,12 +271,10 @@ msgid "Remove access"
msgstr "Supprimer l'accès" msgstr "Supprimer l'accès"
#: canaille/templates/consent_list.html:72 #: canaille/templates/consent_list.html:72
#: canaille/templates/token_list.html:71
msgid "Nothing here" msgid "Nothing here"
msgstr "Rien ici" msgstr "Rien ici"
#: canaille/templates/consent_list.html:73 #: canaille/templates/consent_list.html:73
#: canaille/templates/token_list.html:72
msgid "You did not authorize applications yet." msgid "You did not authorize applications yet."
msgstr "" msgstr ""
"Vous n'avez pas encore autorisé d'application à accéder à votre profil." "Vous n'avez pas encore autorisé d'application à accéder à votre profil."
@ -368,14 +351,6 @@ msgstr "Éditer"
msgid "Password reset" msgid "Password reset"
msgstr "Réinitialisation du mot de passe" msgstr "Réinitialisation du mot de passe"
#: canaille/templates/token_list.html:48
msgid "Until:"
msgstr "Jusqu'à :"
#: canaille/templates/token_list.html:61
msgid "Remove token"
msgstr "Supprimer le jeton"
#: canaille/templates/admin/authorization_list.html:18 #: canaille/templates/admin/authorization_list.html:18
#: canaille/templates/admin/token_list.html:18 #: canaille/templates/admin/token_list.html:18
msgid "Token" msgid "Token"
@ -438,6 +413,46 @@ msgstr "URL"
msgid "View a token" msgid "View a token"
msgstr "Voir un jeton" msgstr "Voir un jeton"
#: canaille/templates/mail/reset.html:28 canaille/templates/mail/reset.txt:1
msgid "Password reinitialisation"
msgstr "Réinitialisation du mot de passe"
#: canaille/templates/mail/reset.html:33
#, python-format
msgid ""
"\n"
" Someone, probably you, asked for a password reinitialization "
"link at %(site_name)s. If you did not asked for this email, please ignore "
"it. I you need to reset your password, please click on the blue button below "
"and follow the instructions.\n"
" "
msgstr ""
"\n"
" Quelqu'un, probablement vous, a demandé un lien de "
"réinitialisation de votre mot de passe pour le site %(site_name)s. Si vous "
"n'êtes pas à l'origine de ce message, veuillez l'ignorer. Si vous voulez "
"réinitialiser votre mot de passe, veuillez cliquer sur le bouton bleu ci-"
"dessous, et suivre les instructions qui vous seront soumises.\n"
" "
#: canaille/templates/mail/reset.html:40 canaille/templates/mail/reset.txt:5
msgid "Reset password"
msgstr "Réinitialiser votre mot de passe"
#: canaille/templates/mail/reset.txt:3
#, python-format
msgid ""
"Someone, probably you, asked for a password reinitialization link at "
"%(site_name)s. If you did not asked for this email, please ignore it. I you "
"need to reset your password, please click on the link below and follow the "
"instructions."
msgstr ""
"Quelqu'un, probablement vous, a demandé un lien de réinitialisation de votre "
"mot de passe pour le site %(site_name)s. Si vous n'êtes pas à l'origine de "
"ce message, veuillez l'ignorer. Si vous voulez réinitialiser votre mot de "
"passe, veuillez cliquer sur le lien ci-dessous, et suivre les instructions "
"qui vous seront soumises."
#~ msgid "Logged in as" #~ msgid "Logged in as"
#~ msgstr "Connecté en tant que" #~ msgstr "Connecté en tant que"
@ -449,3 +464,19 @@ msgstr "Voir un jeton"
#~ msgid "OpenID Connect LDAP Bridge" #~ msgid "OpenID Connect LDAP Bridge"
#~ msgstr "OpendID Connect LDAP Bridge" #~ msgstr "OpendID Connect LDAP Bridge"
#~ msgid ""
#~ "To reset your password on {website_name}, visit the following link :\n"
#~ "{url}"
#~ msgstr ""
#~ "Pour réinitialiser votre mot de passe sur {website_name}, veuillez vous "
#~ "rendre sur le lien suivant : {url}"
#~ msgid "My tokens"
#~ msgstr "Mes jetons"
#~ msgid "Until:"
#~ msgstr "Jusqu'à :"
#~ msgid "Remove token"
#~ msgstr "Supprimer le jeton"

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-10-29 08:31+0100\n" "POT-Creation-Date: 2020-10-29 11:50+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -33,7 +33,7 @@ msgstr ""
msgid "Could not send the password reset link." msgid "Could not send the password reset link."
msgstr "" msgstr ""
#: canaille/account.py:101 canaille/account.py:149 #: canaille/account.py:101 canaille/account.py:161
msgid "A password reset link has been sent at your email address." msgid "A password reset link has been sent at your email address."
msgstr "" msgstr ""
@ -41,29 +41,23 @@ msgstr ""
msgid "Password reset on {website_name}" msgid "Password reset on {website_name}"
msgstr "" msgstr ""
#: canaille/account.py:115 #: canaille/account.py:156
msgid ""
"To reset your password on {website_name}, visit the following link :\n"
"{url}"
msgstr ""
#: canaille/account.py:144
msgid "Could not reset your password" msgid "Could not reset your password"
msgstr "" msgstr ""
#: canaille/account.py:162 #: canaille/account.py:174
msgid "The password reset link that brought you here was invalid." msgid "The password reset link that brought you here was invalid."
msgstr "" msgstr ""
#: canaille/account.py:171 #: canaille/account.py:183
msgid "Your password has been updated successfuly" msgid "Your password has been updated successfuly"
msgstr "" msgstr ""
#: canaille/consents.py:28 canaille/tokens.py:29 #: canaille/consents.py:28
msgid "Could not delete this access" msgid "Could not delete this access"
msgstr "" msgstr ""
#: canaille/consents.py:32 canaille/tokens.py:34 #: canaille/consents.py:32
msgid "The access has been revoked" msgid "The access has been revoked"
msgstr "" msgstr ""
@ -233,37 +227,31 @@ msgstr ""
msgid "My consents" msgid "My consents"
msgstr "" msgstr ""
#: canaille/templates/base.html:47 canaille/templates/token_list.html:18 #: canaille/templates/base.html:51
msgid "My tokens"
msgstr ""
#: canaille/templates/base.html:56
msgid "Clients" msgid "Clients"
msgstr "" msgstr ""
#: canaille/templates/base.html:60 #: canaille/templates/base.html:55
msgid "Tokens" msgid "Tokens"
msgstr "" msgstr ""
#: canaille/templates/base.html:64 #: canaille/templates/base.html:59
msgid "Codes" msgid "Codes"
msgstr "" msgstr ""
#: canaille/templates/base.html:68 #: canaille/templates/base.html:63
msgid "Consents" msgid "Consents"
msgstr "" msgstr ""
#: canaille/templates/base.html:75 #: canaille/templates/base.html:70
msgid "Log out" msgid "Log out"
msgstr "" msgstr ""
#: canaille/templates/consent_list.html:21 #: canaille/templates/consent_list.html:21
#: canaille/templates/token_list.html:21
msgid "Consult and revoke the authorization you gave to websites." msgid "Consult and revoke the authorization you gave to websites."
msgstr "" msgstr ""
#: canaille/templates/consent_list.html:47 #: canaille/templates/consent_list.html:47
#: canaille/templates/token_list.html:47
msgid "From:" msgid "From:"
msgstr "" msgstr ""
@ -272,7 +260,6 @@ msgid "Revoked:"
msgstr "" msgstr ""
#: canaille/templates/consent_list.html:52 #: canaille/templates/consent_list.html:52
#: canaille/templates/token_list.html:51
msgid "Has access to:" msgid "Has access to:"
msgstr "" msgstr ""
@ -281,12 +268,10 @@ msgid "Remove access"
msgstr "" msgstr ""
#: canaille/templates/consent_list.html:72 #: canaille/templates/consent_list.html:72
#: canaille/templates/token_list.html:71
msgid "Nothing here" msgid "Nothing here"
msgstr "" msgstr ""
#: canaille/templates/consent_list.html:73 #: canaille/templates/consent_list.html:73
#: canaille/templates/token_list.html:72
msgid "You did not authorize applications yet." msgid "You did not authorize applications yet."
msgstr "" msgstr ""
@ -356,14 +341,6 @@ msgstr ""
msgid "Password reset" msgid "Password reset"
msgstr "" msgstr ""
#: canaille/templates/token_list.html:48
msgid "Until:"
msgstr ""
#: canaille/templates/token_list.html:61
msgid "Remove token"
msgstr ""
#: canaille/templates/admin/authorization_list.html:18 #: canaille/templates/admin/authorization_list.html:18
#: canaille/templates/admin/token_list.html:18 #: canaille/templates/admin/token_list.html:18
msgid "Token" msgid "Token"
@ -426,3 +403,31 @@ msgstr ""
msgid "View a token" msgid "View a token"
msgstr "" msgstr ""
#: canaille/templates/mail/reset.html:28 canaille/templates/mail/reset.txt:1
msgid "Password reinitialisation"
msgstr ""
#: canaille/templates/mail/reset.html:33
#, python-format
msgid ""
"\n"
" Someone, probably you, asked for a password "
"reinitialization link at %(site_name)s. If you did not asked for this "
"email, please ignore it. I you need to reset your password, please click "
"on the blue button below and follow the instructions.\n"
" "
msgstr ""
#: canaille/templates/mail/reset.html:40 canaille/templates/mail/reset.txt:5
msgid "Reset password"
msgstr ""
#: canaille/templates/mail/reset.txt:3
#, python-format
msgid ""
"Someone, probably you, asked for a password reinitialization link at "
"%(site_name)s. If you did not asked for this email, please ignore it. I "
"you need to reset your password, please click on the link below and "
"follow the instructions."
msgstr ""

5
tests/test_mail_admin.py Normal file
View file

@ -0,0 +1,5 @@
def test_reset_html(testclient, logged_admin):
testclient.get("/admin/mail/reset.html")
def test_reset_txt(testclient, logged_admin):
testclient.get("/admin/mail/reset.txt")