LDAP 'preferredLanguage' attribute support

This commit is contained in:
Éloi Rivard 2022-11-20 22:12:18 +01:00
parent 2a018510d8
commit bb0daf34d7
20 changed files with 343 additions and 192 deletions

View file

@ -25,6 +25,7 @@ Added
- Python 3.11 support. :pr:`61`
- apparmor slapd configuration instructions in CONTRIBUTING.rst :pr:`66`
- ``preferredLanguage`` attribute support. :pr:`75`
Changed
*******

View file

@ -12,6 +12,7 @@ from flask_themer import FileSystemThemeLoader
from flask_themer import render_template
from flask_themer import Themer
from .i18n import available_language_codes
from .ldap_backend.backend import init_backend
from .oidc.oauth import setup_oauth
@ -100,25 +101,34 @@ def setup_jinja(app):
app.jinja_env.filters["timestamp"] = timestamp
def setup_babel(app):
def setup_i18n(app):
babel = Babel(app)
@app.before_request
def before_request():
g.available_language_codes = available_language_codes(babel)
@babel.localeselector
def get_locale():
user = getattr(g, "user", None)
if user is not None:
return user.locale
from .flaskutils import current_user
user = current_user()
available_language_codes = getattr(g, "available_language_codes", [])
if user is not None and user.preferredLanguage in available_language_codes:
return user.preferredLanguage
if app.config.get("LANGUAGE"):
return app.config.get("LANGUAGE")
return request.accept_languages.best_match(["fr_FR", "en_US"])
return request.accept_languages.best_match(available_language_codes)
@babel.timezoneselector
def get_timezone():
user = getattr(g, "user", None)
from .flaskutils import current_user
user = current_user()
if user is not None:
return user.timezone
return user.Timezone
def setup_themer(app):
@ -165,7 +175,7 @@ def create_app(config=None, validate=True):
setup_oauth(app)
setup_blueprints(app)
setup_jinja(app)
setup_babel(app)
setup_i18n(app)
setup_themer(app)
@app.before_request

View file

@ -496,6 +496,12 @@ def profile_edit(editor, username):
) and request.form["action"] == "edit":
flash(_("Profile updated successfuly."), "success")
if (
"preferredLanguage" in request.form
and form["preferredLanguage"].data == "auto"
):
user.preferredLanguage = None
user.save()
return redirect(url_for("account.profile_edition", username=username))

View file

@ -131,7 +131,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
[ACL.DEFAULT]
PERMISSIONS = ["edit_self", "use_oidc"]
READ = ["uid", "groups"]
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber", "jpegPhoto", "mail", "labeledURI"]
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber", "jpegPhoto", "mail", "labeledURI", "preferredLanguage"]
[ACL.ADMIN]
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"

View file

@ -1,10 +1,13 @@
import wtforms.form
from flask import current_app
from flask import g
from flask_babel import lazy_gettext as _
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed
from flask_wtf.file import FileField
from .i18n import available_language_codes
from .i18n import native_language_name_from_code
from .models import Group
from .models import User
@ -89,6 +92,13 @@ class PasswordResetForm(FlaskForm):
)
def available_language_choices():
return [("auto", _("Automatic"))] + [
(lang_code, native_language_name_from_code(lang_code))
for lang_code in g.available_language_codes
]
PROFILE_FORM_FIELDS = dict(
uid=wtforms.StringField(
_("Username"),
@ -164,6 +174,10 @@ PROFILE_FORM_FIELDS = dict(
"placeholder": _("https://mywebsite.tld"),
},
),
preferredLanguage=wtforms.SelectField(
_("Preferred language"),
choices=available_language_choices,
),
)

22
canaille/i18n.py Normal file
View file

@ -0,0 +1,22 @@
import gettext
import pycountry
DEFAULT_LANGUAGE_CODE = "en"
def native_language_name_from_code(code):
language = pycountry.languages.get(alpha_2=code[:2])
if code == DEFAULT_LANGUAGE_CODE:
return language.name
translation = gettext.translation(
"iso639-3", pycountry.LOCALES_DIR, languages=[code]
)
return translation.gettext(language.name)
def available_language_codes(babel):
return [str(translation) for translation in babel.list_translations()] + [
DEFAULT_LANGUAGE_CODE
]

View file

@ -52,7 +52,7 @@ def cached_oauth_authorization_server():
"code id_token",
"token id_token",
],
"ui_locales_supported": ["en-US", "fr-FR"],
"ui_locales_supported": g.available_language_codes,
"code_challenge_methods_supported": ["plain", "S256"],
}

View file

@ -43,10 +43,14 @@ display=true
{% if field.type not in ("SelectField", "SelectMultipleField") %}
{{ field(**kwargs) }}
{% elif field.render_kw and "readonly" in field.render_kw %}
{% elif field.type == "SelectMultipleField" and field.render_kw and "readonly" in field.render_kw %}
{{ field(class_="ui fluid dropdown multiple read-only", **kwargs) }}
{% else %}
{% elif field.type == "SelectMultipleField" %}
{{ field(class_="ui fluid dropdown multiple", **kwargs) }}
{% elif field.type == "SelectField" and field.render_kw and "readonly" in field.render_kw %}
{{ field(class_="ui fluid dropdown read-only", **kwargs) }}
{% elif field.type == "SelectField" %}
{{ field(class_="ui fluid dropdown", **kwargs) }}
{% endif %}
{% if suffix_text %}

View file

