Enable jinja2 strict mode in unit tests

This commit is contained in:
Éloi Rivard 2023-07-01 19:56:13 +02:00
parent f7007544ec
commit 1a0a8096eb
8 changed files with 75 additions and 120 deletions

View file

@ -55,6 +55,9 @@ def test_html(user):
site_name=current_app.config.get("NAME", "Canaille"),
site_url=base_url,
logo=current_app.config.get("LOGO"),
title=_("Test email from {website_name}").format(
website_name=current_app.config.get("NAME", "Canaille"),
),
)
@ -77,6 +80,9 @@ def password_init_html(user):
"account.reset",
user=user,
hash=profile_hash(user.identifier, user.preferred_email, user.password[0]),
title=_("Password initialization on {website_name}").format(
website_name=current_app.config.get("NAME", "Canaille")
),
_external=True,
)
@ -87,7 +93,7 @@ def password_init_html(user):
reset_url=reset_url,
logo=current_app.config.get("LOGO"),
title=_("Password initialization on {website_name}").format(
website_name=current_app.config.get("NAME", reset_url)
website_name=current_app.config.get("NAME", "Canaille")
),
)
@ -105,7 +111,7 @@ def password_init_txt(user):
return render_template(
"mail/firstlogin.txt",
site_name=current_app.config.get("NAME", reset_url),
site_name=current_app.config.get("NAME", "Canaille"),
site_url=current_app.config.get("SERVER_NAME", base_url),
reset_url=reset_url,
)
@ -119,6 +125,9 @@ def password_reset_html(user):
"account.reset",
user=user,
hash=profile_hash(user.identifier, user.preferred_email, user.password[0]),
title=_("Password reset on {website_name}").format(
website_name=current_app.config.get("NAME", "")
),
_external=True,
)
@ -129,7 +138,7 @@ def password_reset_html(user):
reset_url=reset_url,
logo=current_app.config.get("LOGO"),
title=_("Password reset on {website_name}").format(
website_name=current_app.config.get("NAME", reset_url)
website_name=current_app.config.get("NAME", base_url)
),
)

View file

