forked from Github-Mirrors/canaille
admin: email debugging form
This commit is contained in:
parent
e415a4739e
commit
d839dd763d
7 changed files with 124 additions and 52 deletions
|
@ -1,20 +1,49 @@
|
||||||
from canaille.apputils import obj_to_b64
|
from canaille.apputils import obj_to_b64
|
||||||
from canaille.flaskutils import permissions_needed
|
from canaille.flaskutils import permissions_needed
|
||||||
from canaille.mails import profile_hash
|
from canaille.mails import profile_hash
|
||||||
|
from canaille.mails import send_invitation_mail
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
from flask import flash
|
||||||
|
from flask import request
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from flask_themer import render_template
|
from flask_themer import render_template
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import StringField
|
||||||
|
from wtforms.validators import DataRequired
|
||||||
|
from wtforms.validators import Email
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint("admin_mails", __name__)
|
bp = Blueprint("admin_mails", __name__)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/")
|
class MailTestForm(FlaskForm):
|
||||||
|
mail = StringField(
|
||||||
|
_("Email"),
|
||||||
|
validators=[
|
||||||
|
DataRequired(),
|
||||||
|
Email(),
|
||||||
|
],
|
||||||
|
render_kw={
|
||||||
|
"placeholder": _("jane@doe.com"),
|
||||||
|
"spellcheck": "false",
|
||||||
|
"autocorrect": "off",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/", methods=["GET", "POST"])
|
||||||
@permissions_needed("manage_oidc")
|
@permissions_needed("manage_oidc")
|
||||||
def mail_index(user):
|
def mail_index(user):
|
||||||
return render_template("admin/mails.html")
|
form = MailTestForm(request.form or None)
|
||||||
|
if request.form and form.validate():
|
||||||
|
if send_invitation_mail(form.mail.data, ""):
|
||||||
|
flash(_("The test invitation mail has been sent correctly"), "success")
|
||||||
|
else:
|
||||||
|
flash(_("The test invitation mail has been sent correctly"), "error")
|
||||||
|
|
||||||
|
return render_template("admin/mails.html", form=form)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/password-init.html")
|
@bp.route("/password-init.html")
|
||||||
|
|
|
@ -1,15 +1,37 @@
|
||||||
{% extends theme('base.html') %}
|
{% extends theme('base.html') %}
|
||||||
|
{% import 'fomanticui.html' as sui %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="ui attached segment">
|
<div class="ui segment">
|
||||||
|
<h2 class="ui center aligned header">
|
||||||
|
<div class="content">
|
||||||
|
{{ _("Test d'envoi") }}
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="ui info message">
|
||||||
|
{% trans -%}
|
||||||
|
This form will a fake invitation email to the address you want.
|
||||||
|
This should be used for testing mail configuration.
|
||||||
|
{%- endtrans %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% call sui.render_form(form) %}
|
||||||
|
{{ sui.render_fields(form) }}
|
||||||
|
<div class="ui right aligned container">
|
||||||
|
<div class="ui stackable buttons">
|
||||||
|
<input type="submit" class="ui primary button" value="{{ _("Send") }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endcall %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui segment">
|
||||||
<h2 class="ui center aligned header">
|
<h2 class="ui center aligned header">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ _("Email preview") }}
|
{{ _("Email preview") }}
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui attached segment">
|
|
||||||
<div class="ui middle aligned divided list">
|
<div class="ui middle aligned divided list">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="right floated content">
|
<div class="right floated content">
|
||||||
|
|
|
@ -9,8 +9,8 @@ indicator_text=none,
|
||||||
suffix_text=none,
|
suffix_text=none,
|
||||||
display=true
|
display=true
|
||||||
) -%}
|
) -%}
|
||||||
|
{% set field_visible = field.type != 'HiddenField' and field.type !='CSRFTokenField' %}
|
||||||
{% if container %}
|
{% if container and field_visible %}
|
||||||
<div class="field {{ kwargs.pop('class_', '') }}
|
<div class="field {{ kwargs.pop('class_', '') }}
|
||||||
{%- if field.errors %} error{% endif -%}
|
{%- if field.errors %} error{% endif -%}
|
||||||
{%- if field.render_kw and "disabled" in field.render_kw %} disabled{% endif -%}"
|
{%- if field.render_kw and "disabled" in field.render_kw %} disabled{% endif -%}"
|
||||||
|
@ -18,7 +18,7 @@ display=true
|
||||||
>
|
>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if (field.type != 'HiddenField' and field.type !='CSRFTokenField') and label_visible %}
|
{% if field_visible and label_visible %}
|
||||||
{{ field.label() }}
|
{{ field.label() }}
|
||||||
{% if field.description %}
|
{% if field.description %}
|
||||||
<div>{{ field.description }}</div>
|
<div>{{ field.description }}</div>
|
||||||
|
@ -30,30 +30,32 @@ display=true
|
||||||
{% set required_indicator = "required" in field.flags %}
|
{% set required_indicator = "required" in field.flags %}
|
||||||
{% set corner_indicator = not noindicator and (indicator_icon or lock_indicator or required_indicator) %}
|
{% set corner_indicator = not noindicator and (indicator_icon or lock_indicator or required_indicator) %}
|
||||||
{% set labeled = suffix_text or corner_indicator %}
|
{% set labeled = suffix_text or corner_indicator %}
|
||||||
<div class="ui
|
{% if field_visible %}
|
||||||
|
<div class="ui
|
||||||
{% if suffix_text %}right{% endif %}
|
{% if suffix_text %}right{% endif %}
|
||||||
{% if corner_indicator %}corner{% endif %}
|
{% if corner_indicator %}corner{% endif %}
|
||||||
{% if labeled %}labeled{% endif %}
|
{% if labeled %}labeled{% endif %}
|
||||||
{% if icon %}left icon {% endif %}
|
{% if icon %}left icon {% endif %}
|
||||||
{% if field.type not in ("BooleanField", "RadioField") %}input{% endif %}
|
{% if field.type not in ("BooleanField", "RadioField") %}input{% endif %}
|
||||||
">
|
">
|
||||||
{% if icon %}<i class="{{ icon }} icon"></i>{% endif %}
|
{% endif %}
|
||||||
|
{% if icon %}<i class="{{ icon }} icon"></i>{% endif %}
|
||||||
|
|
||||||
{% if field.type not in ("SelectField", "SelectMultipleField") %}
|
{% if field.type not in ("SelectField", "SelectMultipleField") %}
|
||||||
{{ field(**kwargs) }}
|
{{ field(**kwargs) }}
|
||||||
{% elif field.render_kw and "readonly" in field.render_kw %}
|
{% elif field.render_kw and "readonly" in field.render_kw %}
|
||||||
{{ field(class_="ui fluid dropdown multiple read-only", **kwargs) }}
|
{{ field(class_="ui fluid dropdown multiple read-only", **kwargs) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ field(class_="ui fluid dropdown multiple", **kwargs) }}
|
{{ field(class_="ui fluid dropdown multiple", **kwargs) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if suffix_text %}
|
{% if suffix_text %}
|
||||||
<div class="ui basic label">
|
<div class="ui basic label">
|
||||||
{{ suffix_text }}{% if corner_indicator %} {% endif %}
|
{{ suffix_text }}{% if corner_indicator %} {% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if not noindicator %}
|
{% if not noindicator %}
|
||||||
{% if indicator_icon %}
|
{% if indicator_icon %}
|
||||||
<div class="ui corner label"{% if indicator_text %} title="{{ indicator_text }}"{% endif %}>
|
<div class="ui corner label"{% if indicator_text %} title="{{ indicator_text }}"{% endif %}>
|
||||||
<i class="{{ indicator_icon }} icon"></i>
|
<i class="{{ indicator_icon }} icon"></i>
|
||||||
|
@ -67,8 +69,10 @@ display=true
|
||||||
<i class="asterisk icon"></i>
|
<i class="asterisk icon"></i>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
{% if field_visible %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if field.errors %}
|
{% if field.errors %}
|
||||||
{% for error in field.errors %}
|
{% for error in field.errors %}
|
||||||
|
@ -77,7 +81,8 @@ display=true
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if container %}
|
|
||||||
|
{% if container and field_visible %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -96,7 +101,7 @@ display=true
|
||||||
|
|
||||||
{% macro render_form(
|
{% macro render_form(
|
||||||
form,
|
form,
|
||||||
action_text='submit',
|
action_text=none,
|
||||||
class_='',
|
class_='',
|
||||||
btn_class='ui right floated primary button',
|
btn_class='ui right floated primary button',
|
||||||
action=none,
|
action=none,
|
||||||
|
@ -108,7 +113,11 @@ id=none) -%}
|
||||||
enctype="multipart/form-data"
|
enctype="multipart/form-data"
|
||||||
class="ui form {{ class_ }}"
|
class="ui form {{ class_ }}"
|
||||||
>
|
>
|
||||||
|
{% if caller %}
|
||||||
|
{{ caller() }}
|
||||||
|
{% else %}
|
||||||
{{ render_fields(form) }}
|
{{ render_fields(form) }}
|
||||||
|
{% endif %}
|
||||||
{% if action_text %}
|
{% if action_text %}
|
||||||
<button type="submit" class="{{ btn_class }}">{{ action_text }}</button>
|
<button type="submit" class="{{ btn_class }}">{{ action_text }}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -76,6 +76,10 @@
|
||||||
<i class="user secret icon"></i>
|
<i class="user secret icon"></i>
|
||||||
{% trans %}Codes{% endtrans %}
|
{% trans %}Codes{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
<a class="item" href="{{ url_for('admin_mails.mail_index') }}">
|
||||||
|
<i class="user mail icon"></i>
|
||||||
|
{% trans %}Emails{% endtrans %}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1107,4 +1107,3 @@ msgstr ""
|
||||||
#: canaille/themes/default/base.html:84
|
#: canaille/themes/default/base.html:84
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,7 @@ def user(app, slapd_connection):
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def admin(app, slapd_connection):
|
def admin(app, slapd_connection):
|
||||||
User.ldap_object_classes(slapd_connection)
|
User.ldap_object_classes(slapd_connection)
|
||||||
|
LDAPObject.ldap_object_attributes(slapd_connection)
|
||||||
u = User(
|
u = User(
|
||||||
objectClass=["inetOrgPerson"],
|
objectClass=["inetOrgPerson"],
|
||||||
cn="Jane Doe",
|
cn="Jane Doe",
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
def test_reset_html(testclient, logged_admin):
|
def test_send_test_email(testclient, logged_admin, smtpd):
|
||||||
testclient.get("/admin/mail/reset.html")
|
assert len(smtpd.messages) == 0
|
||||||
|
|
||||||
|
res = testclient.get("/admin/mail")
|
||||||
|
res.form["mail"] = "test@test.com"
|
||||||
|
res = res.form.submit()
|
||||||
|
|
||||||
|
assert len(smtpd.messages) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_reset_txt(testclient, logged_admin):
|
def test_mails(testclient, logged_admin):
|
||||||
testclient.get("/admin/mail/reset.txt")
|
for base in ["password-init", "reset", "admin/admin@admin.com/invitation"]:
|
||||||
|
testclient.get(f"/admin/mail/{base}.html")
|
||||||
|
testclient.get(f"/admin/mail/{base}.txt")
|
||||||
|
|
Loading…
Reference in a new issue