@ -143,6 +143,11 @@
{% block labeled_uri_field scoped %}{{ render_field(form.labeledURI) }}{% endblock %}
{% endif %}
{% if "preferredLanguage" in form %}
{% block preferred_language_field scoped %}{{ render_field(form.preferredLanguage) }}{% endblock %}
{% endif %}
<h4 class="ui dividing header">{% trans %}Account information{% endtrans %}</h4>
{% if "uid" in form %}

View file

@ -3,25 +3,25 @@
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
# Camille <camille@yaal.coop>, 2021-2022.
# Éloi Rivard <eloi@yaal.fr>, 2020-2022.
# Éloi Rivard <eloi.rivard@nubla.fr>, 2020-2022.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
"POT-Creation-Date: 2022-07-07 14:27+0200\n"
"PO-Revision-Date: 2022-07-07 14:28+0200\n"
"Last-Translator: Éloi Rivard <eloi@yaal.fr>\n"
"Language: fr_FR\n"
"Language-Team: French - France <equipe@yaal.fr>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2022-11-20 19:32+0100\n"
"PO-Revision-Date: 2022-11-20 19:32+0100\n"
"Last-Translator: Éloi Rivard <eloi.rivard@nubla.fr>\n"
"Language: fr\n"
"Language-Team: French <traduc@traduc.org>\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.10.1\n"
"X-Generator: Gtranslator 40.0\n"
"Generated-By: Babel 2.11.0\n"
"X-Generator: Gtranslator 42.0\n"
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/oauth.py:88
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/endpoints.py:92
msgid "Login failed, please check your information"
msgstr "La connexion a échoué, veuillez vérifier vos informations."
@ -71,7 +71,7 @@ msgstr "Votre compte a déjà été créé."
msgid "You are already logged in, you cannot create an account."
msgstr "Vous êtes déjà connectés, vous ne pouvez pas créer de compte."
#: canaille/account.py:316 canaille/forms.py:185 canaille/forms.py:233
#: canaille/account.py:316 canaille/forms.py:199 canaille/forms.py:247
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
#: canaille/themes/default/base.html:61
msgid "Groups"
@ -113,16 +113,16 @@ msgstr "L'édition du profil a échoué."
msgid "Profile updated successfuly."
msgstr "Le profil a été mis à jour avec succès."
#: canaille/account.py:520
#: canaille/account.py:527
#, python-format
msgid "The user %(user)s has been sucessfuly deleted"
msgstr "L'utilisateur %(user)s a bien été supprimé"
#: canaille/account.py:550
#: canaille/account.py:557
msgid "Could not send the password reset link."
msgstr "Impossible d'envoyer le lien de réinitialisation."
#: canaille/account.py:554
#: canaille/account.py:561
msgid ""
"A password reset link has been sent at your email address. You should "
"receive it within 10 minutes."
@ -130,7 +130,7 @@ msgstr ""
"Un lien de ré-initialisation de votre mot de passe vous a été envoyé par "
"mail. Vous devriez le recevoir d'ici une dizaine de minutes."
#: canaille/account.py:565
#: canaille/account.py:572
#, python-format
msgid ""
"The user '%(user)s' does not have permissions to update their password. We "
@ -139,17 +139,17 @@ msgstr ""
"L'utilisateur '%(user)s' n'a pas la permission d'éditer son mot de passe. "
"Nous ne pouvons pas lui envoyer un email de réinitialisation."
#: canaille/account.py:580
#: canaille/account.py:587
msgid "We encountered an issue while we sent the password recovery email."
msgstr ""
"Nous avons rencontré un problème lors de l'envoi de l'email de "
"réinitialisation de mot de passe."
#: canaille/account.py:599
#: canaille/account.py:606
msgid "The password reset link that brought you here was invalid."
msgstr "Le lien de réinitialisation qui vous a amené ici est invalide."
#: canaille/account.py:608
#: canaille/account.py:615
msgid "Your password has been updated successfuly"
msgstr "Votre mot de passe a correctement été mis à jour."
@ -157,8 +157,8 @@ msgstr "Votre mot de passe a correctement été mis à jour."
msgid "Email"
msgstr "Courriel"
#: canaille/admin.py:29 canaille/forms.py:47 canaille/forms.py:71
#: canaille/forms.py:123 canaille/forms.py:227
#: canaille/admin.py:29 canaille/forms.py:50 canaille/forms.py:74
#: canaille/forms.py:133 canaille/forms.py:241
msgid "jane@doe.com"
msgstr "camille@dupont.fr"
@ -182,7 +182,7 @@ msgstr "Invitation sur {website_name}"
msgid "John Doe"
msgstr "Camille Dupont"
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:215
#: canaille/apputils.py:44 canaille/forms.py:105 canaille/forms.py:229
msgid "jdoe"
msgstr "cdupont"
@ -198,129 +198,137 @@ msgstr " ou "
msgid "No SMTP server has been configured"
msgstr "Aucun serveur SMTP n'a été configuré"
#: canaille/forms.py:15
#: canaille/forms.py:18
msgid "The login '{login}' already exists"
msgstr "L'identifiant '{login}' existe déjà"
#: canaille/forms.py:22
#: canaille/forms.py:25
msgid "The email '{email}' already exists"
msgstr "L'email '{email}' existe déjà"
#: canaille/forms.py:29
#: canaille/forms.py:32
msgid "The group '{group}' already exists"
msgstr "Le group '{group}' existe déjà"
#: canaille/forms.py:38
#: canaille/forms.py:41
msgid "The login '{login}' does not exist"
msgstr "L'identifiant '{login}' n'existe pas"
#: canaille/forms.py:44 canaille/forms.py:68 canaille/templates/userlist.html:8
#: canaille/forms.py:47 canaille/forms.py:71 canaille/templates/userlist.html:8
msgid "Login"
msgstr "Identifiant"
#: canaille/forms.py:57 canaille/forms.py:80 canaille/forms.py:144
#: canaille/forms.py:60 canaille/forms.py:83 canaille/forms.py:154
msgid "Password"
msgstr "Mot de passe"
#: canaille/forms.py:83 canaille/forms.py:148
#: canaille/forms.py:86 canaille/forms.py:158
msgid "Password confirmation"
msgstr "Confirmation du mot de passe"
#: canaille/forms.py:86 canaille/forms.py:151
#: canaille/forms.py:89 canaille/forms.py:161
msgid "Password and confirmation do not match."
msgstr "Le mot de passe et sa confirmation ne correspondent pas."
#: canaille/forms.py:94 canaille/forms.py:214
#: canaille/forms.py:96
msgid "Automatic"
msgstr "Automatique"
#: canaille/forms.py:104 canaille/forms.py:228
msgid "Username"
msgstr "Identifiant"
#: canaille/forms.py:98 canaille/forms.py:200 canaille/oidc/clients.py:36
#: canaille/forms.py:108 canaille/forms.py:214 canaille/oidc/clients.py:36
#: canaille/templates/groups.html:17
#: canaille/templates/oidc/admin/client_list.html:23
#: canaille/templates/userlist.html:11
msgid "Name"
msgstr "Nom"
#: canaille/forms.py:100
#: canaille/forms.py:110
msgid "Given name"
msgstr "Prénom"
#: canaille/forms.py:102
#: canaille/forms.py:112
msgid "John"
msgstr "Martin"
#: canaille/forms.py:108
#: canaille/forms.py:118
msgid "Family Name"
msgstr "Nom de famille"
#: canaille/forms.py:111
#: canaille/forms.py:121
msgid "Doe"
msgstr "Dupont"
#: canaille/forms.py:117 canaille/forms.py:220
#: canaille/forms.py:127 canaille/forms.py:234
msgid "Email address"
msgstr "Courriel"
#: canaille/forms.py:119
#: canaille/forms.py:129
msgid ""
"This email will be used as a recovery address to reset the password if needed"
msgstr ""
"Cette adresse servira d'adresse e-mail de récupération pour recevoir un e-"
"mail de réinitialisation de mot de passe en cas de besoin"
#: canaille/forms.py:129
#: canaille/forms.py:139
msgid "Phone number"
msgstr "Numéro de téléphone"
#: canaille/forms.py:129
#: canaille/forms.py:139
msgid "555-000-555"
msgstr "06 01 02 03 04"
#: canaille/forms.py:132
#: canaille/forms.py:142
msgid "Address"
msgstr "Adresse"
#: canaille/forms.py:134
#: canaille/forms.py:144
msgid "132, Foobar Street, Gotham City 12401"
msgstr "132, rue du Lorem Ipsum - 99000 Gotham City"
#: canaille/forms.py:138
#: canaille/forms.py:148
msgid "Photo"
msgstr "Photo"
#: canaille/forms.py:142 canaille/templates/profile.html:95
#: canaille/forms.py:152 canaille/templates/profile.html:95
msgid "Delete the photo"
msgstr "Supprimer la photo"
#: canaille/forms.py:156
#: canaille/forms.py:166
msgid "Number"
msgstr "Numéro"
#: canaille/forms.py:158
#: canaille/forms.py:168
msgid "1234"
msgstr "1234"
#: canaille/forms.py:162
#: canaille/forms.py:172
msgid "Website"
msgstr "Site internet"
#: canaille/forms.py:164
#: canaille/forms.py:174
msgid "https://mywebsite.tld"
msgstr "https://mon-site-internet.fr"
#: canaille/forms.py:187
#: canaille/forms.py:178
msgid "Preferred language"
msgstr "Langage favori"
#: canaille/forms.py:201
msgid "users, admins ..."
msgstr "utilisateurs, administrateurs ..."
#: canaille/forms.py:203
#: canaille/forms.py:217
msgid "group"
msgstr "groupe"
#: canaille/forms.py:207 canaille/templates/groups.html:18
#: canaille/forms.py:221 canaille/templates/groups.html:18
msgid "Description"
msgstr "Description"
#: canaille/forms.py:218
#: canaille/forms.py:232
msgid "Username editable by the invitee"
msgstr "L'identifiant sera éditable par la personne invitée"
@ -333,11 +341,11 @@ msgstr "La création du groupe a échoué."
msgid "The group %(group)s has been sucessfully created"
msgstr "Le groupe %(group)s a bien été créé"
#: canaille/groups.py:92
#: canaille/groups.py:93
msgid "Group edition failed."
msgstr "L'édition du groupe a échoué."
#: canaille/groups.py:101
#: canaille/groups.py:102
#, python-format
msgid "The group %(group)s has been sucessfully deleted"
msgstr "Le groupe %(group)s a bien été supprimé"
@ -431,11 +439,11 @@ msgstr "Le client n'a pas été ajouté. Veuillez vérifier vos informations."
msgid "The client has been created."
msgstr "Le client a été créé."
#: canaille/oidc/clients.py:233
#: canaille/oidc/clients.py:234
msgid "The client has not been edited. Please check your information."
msgstr "Le client n'a pas été édité. Veuillez vérifier vos informations."
#: canaille/oidc/clients.py:260
#: canaille/oidc/clients.py:263
msgid "The client has been edited."
msgstr "Le client a été édité."
@ -451,39 +459,39 @@ msgstr "Impossible de supprimer cet accès."
msgid "The access has been revoked"
msgstr "L'accès a été révoqué."
#: canaille/oidc/oauth.py:43
#: canaille/oidc/endpoints.py:45
msgid "Personnal information about yourself, such as your name or your gender."
msgstr "Vos informations personnelles, comme votre nom ou votre genre."
#: canaille/oidc/oauth.py:45
#: canaille/oidc/endpoints.py:47
msgid "Your email address."
msgstr "Votre adresse email."
#: canaille/oidc/oauth.py:46
#: canaille/oidc/endpoints.py:48
msgid "Your postal address."
msgstr "Votre adresse postale."
#: canaille/oidc/oauth.py:47
#: canaille/oidc/endpoints.py:49
msgid "Your phone number."
msgstr "Votre numéro de téléphone."
#: canaille/oidc/oauth.py:48
#: canaille/oidc/endpoints.py:50
msgid "Groups you are belonging to"
msgstr "Les groupes auxquels vous appartenez"
#: canaille/oidc/oauth.py:136
#: canaille/oidc/endpoints.py:140
msgid "You have been successfully logged out."
msgstr "Vous avez été déconnecté·e."
#: canaille/oidc/oauth.py:317
#: canaille/oidc/endpoints.py:338
msgid "You have been disconnected"
msgstr "Vous avez été déconnecté·e."
#: canaille/oidc/oauth.py:325
#: canaille/oidc/endpoints.py:346
msgid "An error happened during the logout"
msgstr "Une erreur est survenue lors de la déconnexion"
#: canaille/oidc/oauth.py:337
#: canaille/oidc/endpoints.py:358
msgid "You have not been disconnected"
msgstr "Vous n'avez pas été déconnecté"
@ -581,14 +589,14 @@ msgstr "Page de connexion"
msgid "Send the initialization email"
msgstr "Envoyer le courriel d'initialisation"
#: canaille/templates/fomanticui.html:64
#: canaille/templates/fomanticui.html:68
#: canaille/templates/oidc/admin/client_edit.html:35
#: canaille/templates/oidc/admin/client_edit.html:44
#: canaille/templates/oidc/admin/client_edit.html:53
msgid "This field is not editable"
msgstr "Ce champ n'est pas modifiable"
#: canaille/templates/fomanticui.html:68
#: canaille/templates/fomanticui.html:72
msgid "This field is required"
msgstr "Ce champ est requis"
@ -615,7 +623,6 @@ msgstr ""
" "
#: canaille/templates/forgotten-password.html:38
#: canaille/templates/profile.html:191 canaille/templates/profile.html:219
msgid "Send again"
msgstr "Envoyer à nouveau"
@ -682,7 +689,7 @@ msgstr "Supprimer le groupe"
msgid "Create group"
msgstr "Créer le groupe"
#: canaille/templates/group.html:82 canaille/templates/profile.html:259
#: canaille/templates/group.html:82 canaille/templates/profile.html:254
msgid "Submit"
msgstr "Valider"
@ -873,23 +880,23 @@ msgstr "Informations personnelles"
msgid "Click to upload a photo"
msgstr "Cliquez pour mettre en ligne une photo"
#: canaille/templates/profile.html:146
#: canaille/templates/profile.html:151
msgid "Account information"
msgstr "Informations sur le compte"
#: canaille/templates/profile.html:171
#: canaille/templates/profile.html:176
msgid "User password is not mandatory"
msgstr "Le mot de passe utilisateur n'est pas requis à la création"
#: canaille/templates/profile.html:174
#: canaille/templates/profile.html:179
msgid "The user password can be set:"
msgstr "Il pourra être renseigné :"
#: canaille/templates/profile.html:176
#: canaille/templates/profile.html:181
msgid "by filling this form;"
msgstr "en remplissant ce formulaire ;"
#: canaille/templates/profile.html:177
#: canaille/templates/profile.html:182
msgid ""
"by sending the user a password initialization mail, after the account "
"creation;"
@ -897,7 +904,7 @@ msgstr ""
"en envoyant un lien d'initialisation de mot de passe, par mail à "
"l'utilisateur, après la création de son compte;"
#: canaille/templates/profile.html:178 canaille/templates/profile.html:207
#: canaille/templates/profile.html:183 canaille/templates/profile.html:206
msgid ""
"or simply waiting for the user to sign-in a first time, and then receive a "
"password initialization mail."
@ -905,7 +912,7 @@ msgstr ""
"ou simplement en attendant la première connexion de l'utilisateur, afin "
"qu'il reçoive un lien d'initialisation de mot de passe par email."
#: canaille/templates/profile.html:181 canaille/templates/profile.html:210
#: canaille/templates/profile.html:186 canaille/templates/profile.html:209
msgid "The user will not be able to authenticate unless the password is set"
msgstr ""
"L'utilisateur ne pourra pas se connecter tant que son mot de passe n'est pas "
@ -915,36 +922,36 @@ msgstr ""
msgid "Send email"
msgstr "Envoyer l'email"
#: canaille/templates/profile.html:200
#: canaille/templates/profile.html:199
msgid "This user does not have a password yet"
msgstr "L'utilisateur n'a pas encore de mot de passe"
#: canaille/templates/profile.html:203
#: canaille/templates/profile.html:202
msgid "You can solve this by:"
msgstr "Vous pouvez régler ceci en :"
#: canaille/templates/profile.html:205
#: canaille/templates/profile.html:204
msgid "setting a password using this form;"
msgstr "renseignant un mot de passe via ce formulaire ;"
#: canaille/templates/profile.html:206
#: canaille/templates/profile.html:205
msgid ""
"sending the user a password initialization mail, by clicking this button;"
msgstr ""
"envoyant un lien d'initialisation de mot de passe, par mail à l'utilisateur, "
"en cliquant sur ce bouton;"
#: canaille/templates/profile.html:221
#: canaille/templates/profile.html:217
msgid "Send mail"
msgstr "Envoyer l'email"
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:225
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:220
#: canaille/templates/reset-password.html:11
#: canaille/templates/reset-password.html:16
msgid "Password reset"
msgstr "Réinitialisation du mot de passe"
#: canaille/templates/profile.html:227
#: canaille/templates/profile.html:222
msgid ""
"If the user has forgotten his password, you can send him a password reset "
"email by clicking this button."
@ -952,19 +959,19 @@ msgstr ""
"Si l'utilisateur a oublié son mot de passe, vous pouvez lui envoyer un email "
"contenant un lien de réinitilisation en cliquant sur ce bouton."
#: canaille/templates/profile.html:239
#: canaille/templates/profile.html:234
msgid "Delete the user"
msgstr "Supprimer l'utilisateur"
#: canaille/templates/profile.html:241
#: canaille/templates/profile.html:236
msgid "Delete my account"
msgstr "Supprimer mon compte"
#: canaille/templates/profile.html:248
#: canaille/templates/profile.html:243
msgid "Impersonate"
msgstr "Prendre l'identité"
#: canaille/templates/profile.html:254 canaille/templates/users.html:20
#: canaille/templates/profile.html:249 canaille/templates/users.html:20
msgid "Invite a user"
msgstr "Inviter un utilisateur"
@ -1162,14 +1169,14 @@ msgstr "Secret"
msgid "Issued at"
msgstr "Créé le"
#: canaille/templates/oidc/admin/client_edit.html:72
msgid "Edit"
msgstr "Éditer"
#: canaille/templates/oidc/admin/client_edit.html:75
#: canaille/templates/oidc/admin/client_edit.html:74
msgid "Delete the client"
msgstr "Supprimer le client"
#: canaille/templates/oidc/admin/client_edit.html:77
msgid "Edit"
msgstr "Éditer"
#: canaille/templates/oidc/admin/client_list.html:17
msgid "Add client"
msgstr "Ajouter un client"