@ -24,6 +24,7 @@ def send_test_mail(email):
site_name=current_app.config.get("NAME", "Canaille"),
site_url=base_url,
logo=f"cid:{logo_cid[1:-1]}" if logo_cid else None,
title=subject,
)
return send_email(
@ -50,20 +51,21 @@ def send_password_reset_mail(user, mail):
logo_cid, logo_filename, logo_raw = logo()
subject = _("Password reset on {website_name}").format(
website_name=current_app.config.get("NAME", reset_url)
website_name=current_app.config.get("NAME", base_url)
)
text_body = render_template(
"mail/reset.txt",
site_name=current_app.config.get("NAME", reset_url),
site_name=current_app.config.get("NAME", base_url),
site_url=base_url,
reset_url=reset_url,
)
html_body = render_template(
"mail/reset.html",
site_name=current_app.config.get("NAME", reset_url),
site_name=current_app.config.get("NAME", base_url),
site_url=base_url,
reset_url=reset_url,
logo=f"cid:{logo_cid[1:-1]}" if logo_cid else None,
title=subject,
)
return send_email(
@ -90,20 +92,21 @@ def send_password_initialization_mail(user, email):
logo_cid, logo_filename, logo_raw = logo()
subject = _("Password initialization on {website_name}").format(
website_name=current_app.config.get("NAME", reset_url)
website_name=current_app.config.get("NAME", base_url)
)
text_body = render_template(
"mail/firstlogin.txt",
site_name=current_app.config.get("NAME", reset_url),
site_name=current_app.config.get("NAME", base_url),
site_url=base_url,
reset_url=reset_url,
)
html_body = render_template(
"mail/firstlogin.html",
site_name=current_app.config.get("NAME", reset_url),
site_name=current_app.config.get("NAME", base_url),
site_url=base_url,
reset_url=reset_url,
logo=f"cid:{logo_cid[1:-1]}" if logo_cid else None,
title=subject,
)
return send_email(
@ -120,20 +123,21 @@ def send_invitation_mail(email, registration_url):
logo_cid, logo_filename, logo_raw = logo()
subject = _("You have been invited to create an account on {website_name}").format(
website_name=current_app.config.get("NAME", registration_url)
website_name=current_app.config.get("NAME", base_url)
)
text_body = render_template(
"mail/invitation.txt",
site_name=current_app.config.get("NAME", registration_url),
site_name=current_app.config.get("NAME", base_url),
site_url=base_url,
registration_url=registration_url,
)
html_body = render_template(
"mail/invitation.html",
site_name=current_app.config.get("NAME", registration_url),
site_name=current_app.config.get("NAME", base_url),
site_url=base_url,
registration_url=registration_url,
logo=f"cid:{logo_cid[1:-1]}" if logo_cid else None,
title=subject,
)
return send_email(

View file

@ -2,7 +2,7 @@
{% block content %}
<div class="ui error icon message">
{% if icon and (debug or (user and user.can_manage_oidc)) %}
{% if icon is defined and (debug or (user and user.can_manage_oidc)) %}
<i class="{{ icon }} icon"></i>
{% elif error_code == 400 %}
<i class="question icon"></i>

View file

@ -183,12 +183,12 @@ id=none,
csrf=true) -%}
<form method="POST"
id="{{ id or form.__class__.__name__|lower }}"
action="{{ action or form.action }}"
action="{% if action %}{{ action }}{% elif form.action is defined %}{{ form.action }}{% endif %}"
role="form"
enctype="multipart/form-data"
class="ui form {{ class_ }}"
>
{% if caller %}
{% if caller is defined %}
{% if csrf %}
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
{% endif %}

View file

@ -40,7 +40,7 @@
{{ form.hidden_tag() if form.hidden_tag }}
<input type="hidden" name="page" value="{{ page }}">
<input type="hidden" name="query" value="{{ form.query.data }}">
{% if page == null %}
{% if page is none %}
<span class="icon disabled ui button" style="border-radius: 0">
{{ caller() }}
</span>
@ -69,7 +69,7 @@
<i class="left chevron icon"></i>
{% endcall %}
{% else %}
{% call buttonform(form, "previous", null) %}
{% call buttonform(form, "previous", none) %}
<i class="left chevron icon"></i>
{% endcall %}
{% endif %}
@ -79,7 +79,7 @@
{% endcall %}
{% endif %}
{% if form.page.data > 2 %}
{% call buttonform(form, "ellipsis-previous", null) %}
{% call buttonform(form, "ellipsis-previous", none) %}
{% endcall %}
{% endif %}
@ -87,7 +87,7 @@
{{ form.page.data }}
</span>
{% if form.page.data < form.page_max - 1 %}
{% call buttonform(form, "ellipsis-next", null) %}
{% call buttonform(form, "ellipsis-next", none) %}
{% endcall %}
{% endif %}
@ -101,7 +101,7 @@
<i class="right chevron icon"></i>
{% endcall %}
{% else %}
{% call buttonform(form, "next", null) %}
{% call buttonform(form, "next", none) %}
<i class="right chevron icon"></i>
{% endcall %}
{% endif %}

View file

@ -1,5 +1,6 @@
{% extends theme('base.html') %}
{% import 'macro/form.html' as fui %}
{% import 'partial/profile_field.html' as profile %}
{%- block title -%}
{%- trans %}User creation{% endtrans -%}
@ -28,64 +29,14 @@
</nav>
{% endblock %}
{% macro render_field(field, noindicator=false) %}
{% set lock_indicator = field.render_kw and ("readonly" in field.render_kw or "disabled" in field.render_kw) %}
{% if not edited_user %}
{{ fui.render_field(field, **kwargs) }}
{% elif edited_user.user_name == user.user_name or lock_indicator or noindicator %}
{{ fui.render_field(field, **kwargs) }}
{% elif field.name in edited_user.write %}
{{ fui.render_field(field, **kwargs) }}
{% elif field.name in edited_user.read %}
{{ fui.render_field(field, indicator_icon="eye", indicator_text=_("This user cannot edit this field"), **kwargs) }}
{% else %}
{{ fui.render_field(field, indicator_icon="eye slash", indicator_text=_("This user cannot see this field"), **kwargs) }}
{% endif %}
{% endmacro %}
{% block content %}
{% if self_deletion or (user.can_manage_users and edited_user) %}
<div id="modal-delete" class="ui basic modal">
<div class="ui icon header">
<i class="user minus icon"></i>
{% trans %}Account deletion{% endtrans %}
</div>
<div class="content">
<p>
{% if user.user_name != edited_user.user_name %}
{{ _("Are you sure you want to delete this user? This action is unrevokable and all the data about this user will be removed.") }}
{% else %}
{{ _("Are you sure you want to delete your account? This action is unrevokable and all your data will be removed forever.") }}
{% endif %}
</p>
</div>
<div class="actions">
<div class="ui inverted cancel button">{% trans %}Cancel{% endtrans %}</div>
<div class="ui inverted red approve button">{% trans %}Delete{% endtrans %}</div>
</div>
</div>
{% endif %}
<div class="ui clearing segment">
<h2 class="ui center aligned header">
<div class="content">
{% if not edited_user %}
{% trans %}User creation{% endtrans %}
{% elif user.user_name == edited_user.user_name %}
{% trans %}My profile{% endtrans %}
{% else %}
{% trans %}User profile edition{% endtrans %}
{% endif %}
</div>
<div class="sub header">
{% if not edited_user %}
{% trans %}Create a new user account{% endtrans %}
{% elif user.user_name == edited_user.user_name %}
{% trans %}Edit your personal information{% endtrans %}
{% else %}
{% trans %}Edit information about a user{% endtrans %}
{% endif %}
</div>
</h2>
@ -96,9 +47,8 @@
<div class="ui grid">
<div class="three wide column">
{% block photo_field scoped %}
{{ render_field(form.photo, display=false, class="photo-field") }}
{{ render_field(form.photo_delete, display=false, class="photo-delete-button") }}
{% set photo = edited_user.photo and edited_user.photo[0] %}
{{ profile.render_field(form.photo, display=false, class="photo-field") }}
{{ profile.render_field(form.photo_delete, display=false, class="photo-delete-button") }}
<label
class="ui small bordered image photo-content"
for="{{ form.photo.id }}"
@ -113,8 +63,7 @@
<label
class="ui centered photo-placeholder"
for="{{ form.photo.id }}"
title="{{ _("Click to upload a photo") }}"
{% if photo %}style="display: none;"{% endif %}>
title="{{ _("Click to upload a photo") }}">
<i class="massive centered portrait icon"></i>
</label>
{% endblock %}
@ -126,116 +75,107 @@
{% if "given_name" in form or "family_name" in form %}
<div class="equal width fields">
{% if "given_name" in form %}
{% block given_name_field scoped %}{{ render_field(form.given_name) }}{% endblock %}
{% block given_name_field scoped %}{{ profile.render_field(form.given_name) }}{% endblock %}
{% endif %}
{% if "family_name" in form %}
{% block family_name_field scoped %}{{ render_field(form.family_name) }}{% endblock %}
{% block family_name_field scoped %}{{ profile.render_field(form.family_name) }}{% endblock %}
{% endif %}
</div>
{% endif %}
{% if "display_name" in form %}
{% block display_name_field scoped %}{{ render_field(form.display_name) }}{% endblock %}
{% block display_name_field scoped %}{{ profile.render_field(form.display_name) }}{% endblock %}
{% endif %}
{% if "photo" in form %}</div></div>{% endif %}
{% if "emails" in form %}
{% block emails_field scoped %}{{ render_field(form.emails) }}{% endblock %}
{% block emails_field scoped %}{{ profile.render_field(form.emails) }}{% endblock %}
{% endif %}
{% if "phone_numbers" in form %}
{% block phone_numbers_field scoped %}{{ render_field(form.phone_numbers) }}{% endblock %}
{% block phone_numbers_field scoped %}{{ profile.render_field(form.phone_numbers) }}{% endblock %}
{% endif %}
{% if "formatted_address" in form %}
{% block formatted_address_field scoped %}{{ render_field(form.formatted_address) }}{% endblock %}
{% block formatted_address_field scoped %}{{ profile.render_field(form.formatted_address) }}{% endblock %}
{% endif %}
{% if "street" in form %}
{% block street_field scoped %}{{ render_field(form.street) }}{% endblock %}
{% block street_field scoped %}{{ profile.render_field(form.street) }}{% endblock %}
{% endif %}
<div class="equal width fields">
{% if "postal_code" in form %}
{% block postal_code_field scoped %}{{ render_field(form.postal_code) }}{% endblock %}
{% block postal_code_field scoped %}{{ profile.render_field(form.postal_code) }}{% endblock %}
{% endif %}
{% if "locality" in form %}
{% block locality_field scoped %}{{ render_field(form.locality) }}{% endblock %}
{% block locality_field scoped %}{{ profile.render_field(form.locality) }}{% endblock %}
{% endif %}
{% if "region" in form %}
{% block region_field scoped %}{{ render_field(form.region) }}{% endblock %}
{% block region_field scoped %}{{ profile.render_field(form.region) }}{% endblock %}
{% endif %}
</div>
<div class="equal width fields">
{% if "department" in form %}
{% block department_field scoped %}{{ render_field(form.department) }}{% endblock %}
{% block department_field scoped %}{{ profile.render_field(form.department) }}{% endblock %}
{% endif %}
{% if "employee_number" in form %}
{% block employee_number_field scoped %}{{ render_field(form.employee_number) }}{% endblock %}
{% block employee_number_field scoped %}{{ profile.render_field(form.employee_number) }}{% endblock %}
{% endif %}
</div>
<div class="equal width fields">
{% if "title" in form %}
{% block title_field scoped %}{{ render_field(form.title) }}{% endblock %}
{% block title_field scoped %}{{ profile.render_field(form.title) }}{% endblock %}
{% endif %}
{% if "organization" in form %}
{% block organization_field scoped %}{{ render_field(form.organization) }}{% endblock %}
{% block organization_field scoped %}{{ profile.render_field(form.organization) }}{% endblock %}
{% endif %}
</div>
{% if "profile_url" in form %}
{% block profile_uri_field scoped %}{{ render_field(form.profile_url) }}{% endblock %}
{% block profile_uri_field scoped %}{{ profile.render_field(form.profile_url) }}{% endblock %}
{% endif %}
{% if "preferred_language" in form %}
{% block preferred_language_field scoped %}{{ render_field(form.preferred_language) }}{% endblock %}
{% block preferred_language_field scoped %}{{ profile.render_field(form.preferred_language) }}{% endblock %}
{% endif %}
<h4 class="ui dividing header">{% trans %}Account settings{% endtrans %}</h4>
{% if "user_name" in form %}
{% block user_name_field scoped %}{{ render_field(form.user_name) }}{% endblock %}
{% block user_name_field scoped %}{{ profile.render_field(form.user_name) }}{% endblock %}
{% endif %}
{% if "groups" in form %}
{% block groups_field scoped %}{{ render_field(form.groups) }}{% endblock %}
{% block groups_field scoped %}{{ profile.render_field(form.groups) }}{% endblock %}
{% endif %}
{% if "password1" in form %}
{% block password_field scoped %}
<div class="two fields">
{{ render_field(form.password1, noindicator=true) }}
{{ render_field(form.password2, noindicator=true) }}
{{ profile.render_field(form.password1, noindicator=true) }}
{{ profile.render_field(form.password2, noindicator=true) }}
</div>
{% endblock %}
{% endif %}
{% if user.can_manage_users %}
{% if user and user.can_manage_users %}
<div class="ui message info">
<div class="header">
{% trans %}User password is not mandatory{% endtrans %}
</div>
{% if has_password %}
<p>{% trans %}The user password can be set:{% endtrans %}</p>
<ul class="ui list">
<li>{% trans %}by filling this form;{% endtrans %}</li>
<li>{% trans %}by sending the user a password initialization mail, after the account creation;{% endtrans %}</li>
<li>{% trans %}or simply waiting for the user to sign-in a first time, and then receive a password initialization mail.{% endtrans %}</li>
</ul>
{% else %}
<p>
{% if has_smtp %}
{% trans %}The user will not be able to authenticate unless the password is set, but they will be able to ask for a password initialization mail.{% endtrans %}
@ -243,7 +183,6 @@
{% trans %}The user will not be able to authenticate unless the password is set.{% endtrans %}
{% endif %}
</p>
{% endif %}
</div>
{% endif %}
@ -255,6 +194,7 @@
</button>
</div>
</div>
{% endcall %}
</div>
{% endblock %}

View file

@ -30,35 +30,35 @@
{% endif %}
{% if user.can_edit_self %}
<a class="item {% if menuitem == "profile" %}active{% endif %}"
<a class="item {% if menuitem is defined and menuitem == "profile" %}active{% endif %}"
href="{{ url_for('account.profile_edition', edited_user=user) }}">
<i class="id card icon"></i>
{% trans %}Profile{% endtrans %}
</a>
{% endif %}
{% if user.can_use_oidc %}
<a class="item {% if menuitem == "consents" %}active{% endif %}"
<a class="item {% if menuitem is defined and menuitem == "consents" %}active{% endif %}"
href="{{ url_for('oidc.consents.consents') }}">
<i class="handshake icon"></i>
{% trans %}Consents{% endtrans %}
</a>
{% endif %}
{% if user.can_manage_users %}
<a class="item {% if menuitem == "users" %}active{% endif %}"
<a class="item {% if menuitem is defined and menuitem == "users" %}active{% endif %}"
href="{{ url_for('account.users') }}">
<i class="address book icon"></i>
{% trans %}Users{% endtrans %}
</a>
{% endif %}
{% if user.can_manage_groups %}
<a class="item {% if menuitem == "groups" %}active{% endif %}"
<a class="item {% if menuitem is defined and menuitem == "groups" %}active{% endif %}"
href="{{ url_for('groups.groups') }}">
<i class="users icon"></i>
{% trans %}Groups{% endtrans %}
</a>
{% endif %}
{% if user.can_manage_oidc %}
<a class="item {% if menuitem == "admin" %}active{% endif %}" href="{{ url_for('admin.mail_index') }}">
<a class="item {% if menuitem is defined and menuitem == "admin" %}active{% endif %}" href="{{ url_for('admin.mail_index') }}">
<i class="settings icon"></i>
{% trans %}Admin{% endtrans %}
</a>

View file

@ -2,6 +2,7 @@ import pytest
from canaille import create_app
from canaille.app import models
from flask_webtest import TestApp
from jinja2 import StrictUndefined
from pytest_lazyfixture import lazy_fixture
from werkzeug.security import gen_salt
@ -89,6 +90,7 @@ def app(configuration, backend):
@pytest.fixture
def testclient(app):
app.config["TESTING"] = True
app.jinja_env.undefined = StrictUndefined
with app.app_context():
yield TestApp(app)