View file

@ -8,16 +8,16 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2022-07-07 14:27+0200\n"
"POT-Creation-Date: 2022-11-20 19:32+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.10.1\n"
"Generated-By: Babel 2.11.0\n"
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/oauth.py:88
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/endpoints.py:92
msgid "Login failed, please check your information"
msgstr ""
@ -65,7 +65,7 @@ msgstr ""
msgid "You are already logged in, you cannot create an account."
msgstr ""
#: canaille/account.py:316 canaille/forms.py:185 canaille/forms.py:233
#: canaille/account.py:316 canaille/forms.py:199 canaille/forms.py:247
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
#: canaille/themes/default/base.html:61
msgid "Groups"
@ -103,37 +103,37 @@ msgstr ""
msgid "Profile updated successfuly."
msgstr ""
#: canaille/account.py:520
#: canaille/account.py:527
#, python-format
msgid "The user %(user)s has been sucessfuly deleted"
msgstr ""
#: canaille/account.py:550
#: canaille/account.py:557
msgid "Could not send the password reset link."
msgstr ""
#: canaille/account.py:554
#: canaille/account.py:561
msgid ""
"A password reset link has been sent at your email address. You should "
"receive it within 10 minutes."
msgstr ""
#: canaille/account.py:565
#: canaille/account.py:572
#, python-format
msgid ""
"The user '%(user)s' does not have permissions to update their password. "
"We cannot send a password reset email."
msgstr ""
#: canaille/account.py:580
#: canaille/account.py:587
msgid "We encountered an issue while we sent the password recovery email."
msgstr ""
#: canaille/account.py:599
#: canaille/account.py:606
msgid "The password reset link that brought you here was invalid."
msgstr ""
#: canaille/account.py:608
#: canaille/account.py:615
msgid "Your password has been updated successfuly"
msgstr ""
@ -141,8 +141,8 @@ msgstr ""
msgid "Email"
msgstr ""
#: canaille/admin.py:29 canaille/forms.py:47 canaille/forms.py:71
#: canaille/forms.py:123 canaille/forms.py:227
#: canaille/admin.py:29 canaille/forms.py:50 canaille/forms.py:74
#: canaille/forms.py:133 canaille/forms.py:241
msgid "jane@doe.com"
msgstr ""
@ -166,7 +166,7 @@ msgstr ""
msgid "John Doe"
msgstr ""
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:215
#: canaille/apputils.py:44 canaille/forms.py:105 canaille/forms.py:229
msgid "jdoe"
msgstr ""
@ -182,128 +182,136 @@ msgstr ""
msgid "No SMTP server has been configured"
msgstr ""
#: canaille/forms.py:15
#: canaille/forms.py:18
msgid "The login '{login}' already exists"
msgstr ""
#: canaille/forms.py:22
#: canaille/forms.py:25
msgid "The email '{email}' already exists"
msgstr ""
#: canaille/forms.py:29
#: canaille/forms.py:32
msgid "The group '{group}' already exists"
msgstr ""
#: canaille/forms.py:38
#: canaille/forms.py:41
msgid "The login '{login}' does not exist"
msgstr ""
#: canaille/forms.py:44 canaille/forms.py:68 canaille/templates/userlist.html:8
#: canaille/forms.py:47 canaille/forms.py:71 canaille/templates/userlist.html:8
msgid "Login"
msgstr ""
#: canaille/forms.py:57 canaille/forms.py:80 canaille/forms.py:144
#: canaille/forms.py:60 canaille/forms.py:83 canaille/forms.py:154
msgid "Password"
msgstr ""
#: canaille/forms.py:83 canaille/forms.py:148
#: canaille/forms.py:86 canaille/forms.py:158
msgid "Password confirmation"
msgstr ""
#: canaille/forms.py:86 canaille/forms.py:151
#: canaille/forms.py:89 canaille/forms.py:161
msgid "Password and confirmation do not match."
msgstr ""
#: canaille/forms.py:94 canaille/forms.py:214
#: canaille/forms.py:96
msgid "Automatic"
msgstr ""
#: canaille/forms.py:104 canaille/forms.py:228
msgid "Username"
msgstr ""
#: canaille/forms.py:98 canaille/forms.py:200 canaille/oidc/clients.py:36
#: canaille/forms.py:108 canaille/forms.py:214 canaille/oidc/clients.py:36
#: canaille/templates/groups.html:17
#: canaille/templates/oidc/admin/client_list.html:23
#: canaille/templates/userlist.html:11
msgid "Name"
msgstr ""
#: canaille/forms.py:100
#: canaille/forms.py:110
msgid "Given name"
msgstr ""
#: canaille/forms.py:102
#: canaille/forms.py:112
msgid "John"
msgstr ""
#: canaille/forms.py:108
#: canaille/forms.py:118
msgid "Family Name"
msgstr ""
#: canaille/forms.py:111
#: canaille/forms.py:121
msgid "Doe"
msgstr ""
#: canaille/forms.py:117 canaille/forms.py:220
#: canaille/forms.py:127 canaille/forms.py:234
msgid "Email address"
msgstr ""
#: canaille/forms.py:119
#: canaille/forms.py:129
msgid ""
"This email will be used as a recovery address to reset the password if "
"needed"
msgstr ""
#: canaille/forms.py:129
#: canaille/forms.py:139
msgid "Phone number"
msgstr ""
#: canaille/forms.py:129
#: canaille/forms.py:139
msgid "555-000-555"
msgstr ""
#: canaille/forms.py:132
#: canaille/forms.py:142
msgid "Address"
msgstr ""
#: canaille/forms.py:134
#: canaille/forms.py:144
msgid "132, Foobar Street, Gotham City 12401"
msgstr ""
#: canaille/forms.py:138
#: canaille/forms.py:148
msgid "Photo"
msgstr ""
#: canaille/forms.py:142 canaille/templates/profile.html:95
#: canaille/forms.py:152 canaille/templates/profile.html:95
msgid "Delete the photo"
msgstr ""
#: canaille/forms.py:156
#: canaille/forms.py:166
msgid "Number"
msgstr ""
#: canaille/forms.py:158
#: canaille/forms.py:168
msgid "1234"
msgstr ""
#: canaille/forms.py:162
#: canaille/forms.py:172
msgid "Website"
msgstr ""
#: canaille/forms.py:164
#: canaille/forms.py:174
msgid "https://mywebsite.tld"
msgstr ""
#: canaille/forms.py:187
#: canaille/forms.py:178
msgid "Preferred language"
msgstr ""
#: canaille/forms.py:201
msgid "users, admins ..."
msgstr ""
#: canaille/forms.py:203
#: canaille/forms.py:217
msgid "group"
msgstr ""
#: canaille/forms.py:207 canaille/templates/groups.html:18
#: canaille/forms.py:221 canaille/templates/groups.html:18
msgid "Description"
msgstr ""
#: canaille/forms.py:218
#: canaille/forms.py:232
msgid "Username editable by the invitee"
msgstr ""
@ -316,11 +324,11 @@ msgstr ""
msgid "The group %(group)s has been sucessfully created"
msgstr ""
#: canaille/groups.py:92
#: canaille/groups.py:93
msgid "Group edition failed."
msgstr ""
#: canaille/groups.py:101
#: canaille/groups.py:102
#, python-format
msgid "The group %(group)s has been sucessfully deleted"
msgstr ""
@ -413,11 +421,11 @@ msgstr ""
msgid "The client has been created."
msgstr ""
#: canaille/oidc/clients.py:233
#: canaille/oidc/clients.py:234
msgid "The client has not been edited. Please check your information."
msgstr ""
#: canaille/oidc/clients.py:260
#: canaille/oidc/clients.py:263
msgid "The client has been edited."
msgstr ""
@ -433,39 +441,39 @@ msgstr ""
msgid "The access has been revoked"
msgstr ""
#: canaille/oidc/oauth.py:43
#: canaille/oidc/endpoints.py:45
msgid "Personnal information about yourself, such as your name or your gender."
msgstr ""
#: canaille/oidc/oauth.py:45
#: canaille/oidc/endpoints.py:47
msgid "Your email address."
msgstr ""
#: canaille/oidc/oauth.py:46
#: canaille/oidc/endpoints.py:48
msgid "Your postal address."
msgstr ""
#: canaille/oidc/oauth.py:47
#: canaille/oidc/endpoints.py:49
msgid "Your phone number."
msgstr ""
#: canaille/oidc/oauth.py:48
#: canaille/oidc/endpoints.py:50
msgid "Groups you are belonging to"
msgstr ""
#: canaille/oidc/oauth.py:136
#: canaille/oidc/endpoints.py:140
msgid "You have been successfully logged out."
msgstr ""
#: canaille/oidc/oauth.py:317
#: canaille/oidc/endpoints.py:338
msgid "You have been disconnected"
msgstr ""
#: canaille/oidc/oauth.py:325
#: canaille/oidc/endpoints.py:346
msgid "An error happened during the logout"
msgstr ""
#: canaille/oidc/oauth.py:337
#: canaille/oidc/endpoints.py:358
msgid "You have not been disconnected"
msgstr ""
@ -553,14 +561,14 @@ msgstr ""
msgid "Send the initialization email"
msgstr ""
#: canaille/templates/fomanticui.html:64
#: canaille/templates/fomanticui.html:68
#: canaille/templates/oidc/admin/client_edit.html:35
#: canaille/templates/oidc/admin/client_edit.html:44
#: canaille/templates/oidc/admin/client_edit.html:53
msgid "This field is not editable"
msgstr ""
#: canaille/templates/fomanticui.html:68
#: canaille/templates/fomanticui.html:72
msgid "This field is required"
msgstr ""
@ -581,7 +589,6 @@ msgid ""
msgstr ""
#: canaille/templates/forgotten-password.html:38
#: canaille/templates/profile.html:191 canaille/templates/profile.html:219
msgid "Send again"
msgstr ""
@ -643,7 +650,7 @@ msgstr ""
msgid "Create group"
msgstr ""
#: canaille/templates/group.html:82 canaille/templates/profile.html:259
#: canaille/templates/group.html:82 canaille/templates/profile.html:254
msgid "Submit"
msgstr ""
@ -821,35 +828,35 @@ msgstr ""
msgid "Click to upload a photo"
msgstr ""
#: canaille/templates/profile.html:146
#: canaille/templates/profile.html:151
msgid "Account information"
msgstr ""
#: canaille/templates/profile.html:171
#: canaille/templates/profile.html:176
msgid "User password is not mandatory"
msgstr ""
#: canaille/templates/profile.html:174
#: canaille/templates/profile.html:179
msgid "The user password can be set:"
msgstr ""
#: canaille/templates/profile.html:176
#: canaille/templates/profile.html:181
msgid "by filling this form;"
msgstr ""
#: canaille/templates/profile.html:177
#: canaille/templates/profile.html:182
msgid ""
"by sending the user a password initialization mail, after the account "
"creation;"
msgstr ""
#: canaille/templates/profile.html:178 canaille/templates/profile.html:207
#: canaille/templates/profile.html:183 canaille/templates/profile.html:206
msgid ""
"or simply waiting for the user to sign-in a first time, and then receive "
"a password initialization mail."
msgstr ""
#: canaille/templates/profile.html:181 canaille/templates/profile.html:210
#: canaille/templates/profile.html:186 canaille/templates/profile.html:209
msgid "The user will not be able to authenticate unless the password is set"
msgstr ""
@ -857,51 +864,51 @@ msgstr ""
msgid "Send email"
msgstr ""
#: canaille/templates/profile.html:200
#: canaille/templates/profile.html:199
msgid "This user does not have a password yet"
msgstr ""
#: canaille/templates/profile.html:203
#: canaille/templates/profile.html:202
msgid "You can solve this by:"
msgstr ""
#: canaille/templates/profile.html:205
#: canaille/templates/profile.html:204
msgid "setting a password using this form;"
msgstr ""
#: canaille/templates/profile.html:206
#: canaille/templates/profile.html:205
msgid "sending the user a password initialization mail, by clicking this button;"
msgstr ""
#: canaille/templates/profile.html:221
#: canaille/templates/profile.html:217
msgid "Send mail"
msgstr ""
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:225
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:220
#: canaille/templates/reset-password.html:11
#: canaille/templates/reset-password.html:16
msgid "Password reset"
msgstr ""
#: canaille/templates/profile.html:227
#: canaille/templates/profile.html:222
msgid ""
"If the user has forgotten his password, you can send him a password reset"
" email by clicking this button."
msgstr ""
#: canaille/templates/profile.html:239
#: canaille/templates/profile.html:234
msgid "Delete the user"
msgstr ""
#: canaille/templates/profile.html:241
#: canaille/templates/profile.html:236
msgid "Delete my account"
msgstr ""
#: canaille/templates/profile.html:248
#: canaille/templates/profile.html:243
msgid "Impersonate"
msgstr ""
#: canaille/templates/profile.html:254 canaille/templates/users.html:20
#: canaille/templates/profile.html:249 canaille/templates/users.html:20
msgid "Invite a user"
msgstr ""
@ -1072,12 +1079,12 @@ msgstr ""
msgid "Issued at"
msgstr ""
#: canaille/templates/oidc/admin/client_edit.html:72
msgid "Edit"
#: canaille/templates/oidc/admin/client_edit.html:74
msgid "Delete the client"
msgstr ""
#: canaille/templates/oidc/admin/client_edit.html:75
msgid "Delete the client"
#: canaille/templates/oidc/admin/client_edit.html:77
msgid "Edit"
msgstr ""
#: canaille/templates/oidc/admin/client_list.html:17

View file

@ -132,7 +132,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
[ACL.DEFAULT]
PERMISSIONS = ["use_oidc"]
READ = ["uid", "groups"]
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI"]
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI", "preferredLanguage"]
[ACL.ADMIN]
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"

View file

@ -132,7 +132,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
[ACL.DEFAULT]
PERMISSIONS = ["edit_self", "use_oidc"]
READ = ["uid", "groups"]
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI", "postalAddress"]
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI", "postalAddress", "preferredLanguage"]
[ACL.ADMIN]
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"

27
poetry.lock generated
View file

@ -562,6 +562,17 @@ python-versions = "*"
[package.dependencies]
pyasn1 = ">=0.4.6,<0.5.0"
[[package]]
name = "pycountry"
version = "22.3.5"
description = "ISO country, subdivision, language, currency and script definitions and their translations"
category = "main"
optional = false
python-versions = ">=3.6, <4"
[package.dependencies]
setuptools = "*"
[[package]]
name = "pycparser"
version = "2.21"
@ -785,7 +796,7 @@ tornado = ["tornado (>=5)"]
name = "setuptools"
version = "65.5.1"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.7"
@ -1132,7 +1143,7 @@ sentry = ["sentry-sdk"]
[metadata]
lock-version = "1.1"
python-versions = ">=3.7, <4"
content-hash = "ca4930693ac75ee10a32eb6eb7880b3f9a152fbbcaafe2e928e27f8334513146"
content-hash = "f2c09fc960f35844fe14b819721ea49c5722c59d2c30946892a698db920917bb"
[metadata.files]
aiosmtpd = [
@ -1566,6 +1577,9 @@ pyasn1-modules = [
{file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"},
{file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"},
]
pycountry = [
{file = "pycountry-22.3.5.tar.gz", hash = "sha256:b2163a246c585894d808f18783e19137cb70a0c18fb36748dc01fc6f109c1646"},
]
pycparser = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
@ -1583,8 +1597,6 @@ pyquery = [
{file = "pyquery-1.4.3.tar.gz", hash = "sha256:a388eefb6bc4a55350de0316fbd97cda999ae669b6743ae5b99102ba54f5aa72"},
]
pyreadline = [
{file = "pyreadline-2.1.win-amd64.exe", hash = "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b"},
{file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"},
{file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"},
]
pyrepl = [
@ -1629,6 +1641,13 @@ pyyaml = [
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
{file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
{file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
{file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
{file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},

View file

@ -52,6 +52,7 @@ wtforms = "<4"
"sphinx" = {version = "*", optional=true}
"sphinx-rtd-theme" = {version = "*", optional=true}
"sphinx-issues" = {version = "*", optional=true}
pycountry = "^22.3.5"
[tool.poetry.extras]
sentry = ["sentry-sdk"]

View file

@ -171,6 +171,7 @@ def configuration(slapd_server, smtpd, keypair_path):
"telephoneNumber",
"postalAddress",
"employeeNumber",
"preferredLanguage",
],
},
"ADMIN": {

View file

@ -39,6 +39,7 @@ def test_generate_user_standard_claims_with_default_config(
testclient, slapd_connection, user
):
User.ldap_object_classes(slapd_connection)
user.preferredLanguage = ["fr"]
data = generate_user_claims(user, STANDARD_CLAIMS, DEFAULT_JWT_MAPPING_CONFIG)
@ -47,6 +48,7 @@ def test_generate_user_standard_claims_with_default_config(
"family_name": "Doe",
"email": "john@doe.com",
"sub": "user",
"locale": "fr",
}

View file

@ -1,8 +1,13 @@
from flask import g
def test_oauth_authorization_server(testclient):
res = testclient.get("/.well-known/oauth-authorization-server", status=200).json
assert "https://auth.mydomain.tld" == res["issuer"]
assert res["ui_locales_supported"] == g.available_language_codes
def test_openid_configuration(testclient):
res = testclient.get("/.well-known/openid-configuration", status=200).json
assert "https://auth.mydomain.tld" == res["issuer"]
assert res["ui_locales_supported"] == g.available_language_codes

45
tests/test_i18n.py Normal file
View file

@ -0,0 +1,45 @@
from canaille.models import User
def test_preferred_language(testclient, logged_user):
assert logged_user.preferredLanguage is None
res = testclient.get("/profile/user", status=200)
assert res.form["preferredLanguage"].value == "auto"
assert "My profile" in res.text
assert "Mon profil" not in res.text
res.form["preferredLanguage"] = "fr"
res = res.form.submit(name="action", value="edit").follow()
logged_user = User.get(dn=logged_user.dn)
assert logged_user.preferredLanguage == "fr"
assert res.form["preferredLanguage"].value == "fr"
assert "My profile" not in res.text
assert "Mon profil" in res.text
res.form["preferredLanguage"] = "en"
res = res.form.submit(name="action", value="edit").follow()
logged_user = User.get(dn=logged_user.dn)
assert logged_user.preferredLanguage == "en"
assert res.form["preferredLanguage"].value == "en"
assert "My profile" in res.text
assert "Mon profil" not in res.text
res.form["preferredLanguage"] = "auto"
res = res.form.submit(name="action", value="edit").follow()
logged_user = User.get(dn=logged_user.dn)
assert logged_user.preferredLanguage is None
assert res.form["preferredLanguage"].value == "auto"
assert "My profile" in res.text
assert "Mon profil" not in res.text
def test_language_config(testclient, logged_user):
res = testclient.get("/profile/user", status=200)
assert "My profile" in res.text
assert "Mon profil" not in res.text
testclient.app.config["LANGUAGE"] = "fr"
res = testclient.get("/profile/user", status=200)
assert "My profile" not in res.text
assert "Mon profil" in res.text

View file

@ -50,6 +50,7 @@ def test_edition(
"cn=foo,ou=groups,dc=mydomain,dc=tld",
"cn=bar,ou=groups,dc=mydomain,dc=tld",
]
res.form["preferredLanguage"] = "fr"
res.form["jpegPhoto"] = Upload("logo.jpg", jpeg_photo)
res = res.form.submit(name="action", value="edit").follow()
assert "Profile updated successfuly." in res, str(res)
@ -63,6 +64,7 @@ def test_edition(
assert ["email@mydomain.tld"] == logged_user.mail
assert ["555-666-777"] == logged_user.telephoneNumber
assert ["postal_address"] == logged_user.postalAddress
assert "fr" == logged_user.preferredLanguage
assert "666" == logged_user.employeeNumber
assert [jpeg_photo] == logged_user.jpegPhoto