forked from Github-Mirrors/canaille
jpegPhoto profile form
This commit is contained in:
parent
5ba87a2ddc
commit
0053369604
19 changed files with 432 additions and 221 deletions
|
@ -22,7 +22,7 @@ from flask_babel import Babel, gettext as _
|
|||
from flask_themer import Themer, render_template, FileSystemThemeLoader
|
||||
from logging.config import dictConfig
|
||||
|
||||
from .flaskutils import current_user
|
||||
from .flaskutils import current_user, base64picture
|
||||
from .ldaputils import LDAPObject
|
||||
from .oauth2utils import setup_oauth
|
||||
from .models import User, Group
|
||||
|
@ -163,6 +163,10 @@ def teardown_ldap_connection(app):
|
|||
g.ldap.unbind_s()
|
||||
|
||||
|
||||
def setup_jinja(app):
|
||||
app.jinja_env.filters["base64picture"] = base64picture
|
||||
|
||||
|
||||
def setup_babel(app):
|
||||
babel = Babel(app)
|
||||
|
||||
|
@ -231,6 +235,7 @@ def create_app(config=None, validate=True):
|
|||
setup_ldap_models(app)
|
||||
setup_oauth(app)
|
||||
setup_blueprints(app)
|
||||
setup_jinja(app)
|
||||
setup_babel(app)
|
||||
setup_themer(app)
|
||||
|
||||
|
|
|
@ -14,7 +14,13 @@ from flask import (
|
|||
from flask_babel import gettext as _
|
||||
from flask_themer import render_template
|
||||
from werkzeug.datastructures import CombinedMultiDict, FileStorage
|
||||
from .apputils import default_fields, b64_to_obj, login_placeholder, profile_hash, obj_to_b64
|
||||
from .apputils import (
|
||||
default_fields,
|
||||
b64_to_obj,
|
||||
login_placeholder,
|
||||
profile_hash,
|
||||
obj_to_b64,
|
||||
)
|
||||
from .forms import (
|
||||
InvitationForm,
|
||||
LoginForm,
|
||||
|
@ -54,7 +60,9 @@ def about():
|
|||
@bp.route("/login", methods=("GET", "POST"))
|
||||
def login():
|
||||
if current_user():
|
||||
return redirect(url_for("account.profile_edition", username=current_user().uid[0]))
|
||||
return redirect(
|
||||
url_for("account.profile_edition", username=current_user().uid[0])
|
||||
)
|
||||
|
||||
form = LoginForm(request.form or None)
|
||||
form["login"].render_kw["placeholder"] = login_placeholder()
|
||||
|
@ -295,6 +303,9 @@ def profile_create(current_app, form):
|
|||
else:
|
||||
user[attribute.name] = [data]
|
||||
|
||||
if "jpegPhoto" in form and form["jpegPhoto_delete"].data:
|
||||
user["jpegPhoto"] = None
|
||||
|
||||
user.cn = [f"{user.givenName[0]} {user.sn[0]}"]
|
||||
user.save()
|
||||
|
||||
|
@ -391,6 +402,9 @@ def profile_edit(editor, username):
|
|||
elif attribute.name == "groups" and "groups" in editor.write:
|
||||
user.set_groups(attribute.data)
|
||||
|
||||
if "jpegPhoto" in form and form["jpegPhoto_delete"].data:
|
||||
user["jpegPhoto"] = None
|
||||
|
||||
if (
|
||||
"password1" not in request.form
|
||||
or not form["password1"].data
|
||||
|
|
|
@ -111,9 +111,9 @@ GROUP_USER_FILTER = "member={user.dn}"
|
|||
# The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
|
||||
# object that users will be able to read and/or write.
|
||||
[ACL.DEFAULT]
|
||||
READ = ["uid", "groups"]
|
||||
PERMISSIONS = ["use_oidc"]
|
||||
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber", "jpegPhoto", "mail"]
|
||||
|
||||
[ACL.ADMIN]
|
||||
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import base64
|
||||
import ldap
|
||||
import logging
|
||||
from functools import wraps
|
||||
|
@ -82,3 +83,8 @@ def smtp_needed():
|
|||
return decorator
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def base64picture(data):
|
||||
data = base64.b64encode(data).decode("utf-8")
|
||||
return f"data:image/jpeg;base64,{data}"
|
||||
|
|
|
@ -3,7 +3,7 @@ import wtforms.form
|
|||
from flask import current_app
|
||||
from flask_babel import lazy_gettext as _
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileField, FileRequired
|
||||
from flask_wtf.file import FileField, FileAllowed
|
||||
from .models import User, Group
|
||||
|
||||
|
||||
|
@ -122,7 +122,12 @@ PROFILE_FORM_FIELDS = dict(
|
|||
telephoneNumber=wtforms.TelField(
|
||||
_("Phone number"), render_kw={"placeholder": _("555-000-555")}
|
||||
),
|
||||
jpegPhoto=FileField(_("Photo"), validators=[FileRequired()]),
|
||||
jpegPhoto=FileField(
|
||||
_("Photo"),
|
||||
validators=[FileAllowed(["jpg", "jpeg"])],
|
||||
render_kw={"accept": "image/jpg, image/jpeg"},
|
||||
),
|
||||
jpegPhoto_delete=wtforms.BooleanField(_("Delete the photo")),
|
||||
password1=wtforms.PasswordField(
|
||||
_("Password"),
|
||||
validators=[wtforms.validators.Optional(), wtforms.validators.Length(min=8)],
|
||||
|
@ -148,6 +153,9 @@ def profile_form(write_field_names, readonly_field_names):
|
|||
if "userPassword" in write_field_names:
|
||||
write_field_names |= {"password1", "password2"}
|
||||
|
||||
if "jpegPhoto" in write_field_names:
|
||||
write_field_names |= {"jpegPhoto_delete"}
|
||||
|
||||
fields = {
|
||||
name: PROFILE_FORM_FIELDS.get(name)
|
||||
for name in write_field_names | readonly_field_names
|
||||
|
|
|
@ -166,6 +166,9 @@ class LDAPObject:
|
|||
if syntax == "1.3.6.1.4.1.1466.115.121.1.27": # Integer
|
||||
return int(value.decode("utf-8"))
|
||||
|
||||
if syntax == "1.3.6.1.4.1.1466.115.121.1.28": # JPEG
|
||||
return value
|
||||
|
||||
if syntax == "1.3.6.1.4.1.1466.115.121.1.7": # Boolean
|
||||
return value.decode("utf-8").upper() == "TRUE"
|
||||
|
||||
|
@ -181,6 +184,9 @@ class LDAPObject:
|
|||
if syntax == "1.3.6.1.4.1.1466.115.121.1.27": # Integer
|
||||
return str(value).encode("utf-8")
|
||||
|
||||
if syntax == "1.3.6.1.4.1.1466.115.121.1.28": # JPEG
|
||||
return value
|
||||
|
||||
if syntax == "1.3.6.1.4.1.1466.115.121.1.7": # Boolean
|
||||
return ("TRUE" if value else "FALSE").encode("utf-8")
|
||||
|
||||
|
@ -215,13 +221,18 @@ class LDAPObject:
|
|||
|
||||
# Object already exists in the LDAP database
|
||||
if match:
|
||||
deletions = [
|
||||
name
|
||||
for name, value in self.changes.items()
|
||||
if value is None and name in self.attrs
|
||||
]
|
||||
changes = {
|
||||
name: value
|
||||
for name, value in self.changes.items()
|
||||
if value and value[0] and self.attrs.get(name) != value
|
||||
}
|
||||
formatted_changes = self.python_attrs_to_ldap(changes)
|
||||
modlist = [
|
||||
modlist = [(ldap.MOD_DELETE, name, None) for name in deletions] + [
|
||||
(ldap.MOD_REPLACE, name, values)
|
||||
for name, values in formatted_changes.items()
|
||||
]
|
||||
|
|
|
@ -148,6 +148,12 @@ class User(LDAPObject):
|
|||
self.read |= set(details.get("READ", []))
|
||||
self.write |= set(details.get("WRITE", []))
|
||||
|
||||
def can_read(self, field):
|
||||
return field in self.read | self.write
|
||||
|
||||
def can_writec(self, field):
|
||||
return field in self.write
|
||||
|
||||
@property
|
||||
def can_use_oidc(self):
|
||||
return "use_oidc" in self.permissions
|
||||
|
|
|
@ -42,3 +42,11 @@ footer a {
|
|||
.ui.corner.labeled.input .ui.dropdown .dropdown.icon {
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
.profile-form label img{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.profile-form label i{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
17
canaille/static/js/profile.js
Normal file
17
canaille/static/js/profile.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
$(function(){
|
||||
$(".photo-delete-icon").click(function(event){
|
||||
event.preventDefault();
|
||||
$(".photo-content").hide();
|
||||
$(".photo-placeholder").show();
|
||||
$(".photo-field").val("");
|
||||
$(".photo-delete-button").prop("checked", true);
|
||||
});
|
||||
|
||||
$(".photo-field").change(function(event){
|
||||
var upload = URL.createObjectURL(event.target.files[0]);
|
||||
$(".photo-content").show();
|
||||
$(".photo-placeholder").hide();
|
||||
$(".photo-content img").attr("src", upload);
|
||||
$(".photo-delete-button").prop("checked", false);
|
||||
});
|
||||
});
|
|
@ -5,13 +5,16 @@
|
|||
container=true,
|
||||
noindicator=false,
|
||||
indicator_icon=none,
|
||||
indicator_text=none
|
||||
indicator_text=none,
|
||||
display=true
|
||||
) -%}
|
||||
|
||||
{% if container %}
|
||||
<div class="field {{ kwargs.pop('class_', '') }}
|
||||
{%- 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 -%}"
|
||||
{% if not display %}style="display: none"{% endif %}
|
||||
>
|
||||
{% endif %}
|
||||
|
||||
{% if (field.type != 'HiddenField' and field.type !='CSRFTokenField') and label_visible %}
|
||||
|
@ -31,7 +34,6 @@
|
|||
{% if field.type not in ("SelectField", "SelectMultipleField") %}
|
||||
{{ field(**kwargs) }}
|
||||
{% elif field.render_kw and "readonly" in field.render_kw %}
|
||||
{# This will be un-needed when https://github.com/fomantic/Fomantic-UI/issues/2173 is solved #}
|
||||
{{ field(class_="ui fluid dropdown multiple read-only", **kwargs) }}
|
||||
{% else %}
|
||||
{{ field(class_="ui fluid dropdown multiple", **kwargs) }}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import 'fomanticui.html' as sui %}
|
||||
{% import 'userlist.html' as user_list %}
|
||||
|
||||
{% block style %}
|
||||
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
||||
|
@ -85,27 +86,7 @@
|
|||
</div>
|
||||
|
||||
{% if edited_group %}
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<th>{% trans %}Login{% endtrans %}</th>
|
||||
<th>{% trans %}Name{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Groups{% endtrans %}</th>
|
||||
</thead>
|
||||
{% for user_account in members %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('account.profile_edition', username=user_account.uid[0]) }}">{{ user_account.uid[0] }}</a></td>
|
||||
<td>{{ user_account.name }}</td>
|
||||
<td><a href="mailto:{{ user_account.mail[0] }}">{{ user_account.mail[0] }}</a></td>
|
||||
<td>
|
||||
{% for group in user_account.groups %}
|
||||
<a class="ui label" href="{{ url_for('groups.group', groupname=group.name) }}">{{ group.name }}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{{ user_list.user_list(user, members) }}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,20 +3,21 @@
|
|||
|
||||
{% block script %}
|
||||
<script src="/static/js/confirm.js"></script>
|
||||
<script src="/static/js/profile.js"></script>
|
||||
{% 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 %}
|
||||
{{ sui.render_field(field) }}
|
||||
{{ sui.render_field(field, **kwargs) }}
|
||||
{% elif edited_user.uid == user.uid or lock_indicator or noindicator %}
|
||||
{{ sui.render_field(field) }}
|
||||
{{ sui.render_field(field, **kwargs) }}
|
||||
{% elif field.name in edited_user.write %}
|
||||
{{ sui.render_field(field, noindicator=true) }}
|
||||
{{ sui.render_field(field, noindicator=true, **kwargs) }}
|
||||
{% elif field.name in edited_user.read %}
|
||||
{{ sui.render_field(field, indicator_icon="eye", indicator_text=_("This user cannot edit this field")) }}
|
||||
{{ sui.render_field(field, indicator_icon="eye", indicator_text=_("This user cannot edit this field"), **kwargs) }}
|
||||
{% else %}
|
||||
{{ sui.render_field(field, indicator_icon="eye slash", indicator_text=_("This user cannot see this field")) }}
|
||||
{{ sui.render_field(field, indicator_icon="eye slash", indicator_text=_("This user cannot see this field"), **kwargs) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
@ -71,12 +72,42 @@
|
|||
action="{{ request.url }}"
|
||||
role="form"
|
||||
enctype="multipart/form-data"
|
||||
class="ui form info{% if user.can_manage_users and edited_user and not edited_user.has_password() %} warning{% endif %}"
|
||||
class="ui form info{% if user.can_manage_users and edited_user and not edited_user.has_password() %} warning{% endif %} profile-form"
|
||||
>
|
||||
|
||||
{#{ render_field(form.csrf_token) }#}
|
||||
|
||||
<h4 class="ui dividing header">{% trans %}Personal information{% endtrans %}</h4>
|
||||
|
||||
{% if "jpegPhoto" in form %}
|
||||
<div class="ui grid">
|
||||
<div class="three wide column">
|
||||
{{ render_field(form.jpegPhoto, display=false, class="photo-field") }}
|
||||
{{ render_field(form.jpegPhoto_delete, display=false, class="photo-delete-button") }}
|
||||
{% set photo = edited_user.jpegPhoto and edited_user.jpegPhoto[0] %}
|
||||
<label
|
||||
class="ui small bordered image photo-content"
|
||||
for="{{ form.jpegPhoto.id }}"
|
||||
title="{{ _("Click to upload a photo") }}"
|
||||
{% if not photo %}style="display: none;"{% endif %}>
|
||||
|
||||
<a class="ui right corner label photo-delete-icon" title="{{ _("Delete the photo") }}">
|
||||
<i class="times icon"></i>
|
||||
</a>
|
||||
<img src="{% if photo %}{{ edited_user.jpegPhoto[0]|base64picture }}{% endif %}" alt="User photo">
|
||||
</label>
|
||||
<label
|
||||
class="ui centered photo-placeholder"
|
||||
for="{{ form.jpegPhoto.id }}"
|
||||
title="{{ _("Click to upload a photo") }}"
|
||||
{% if photo %}style="display: none;"{% endif %}>
|
||||
<i class="massive centered portrait icon"></i>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="thirteen wide column">
|
||||
{% endif %}
|
||||
|
||||
<div class="two fields">
|
||||
{% if "givenName" in form %}
|
||||
{{ render_field(form.givenName) }}
|
||||
|
@ -85,9 +116,13 @@
|
|||
{{ render_field(form.sn) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if "mail" in form %}
|
||||
{{ render_field(form.mail) }}
|
||||
{% endif %}
|
||||
|
||||
{% if "jpegPhoto" in form %}</div></div>{% endif %}
|
||||
|
||||
{% if "telephoneNumber" in form %}
|
||||
{{ render_field(form.telephoneNumber) }}
|
||||
{% endif %}
|
||||
|
|
52
canaille/templates/userlist.html
Normal file
52
canaille/templates/userlist.html
Normal file
|
@ -0,0 +1,52 @@
|
|||
{% macro user_list(watcher, users) %}
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
{% if watcher.can_read("jpegPhoto") %}
|
||||
<th></th>
|
||||
{% endif %}
|
||||
{% if watcher.can_read("uid") %}
|
||||
<th>{% trans %}Login{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if watcher.can_read("sn") or watcher.can_read("givenName") %}
|
||||
<th>{% trans %}Name{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if watcher.can_read("mail") %}
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if watcher.can_manage_groups %}
|
||||
<th>{% trans %}Groups{% endtrans %}</th>
|
||||
{% endif %}
|
||||
</thead>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
{% if watcher.can_read("jpegPhoto") %}
|
||||
<td>
|
||||
<a href="{{ url_for('account.profile_edition', username=user.uid[0]) }}">
|
||||
{% if user.jpegPhoto and user.jpegPhoto[0] %}
|
||||
<img class="ui avatar image" src="{{ user.jpegPhoto[0]|base64picture }}" alt="User photo">
|
||||
{% else %}
|
||||
<i class="user circle big black icon"></i>
|
||||
{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if watcher.can_read("uid") %}
|
||||
<td><a href="{{ url_for('account.profile_edition', username=user.uid[0]) }}">{{ user.uid[0] }}</a></td>
|
||||
{% endif %}
|
||||
{% if watcher.can_read("sn") or watcher.can_read("givenName") %}
|
||||
<td>{{ user.name }}</td>
|
||||
{% endif %}
|
||||
{% if watcher.can_read("mail") %}
|
||||
<td><a href="mailto:{{ user.mail[0] }}">{{ user.mail[0] }}</a></td>
|
||||
{% endif %}
|
||||
{% if watcher.can_manage_groups %}
|
||||
<td>
|
||||
{% for group in user.groups %}
|
||||
<a class="ui label" href="{{ url_for('groups.group', groupname=group.name) }}">{{ group.name }}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endmacro %}
|
|
@ -1,4 +1,5 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import 'userlist.html' as user_list %}
|
||||
|
||||
{% block style %}
|
||||
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
||||
|
@ -21,27 +22,5 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<th>{% trans %}Login{% endtrans %}</th>
|
||||
<th>{% trans %}Name{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
{% if user.can_manage_groups %}<th>{% trans %}Groups{% endtrans %}</th>{% endif %}
|
||||
</thead>
|
||||
{% for user_account in users %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('account.profile_edition', username=user_account.uid[0]) }}">{{ user_account.uid[0] }}</a></td>
|
||||
<td>{{ user_account.name }}</td>
|
||||
<td><a href="mailto:{{ user_account.mail[0] }}">{{ user_account.mail[0] }}</a></td>
|
||||
{% if user.can_manage_groups %}
|
||||
<td>
|
||||
{% for group in user_account.groups %}
|
||||
<a class="ui label" href="{{ url_for('groups.group', groupname=group.name) }}">{{ group.name }}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{{ user_list.user_list(user, users) }}
|
||||
{% endblock %}
|
||||
|
|
|
@ -9,46 +9,46 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
||||
"POT-Creation-Date: 2021-12-07 19:58+0100\n"
|
||||
"PO-Revision-Date: 2021-12-07 20:03+0100\n"
|
||||
"POT-Creation-Date: 2021-12-08 18:56+0100\n"
|
||||
"PO-Revision-Date: 2021-12-08 18:56+0100\n"
|
||||
"Last-Translator: Éloi Rivard <eloi.rivard@aquilenet.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-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
"X-Generator: Gtranslator 40.0\n"
|
||||
|
||||
#: canaille/__init__.py:123
|
||||
#: canaille/__init__.py:129
|
||||
msgid "Could not connect to the LDAP server '{uri}'"
|
||||
msgstr "Impossible de se connecter au serveur LDAP '{uri}'"
|
||||
|
||||
#: canaille/__init__.py:139
|
||||
#: canaille/__init__.py:145
|
||||
msgid "LDAP authentication failed with user '{user}'"
|
||||
msgstr ""
|
||||
"L'authentification au serveur LDAP a échoué pour l'utilisateur '{user}'"
|
||||
|
||||
#: canaille/account.py:69 canaille/account.py:94 canaille/oauth.py:74
|
||||
#: canaille/account.py:77 canaille/account.py:102 canaille/oauth.py:74
|
||||
msgid "Login failed, please check your information"
|
||||
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
||||
|
||||
#: canaille/account.py:100
|
||||
#: canaille/account.py:108
|
||||
#, python-format
|
||||
msgid "Connection successful. Welcome %(user)s"
|
||||
msgstr "Connexion réussie. Bienvenue %(user)s"
|
||||
|
||||
#: canaille/account.py:113
|
||||
#: canaille/account.py:121
|
||||
#, python-format
|
||||
msgid "You have been disconnected. See you next time %(user)s"
|
||||
msgstr "Vous avez été déconnectés. À bientôt %(user)s"
|
||||
|
||||
#: canaille/account.py:130
|
||||
#: canaille/account.py:138
|
||||
msgid "Could not send the password initialization link."
|
||||
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
||||
|
||||
#: canaille/account.py:135
|
||||
#: canaille/account.py:143
|
||||
msgid ""
|
||||
"A password initialization link has been sent at your email address. You "
|
||||
"should receive it within 10 minutes."
|
||||
|
@ -56,35 +56,35 @@ msgstr ""
|
|||
"Un lien d'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:141 canaille/account.py:326
|
||||
#: canaille/account.py:149 canaille/account.py:340
|
||||
msgid "Could not send the password initialization email"
|
||||
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
||||
|
||||
#: canaille/account.py:192 canaille/account.py:264
|
||||
#: canaille/account.py:204 canaille/account.py:275
|
||||
msgid "User account creation failed."
|
||||
msgstr "La création du compte utilisateur a échoué."
|
||||
|
||||
#: canaille/account.py:213 canaille/account.py:234
|
||||
#: canaille/account.py:225 canaille/account.py:246
|
||||
msgid "The invitation link that brought you here was invalid."
|
||||
msgstr "Le lien d'invitation qui vous a amené ici est invalide."
|
||||
|
||||
#: canaille/account.py:220
|
||||
#: canaille/account.py:232
|
||||
msgid "Your account has already been created."
|
||||
msgstr "Votre compte a déjà été créé."
|
||||
|
||||
#: canaille/account.py:227
|
||||
#: canaille/account.py:239
|
||||
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:269
|
||||
#: canaille/account.py:280
|
||||
msgid "You account has been created successfuly."
|
||||
msgstr "Votre compte utilisateur a été créé avec succès."
|
||||
|
||||
#: canaille/account.py:299
|
||||
#: canaille/account.py:313
|
||||
msgid "User account creation succeed."
|
||||
msgstr "La création du compte utilisateur a réussi."
|
||||
|
||||
#: canaille/account.py:320
|
||||
#: canaille/account.py:334
|
||||
msgid ""
|
||||
"A password initialization link has been sent at the user email address. It "
|
||||
"should be received within 10 minutes."
|
||||
|
@ -92,7 +92,7 @@ msgstr ""
|
|||
"Un lien d'initialisation de mot de passe a été envoyé à l'utilisateur par "
|
||||
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:334
|
||||
#: canaille/account.py:348
|
||||
msgid ""
|
||||
"A password reset link has been sent at the user email address. It should be "
|
||||
"received within 10 minutes."
|
||||
|
@ -100,28 +100,28 @@ msgstr ""
|
|||
"Un lien de réinitialisation de mot de passe a été envoyé à l'utilisateur par "
|
||||
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:340
|
||||
#: canaille/account.py:354
|
||||
msgid "Could not send the password reset email"
|
||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||
|
||||
#: canaille/account.py:371
|
||||
#: canaille/account.py:385
|
||||
msgid "Profile edition failed."
|
||||
msgstr "L'édition du profil a échoué."
|
||||
|
||||
#: canaille/account.py:396
|
||||
#: canaille/account.py:413
|
||||
msgid "Profile updated successfuly."
|
||||
msgstr "Le profil a été mis à jour avec succès."
|
||||
|
||||
#: canaille/account.py:416
|
||||
#: canaille/account.py:433
|
||||
#, python-format
|
||||
msgid "The user %(user)s has been sucessfuly deleted"
|
||||
msgstr "L'utilisateur %(user)s a bien été supprimé"
|
||||
|
||||
#: canaille/account.py:440
|
||||
#: canaille/account.py:457
|
||||
msgid "Could not send the password reset link."
|
||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||
|
||||
#: canaille/account.py:447 canaille/account.py:458
|
||||
#: canaille/account.py:464 canaille/account.py:475
|
||||
msgid ""
|
||||
"A password reset link has been sent at your email address. You should "
|
||||
"receive it within 10 minutes."
|
||||
|
@ -129,15 +129,15 @@ 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:464
|
||||
#: canaille/account.py:481
|
||||
msgid "Could not reset your password"
|
||||
msgstr "Impossible de réinitialiser votre mot de passe"
|
||||
|
||||
#: canaille/account.py:478
|
||||
#: canaille/account.py:495
|
||||
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:487
|
||||
#: canaille/account.py:504
|
||||
msgid "Your password has been updated successfuly"
|
||||
msgstr "Votre mot de passe a correctement été mis à jour."
|
||||
|
||||
|
@ -145,7 +145,7 @@ msgstr "Votre mot de passe a correctement été mis à jour."
|
|||
msgid "John Doe"
|
||||
msgstr "Camille Dupont"
|
||||
|
||||
#: canaille/apputils.py:37 canaille/forms.py:93 canaille/forms.py:188
|
||||
#: canaille/apputils.py:37 canaille/forms.py:93 canaille/forms.py:196
|
||||
msgid "jdoe"
|
||||
msgstr "cdupont"
|
||||
|
||||
|
@ -165,7 +165,7 @@ msgstr "Impossible de supprimer cet accès."
|
|||
msgid "The access has been revoked"
|
||||
msgstr "L'accès a été révoqué."
|
||||
|
||||
#: canaille/flaskutils.py:69
|
||||
#: canaille/flaskutils.py:70
|
||||
msgid "No SMTP server has been configured"
|
||||
msgstr "Aucun serveur SMTP n'a été configuré"
|
||||
|
||||
|
@ -191,27 +191,27 @@ msgid "Login"
|
|||
msgstr "Identifiant"
|
||||
|
||||
#: canaille/forms.py:45 canaille/forms.py:69 canaille/forms.py:117
|
||||
#: canaille/forms.py:199
|
||||
#: canaille/forms.py:207
|
||||
msgid "jane@doe.com"
|
||||
msgstr "camille@dupont.fr"
|
||||
|
||||
#: canaille/forms.py:55 canaille/forms.py:78 canaille/forms.py:127
|
||||
#: canaille/forms.py:55 canaille/forms.py:78 canaille/forms.py:132
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: canaille/forms.py:81 canaille/forms.py:131
|
||||
#: canaille/forms.py:81 canaille/forms.py:136
|
||||
msgid "Password confirmation"
|
||||
msgstr "Confirmation du mot de passe"
|
||||
|
||||
#: canaille/forms.py:84 canaille/forms.py:134
|
||||
#: canaille/forms.py:84 canaille/forms.py:139
|
||||
msgid "Password and confirmation do not match."
|
||||
msgstr "Le mot de passe et sa confirmation ne correspondent pas."
|
||||
|
||||
#: canaille/forms.py:92 canaille/forms.py:187
|
||||
#: canaille/forms.py:92 canaille/forms.py:195
|
||||
msgid "Username"
|
||||
msgstr "Identifiant"
|
||||
|
||||
#: canaille/admin/clients.py:28 canaille/forms.py:96 canaille/forms.py:177
|
||||
#: canaille/admin/clients.py:28 canaille/forms.py:96 canaille/forms.py:185
|
||||
#: canaille/templates/admin/client_list.html:22
|
||||
#: canaille/templates/group.html:91 canaille/templates/users.html:27
|
||||
msgid "Name"
|
||||
|
@ -233,7 +233,7 @@ msgstr "Nom de famille"
|
|||
msgid "Doe"
|
||||
msgstr "Dupont"
|
||||
|
||||
#: canaille/forms.py:114 canaille/forms.py:192
|
||||
#: canaille/forms.py:114 canaille/forms.py:200
|
||||
msgid "Email address"
|
||||
msgstr "Courriel"
|
||||
|
||||
|
@ -245,25 +245,29 @@ msgstr "Numéro de téléphone"
|
|||
msgid "555-000-555"
|
||||
msgstr "06 01 02 03 04"
|
||||
|
||||
#: canaille/forms.py:125
|
||||
#: canaille/forms.py:126
|
||||
msgid "Photo"
|
||||
msgstr "Photo"
|
||||
|
||||
#: canaille/forms.py:139
|
||||
#: canaille/forms.py:130 canaille/templates/profile.html:91
|
||||
msgid "Delete the photo"
|
||||
msgstr "Supprimer la photo"
|
||||
|
||||
#: canaille/forms.py:144
|
||||
msgid "Number"
|
||||
msgstr "Numéro"
|
||||
|
||||
#: canaille/forms.py:141
|
||||
#: canaille/forms.py:146
|
||||
msgid "1234"
|
||||
msgstr "1234"
|
||||
|
||||
#: canaille/forms.py:162 canaille/forms.py:205 canaille/templates/group.html:93
|
||||
#: canaille/forms.py:170 canaille/forms.py:213 canaille/templates/group.html:93
|
||||
#: canaille/templates/groups.html:9 canaille/templates/users.html:29
|
||||
#: canaille/themes/default/base.html:59
|
||||
msgid "Groups"
|
||||
msgstr "Groupes"
|
||||
|
||||
#: canaille/forms.py:180
|
||||
#: canaille/forms.py:188
|
||||
msgid "group"
|
||||
msgstr "groupe"
|
||||
|
||||
|
@ -553,11 +557,11 @@ msgstr "Envoyer le courriel d'initialisation"
|
|||
#: canaille/templates/admin/client_edit.html:35
|
||||
#: canaille/templates/admin/client_edit.html:44
|
||||
#: canaille/templates/admin/client_edit.html:53
|
||||
#: canaille/templates/fomanticui.html:46
|
||||
#: canaille/templates/fomanticui.html:48
|
||||
msgid "This field is not editable"
|
||||
msgstr "Ce champ n'est pas modifiable"
|
||||
|
||||
#: canaille/templates/fomanticui.html:50
|
||||
#: canaille/templates/fomanticui.html:52
|
||||
msgid "This field is required"
|
||||
msgstr "Ce champ est requis"
|
||||
|
||||
|
@ -584,7 +588,7 @@ msgstr ""
|
|||
" "
|
||||
|
||||
#: canaille/templates/forgotten-password.html:38
|
||||
#: canaille/templates/profile.html:137 canaille/templates/profile.html:165
|
||||
#: canaille/templates/profile.html:164 canaille/templates/profile.html:192
|
||||
msgid "Send again"
|
||||
msgstr "Envoyer à nouveau"
|
||||
|
||||
|
@ -605,12 +609,12 @@ msgstr ""
|
|||
"irrévocable, et toutes les données de cet utilisateur seront supprimées."
|
||||
|
||||
#: canaille/templates/admin/client_edit.html:18
|
||||
#: canaille/templates/group.html:29 canaille/templates/profile.html:38
|
||||
#: canaille/templates/group.html:29 canaille/templates/profile.html:41
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: canaille/templates/admin/client_edit.html:19
|
||||
#: canaille/templates/group.html:30 canaille/templates/profile.html:39
|
||||
#: canaille/templates/group.html:30 canaille/templates/profile.html:42
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
|
@ -648,7 +652,7 @@ msgstr "Supprimer le groupe"
|
|||
msgid "Create group"
|
||||
msgstr "Créer le groupe"
|
||||
|
||||
#: canaille/templates/group.html:79 canaille/templates/profile.html:205
|
||||
#: canaille/templates/group.html:79 canaille/templates/profile.html:232
|
||||
msgid "Submit"
|
||||
msgstr "Valider"
|
||||
|
||||
|
@ -775,19 +779,19 @@ msgstr "Je ne suis pas %(username)s"
|
|||
msgid "Sign in"
|
||||
msgstr "Se connecter"
|
||||
|
||||
#: canaille/templates/profile.html:15
|
||||
#: canaille/templates/profile.html:18
|
||||
msgid "This user cannot edit this field"
|
||||
msgstr "Cet utilisateur ne peut pas éditer ce champ"
|
||||
|
||||
#: canaille/templates/profile.html:17
|
||||
#: canaille/templates/profile.html:20
|
||||
msgid "This user cannot see this field"
|
||||
msgstr "Cet utilisateur ne peut pas voir ce champ"
|
||||
|
||||
#: canaille/templates/profile.html:26
|
||||
#: canaille/templates/profile.html:29
|
||||
msgid "Account deletion"
|
||||
msgstr "Suppression d'un compte"
|
||||
|
||||
#: canaille/templates/profile.html:31
|
||||
#: canaille/templates/profile.html:34
|
||||
msgid ""
|
||||
"Are you sure you want to delete this user? This action is unrevokable and "
|
||||
"all the data about this user will be removed."
|
||||
|
@ -795,7 +799,7 @@ msgstr ""
|
|||
"Êtes-vous sûrs de vouloir supprimer cet utilisateur ? Cette action est "
|
||||
"irrévocable, et toutes les données de cet utilisateur seront supprimées."
|
||||
|
||||
#: canaille/templates/profile.html:33
|
||||
#: canaille/templates/profile.html:36
|
||||
msgid ""
|
||||
"Are you sure you want to delete your account? This action is unrevokable and "
|
||||
"all your data will be removed forever."
|
||||
|
@ -803,51 +807,55 @@ msgstr ""
|
|||
"Êtes-vous sûrs de vouloir supprimer votre compte ? Cette action est "
|
||||
"irrévocable et toutes vos données seront supprimées pour toujours."
|
||||
|
||||
#: canaille/templates/profile.html:48
|
||||
#: canaille/templates/profile.html:51
|
||||
msgid "User creation"
|
||||
msgstr "Nouvel utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:50 canaille/themes/default/base.html:39
|
||||
#: canaille/templates/profile.html:53 canaille/themes/default/base.html:39
|
||||
msgid "My profile"
|
||||
msgstr "Mon profil"
|
||||
|
||||
#: canaille/templates/profile.html:52
|
||||
#: canaille/templates/profile.html:55
|
||||
msgid "User profile edition"
|
||||
msgstr "Édition d'un profil utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:58
|
||||
#: canaille/templates/profile.html:61
|
||||
msgid "Create a new user account"
|
||||
msgstr "Création d'un nouveau compte utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:60
|
||||
#: canaille/templates/profile.html:63
|
||||
msgid "Edit your personal informations"
|
||||
msgstr "Éditez vos informations personnelles"
|
||||
|
||||
#: canaille/templates/profile.html:62
|
||||
#: canaille/templates/profile.html:65
|
||||
msgid "Edit informations about an user"
|
||||
msgstr "Éditez les informations d'un utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:77
|
||||
#: canaille/templates/profile.html:80
|
||||
msgid "Personal information"
|
||||
msgstr "Informations personnelles"
|
||||
|
||||
#: canaille/templates/profile.html:99
|
||||
#: canaille/templates/profile.html:88 canaille/templates/profile.html:99
|
||||
msgid "Click to upload a photo"
|
||||
msgstr "Cliquez pour mettre en ligne une photo"
|
||||
|
||||
#: canaille/templates/profile.html:126
|
||||
msgid "Account information"
|
||||
msgstr "Informations sur le compte"
|
||||
|
||||
#: canaille/templates/profile.html:117
|
||||
#: canaille/templates/profile.html:144
|
||||
msgid "User password is not mandatory"
|
||||
msgstr "Le mot de passe utilisateur n'est pas requis à la création"
|
||||
|
||||
#: canaille/templates/profile.html:120
|
||||
#: canaille/templates/profile.html:147
|
||||
msgid "The user password can be set:"
|
||||
msgstr "Il pourra être renseigné :"
|
||||
|
||||
#: canaille/templates/profile.html:122
|
||||
#: canaille/templates/profile.html:149
|
||||
msgid "by filling this form;"
|
||||
msgstr "en remplissant ce formulaire ;"
|
||||
|
||||
#: canaille/templates/profile.html:123
|
||||
#: canaille/templates/profile.html:150
|
||||
msgid ""
|
||||
"by sending the user a password initialization mail, after the account "
|
||||
"creation;"
|
||||
|
@ -855,7 +863,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:124 canaille/templates/profile.html:153
|
||||
#: canaille/templates/profile.html:151 canaille/templates/profile.html:180
|
||||
msgid ""
|
||||
"or simply waiting for the user to sign-in a first time, and then receive a "
|
||||
"password initialization mail."
|
||||
|
@ -863,46 +871,46 @@ 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:127 canaille/templates/profile.html:156
|
||||
#: canaille/templates/profile.html:154 canaille/templates/profile.html:183
|
||||
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 "
|
||||
"défini"
|
||||
|
||||
#: canaille/templates/profile.html:141
|
||||
#: canaille/templates/profile.html:168
|
||||
msgid "Send email"
|
||||
msgstr "Envoyer l'email"
|
||||
|
||||
#: canaille/templates/profile.html:146
|
||||
#: canaille/templates/profile.html:173
|
||||
msgid "This user does not have a password yet"
|
||||
msgstr "L'utilisateur n'a pas encore de mot de passe"
|
||||
|
||||
#: canaille/templates/profile.html:149
|
||||
#: canaille/templates/profile.html:176
|
||||
msgid "You can solve this by:"
|
||||
msgstr "Vous pouvez régler ceci en :"
|
||||
|
||||
#: canaille/templates/profile.html:151
|
||||
#: canaille/templates/profile.html:178
|
||||
msgid "setting a password using this form;"
|
||||
msgstr "renseignant un mot de passe via ce formulaire ;"
|
||||
|
||||
#: canaille/templates/profile.html:152
|
||||
#: canaille/templates/profile.html:179
|
||||
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:167
|
||||
#: canaille/templates/profile.html:194
|
||||
msgid "Send mail"
|
||||
msgstr "Envoyer l'email"
|
||||
|
||||
#: canaille/templates/admin/mails.html:34 canaille/templates/profile.html:171
|
||||
#: canaille/templates/admin/mails.html:34 canaille/templates/profile.html:198
|
||||
#: 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:173
|
||||
#: canaille/templates/profile.html:200
|
||||
msgid ""
|
||||
"If the user has forgotten his password, you can send him a password reset "
|
||||
"email by clicking this button."
|
||||
|
@ -910,19 +918,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:185
|
||||
#: canaille/templates/profile.html:212
|
||||
msgid "Delete the user"
|
||||
msgstr "Supprimer l'utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:187
|
||||
#: canaille/templates/profile.html:214
|
||||
msgid "Delete my account"
|
||||
msgstr "Supprimer mon compte"
|
||||
|
||||
#: canaille/templates/profile.html:194
|
||||
#: canaille/templates/profile.html:221
|
||||
msgid "Impersonate"
|
||||
msgstr "Prendre l'identité"
|
||||
|
||||
#: canaille/templates/profile.html:200 canaille/templates/users.html:19
|
||||
#: canaille/templates/profile.html:227 canaille/templates/users.html:19
|
||||
msgid "Invite a user"
|
||||
msgstr "Inviter un utilisateur"
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2021-12-07 19:58+0100\n"
|
||||
"POT-Creation-Date: 2021-12-08 18:56+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"
|
||||
|
@ -17,114 +17,114 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: canaille/__init__.py:123
|
||||
#: canaille/__init__.py:129
|
||||
msgid "Could not connect to the LDAP server '{uri}'"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/__init__.py:139
|
||||
#: canaille/__init__.py:145
|
||||
msgid "LDAP authentication failed with user '{user}'"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:69 canaille/account.py:94 canaille/oauth.py:74
|
||||
#: canaille/account.py:77 canaille/account.py:102 canaille/oauth.py:74
|
||||
msgid "Login failed, please check your information"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:100
|
||||
#: canaille/account.py:108
|
||||
#, python-format
|
||||
msgid "Connection successful. Welcome %(user)s"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:113
|
||||
#: canaille/account.py:121
|
||||
#, python-format
|
||||
msgid "You have been disconnected. See you next time %(user)s"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:130
|
||||
#: canaille/account.py:138
|
||||
msgid "Could not send the password initialization link."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:135
|
||||
#: canaille/account.py:143
|
||||
msgid ""
|
||||
"A password initialization link has been sent at your email address. You "
|
||||
"should receive it within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:141 canaille/account.py:326
|
||||
#: canaille/account.py:149 canaille/account.py:340
|
||||
msgid "Could not send the password initialization email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:192 canaille/account.py:264
|
||||
#: canaille/account.py:204 canaille/account.py:275
|
||||
msgid "User account creation failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:213 canaille/account.py:234
|
||||
#: canaille/account.py:225 canaille/account.py:246
|
||||
msgid "The invitation link that brought you here was invalid."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:220
|
||||
#: canaille/account.py:232
|
||||
msgid "Your account has already been created."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:227
|
||||
#: canaille/account.py:239
|
||||
msgid "You are already logged in, you cannot create an account."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:269
|
||||
#: canaille/account.py:280
|
||||
msgid "You account has been created successfuly."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:299
|
||||
#: canaille/account.py:313
|
||||
msgid "User account creation succeed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:320
|
||||
#: canaille/account.py:334
|
||||
msgid ""
|
||||
"A password initialization link has been sent at the user email address. "
|
||||
"It should be received within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:334
|
||||
#: canaille/account.py:348
|
||||
msgid ""
|
||||
"A password reset link has been sent at the user email address. It should "
|
||||
"be received within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:340
|
||||
#: canaille/account.py:354
|
||||
msgid "Could not send the password reset email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:371
|
||||
#: canaille/account.py:385
|
||||
msgid "Profile edition failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:396
|
||||
#: canaille/account.py:413
|
||||
msgid "Profile updated successfuly."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:416
|
||||
#: canaille/account.py:433
|
||||
#, python-format
|
||||
msgid "The user %(user)s has been sucessfuly deleted"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:440
|
||||
#: canaille/account.py:457
|
||||
msgid "Could not send the password reset link."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:447 canaille/account.py:458
|
||||
#: canaille/account.py:464 canaille/account.py:475
|
||||
msgid ""
|
||||
"A password reset link has been sent at your email address. You should "
|
||||
"receive it within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:464
|
||||
#: canaille/account.py:481
|
||||
msgid "Could not reset your password"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:478
|
||||
#: canaille/account.py:495
|
||||
msgid "The password reset link that brought you here was invalid."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:487
|
||||
#: canaille/account.py:504
|
||||
msgid "Your password has been updated successfuly"
|
||||
msgstr ""
|
||||
|
||||
|
@ -132,7 +132,7 @@ msgstr ""
|
|||
msgid "John Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/apputils.py:37 canaille/forms.py:93 canaille/forms.py:188
|
||||
#: canaille/apputils.py:37 canaille/forms.py:93 canaille/forms.py:196
|
||||
msgid "jdoe"
|
||||
msgstr ""
|
||||
|
||||
|
@ -152,7 +152,7 @@ msgstr ""
|
|||
msgid "The access has been revoked"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/flaskutils.py:69
|
||||
#: canaille/flaskutils.py:70
|
||||
msgid "No SMTP server has been configured"
|
||||
msgstr ""
|
||||
|
||||
|
@ -178,27 +178,27 @@ msgid "Login"
|
|||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:45 canaille/forms.py:69 canaille/forms.py:117
|
||||
#: canaille/forms.py:199
|
||||
#: canaille/forms.py:207
|
||||
msgid "jane@doe.com"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:55 canaille/forms.py:78 canaille/forms.py:127
|
||||
#: canaille/forms.py:55 canaille/forms.py:78 canaille/forms.py:132
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:81 canaille/forms.py:131
|
||||
#: canaille/forms.py:81 canaille/forms.py:136
|
||||
msgid "Password confirmation"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:84 canaille/forms.py:134
|
||||
#: canaille/forms.py:84 canaille/forms.py:139
|
||||
msgid "Password and confirmation do not match."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:92 canaille/forms.py:187
|
||||
#: canaille/forms.py:92 canaille/forms.py:195
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/admin/clients.py:28 canaille/forms.py:96 canaille/forms.py:177
|
||||
#: canaille/admin/clients.py:28 canaille/forms.py:96 canaille/forms.py:185
|
||||
#: canaille/templates/admin/client_list.html:22
|
||||
#: canaille/templates/group.html:91 canaille/templates/users.html:27
|
||||
msgid "Name"
|
||||
|
@ -220,7 +220,7 @@ msgstr ""
|
|||
msgid "Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:114 canaille/forms.py:192
|
||||
#: canaille/forms.py:114 canaille/forms.py:200
|
||||
msgid "Email address"
|
||||
msgstr ""
|
||||
|
||||
|
@ -232,25 +232,29 @@ msgstr ""
|
|||
msgid "555-000-555"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:125
|
||||
#: canaille/forms.py:126
|
||||
msgid "Photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:139
|
||||
#: canaille/forms.py:130 canaille/templates/profile.html:91
|
||||
msgid "Delete the photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:144
|
||||
msgid "Number"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:141
|
||||
#: canaille/forms.py:146
|
||||
msgid "1234"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:162 canaille/forms.py:205 canaille/templates/group.html:93
|
||||
#: canaille/forms.py:170 canaille/forms.py:213 canaille/templates/group.html:93
|
||||
#: canaille/templates/groups.html:9 canaille/templates/users.html:29
|
||||
#: canaille/themes/default/base.html:59
|
||||
msgid "Groups"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:180
|
||||
#: canaille/forms.py:188
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
|
@ -533,11 +537,11 @@ msgstr ""
|
|||
#: canaille/templates/admin/client_edit.html:35
|
||||
#: canaille/templates/admin/client_edit.html:44
|
||||
#: canaille/templates/admin/client_edit.html:53
|
||||
#: canaille/templates/fomanticui.html:46
|
||||
#: canaille/templates/fomanticui.html:48
|
||||
msgid "This field is not editable"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/fomanticui.html:50
|
||||
#: canaille/templates/fomanticui.html:52
|
||||
msgid "This field is required"
|
||||
msgstr ""
|
||||
|
||||
|
@ -558,7 +562,7 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: canaille/templates/forgotten-password.html:38
|
||||
#: canaille/templates/profile.html:137 canaille/templates/profile.html:165
|
||||
#: canaille/templates/profile.html:164 canaille/templates/profile.html:192
|
||||
msgid "Send again"
|
||||
msgstr ""
|
||||
|
||||
|
@ -577,12 +581,12 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: canaille/templates/admin/client_edit.html:18
|
||||
#: canaille/templates/group.html:29 canaille/templates/profile.html:38
|
||||
#: canaille/templates/group.html:29 canaille/templates/profile.html:41
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/admin/client_edit.html:19
|
||||
#: canaille/templates/group.html:30 canaille/templates/profile.html:39
|
||||
#: canaille/templates/group.html:30 canaille/templates/profile.html:42
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
|
@ -617,7 +621,7 @@ msgstr ""
|
|||
msgid "Create group"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/group.html:79 canaille/templates/profile.html:205
|
||||
#: canaille/templates/group.html:79 canaille/templates/profile.html:232
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
|
@ -735,139 +739,143 @@ msgstr ""
|
|||
msgid "Sign in"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:15
|
||||
#: canaille/templates/profile.html:18
|
||||
msgid "This user cannot edit this field"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:17
|
||||
#: canaille/templates/profile.html:20
|
||||
msgid "This user cannot see this field"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:26
|
||||
#: canaille/templates/profile.html:29
|
||||
msgid "Account deletion"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:31
|
||||
#: canaille/templates/profile.html:34
|
||||
msgid ""
|
||||
"Are you sure you want to delete this user? This action is unrevokable and"
|
||||
" all the data about this user will be removed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:33
|
||||
#: canaille/templates/profile.html:36
|
||||
msgid ""
|
||||
"Are you sure you want to delete your account? This action is unrevokable "
|
||||
"and all your data will be removed forever."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:48
|
||||
#: canaille/templates/profile.html:51
|
||||
msgid "User creation"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:50 canaille/themes/default/base.html:39
|
||||
#: canaille/templates/profile.html:53 canaille/themes/default/base.html:39
|
||||
msgid "My profile"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:52
|
||||
#: canaille/templates/profile.html:55
|
||||
msgid "User profile edition"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:58
|
||||
#: canaille/templates/profile.html:61
|
||||
msgid "Create a new user account"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:60
|
||||
#: canaille/templates/profile.html:63
|
||||
msgid "Edit your personal informations"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:62
|
||||
#: canaille/templates/profile.html:65
|
||||
msgid "Edit informations about an user"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:77
|
||||
#: canaille/templates/profile.html:80
|
||||
msgid "Personal information"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:99
|
||||
#: canaille/templates/profile.html:88 canaille/templates/profile.html:99
|
||||
msgid "Click to upload a photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:126
|
||||
msgid "Account information"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:117
|
||||
#: canaille/templates/profile.html:144
|
||||
msgid "User password is not mandatory"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:120
|
||||
#: canaille/templates/profile.html:147
|
||||
msgid "The user password can be set:"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:122
|
||||
#: canaille/templates/profile.html:149
|
||||
msgid "by filling this form;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:123
|
||||
#: canaille/templates/profile.html:150
|
||||
msgid ""
|
||||
"by sending the user a password initialization mail, after the account "
|
||||
"creation;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:124 canaille/templates/profile.html:153
|
||||
#: canaille/templates/profile.html:151 canaille/templates/profile.html:180
|
||||
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:127 canaille/templates/profile.html:156
|
||||
#: canaille/templates/profile.html:154 canaille/templates/profile.html:183
|
||||
msgid "The user will not be able to authenticate unless the password is set"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:141
|
||||
#: canaille/templates/profile.html:168
|
||||
msgid "Send email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:146
|
||||
#: canaille/templates/profile.html:173
|
||||
msgid "This user does not have a password yet"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:149
|
||||
#: canaille/templates/profile.html:176
|
||||
msgid "You can solve this by:"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:151
|
||||
#: canaille/templates/profile.html:178
|
||||
msgid "setting a password using this form;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:152
|
||||
#: canaille/templates/profile.html:179
|
||||
msgid "sending the user a password initialization mail, by clicking this button;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:167
|
||||
#: canaille/templates/profile.html:194
|
||||
msgid "Send mail"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/admin/mails.html:34 canaille/templates/profile.html:171
|
||||
#: canaille/templates/admin/mails.html:34 canaille/templates/profile.html:198
|
||||
#: canaille/templates/reset-password.html:11
|
||||
#: canaille/templates/reset-password.html:16
|
||||
msgid "Password reset"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:173
|
||||
#: canaille/templates/profile.html:200
|
||||
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:185
|
||||
#: canaille/templates/profile.html:212
|
||||
msgid "Delete the user"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:187
|
||||
#: canaille/templates/profile.html:214
|
||||
msgid "Delete my account"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:194
|
||||
#: canaille/templates/profile.html:221
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:200 canaille/templates/users.html:19
|
||||
#: canaille/templates/profile.html:227 canaille/templates/users.html:19
|
||||
msgid "Invite a user"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -113,9 +113,9 @@ GROUP_USER_FILTER = "member={user.dn}"
|
|||
# The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
|
||||
# object that users will be able to read and/or write.
|
||||
[ACL.DEFAULT]
|
||||
READ = ["uid", "groups"]
|
||||
PERMISSIONS = ["use_oidc"]
|
||||
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail"]
|
||||
|
||||
[ACL.ADMIN]
|
||||
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"
|
||||
|
@ -154,7 +154,7 @@ GIVEN_NAME = "givenName"
|
|||
FAMILY_NAME = "sn"
|
||||
PREFERRED_USERNAME = "displayName"
|
||||
LOCALE = "preferredLanguage"
|
||||
PICTURE = "photo"
|
||||
PICTURE = "jpegPhoto"
|
||||
ADDRESS = "postalAddress"
|
||||
|
||||
# The SMTP server options. If not set, mail related features such as
|
||||
|
|
|
@ -151,6 +151,7 @@ def configuration(slapd_server, smtpd, keypair_path):
|
|||
"WRITE": [
|
||||
"mail",
|
||||
"givenName",
|
||||
"jpegPhoto",
|
||||
"sn",
|
||||
"userPassword",
|
||||
"telephoneNumber",
|
||||
|
@ -446,3 +447,8 @@ def bar_group(app, admin, slapd_connection):
|
|||
yield g
|
||||
admin._groups = []
|
||||
g.delete(conn=slapd_connection)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def jpeg_photo():
|
||||
return b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x01,\x01,\x00\x00\xff\xfe\x00\x13Created with GIMP\xff\xe2\x02\xb0ICC_PROFILE\x00\x01\x01\x00\x00\x02\xa0lcms\x040\x00\x00mntrRGB XYZ \x07\xe5\x00\x0c\x00\x08\x00\x0f\x00\x16\x00(acspAPPL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xd6\x00\x01\x00\x00\x00\x00\xd3-lcms\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\rdesc\x00\x00\x01 \x00\x00\x00@cprt\x00\x00\x01`\x00\x00\x006wtpt\x00\x00\x01\x98\x00\x00\x00\x14chad\x00\x00\x01\xac\x00\x00\x00,rXYZ\x00\x00\x01\xd8\x00\x00\x00\x14bXYZ\x00\x00\x01\xec\x00\x00\x00\x14gXYZ\x00\x00\x02\x00\x00\x00\x00\x14rTRC\x00\x00\x02\x14\x00\x00\x00 gTRC\x00\x00\x02\x14\x00\x00\x00 bTRC\x00\x00\x02\x14\x00\x00\x00 chrm\x00\x00\x024\x00\x00\x00$dmnd\x00\x00\x02X\x00\x00\x00$dmdd\x00\x00\x02|\x00\x00\x00$mluc\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0cenUS\x00\x00\x00$\x00\x00\x00\x1c\x00G\x00I\x00M\x00P\x00 \x00b\x00u\x00i\x00l\x00t\x00-\x00i\x00n\x00 \x00s\x00R\x00G\x00Bmluc\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0cenUS\x00\x00\x00\x1a\x00\x00\x00\x1c\x00P\x00u\x00b\x00l\x00i\x00c\x00 \x00D\x00o\x00m\x00a\x00i\x00n\x00\x00XYZ \x00\x00\x00\x00\x00\x00\xf6\xd6\x00\x01\x00\x00\x00\x00\xd3-sf32\x00\x00\x00\x00\x00\x01\x0cB\x00\x00\x05\xde\xff\xff\xf3%\x00\x00\x07\x93\x00\x00\xfd\x90\xff\xff\xfb\xa1\xff\xff\xfd\xa2\x00\x00\x03\xdc\x00\x00\xc0nXYZ \x00\x00\x00\x00\x00\x00o\xa0\x00\x008\xf5\x00\x00\x03\x90XYZ \x00\x00\x00\x00\x00\x00$\x9f\x00\x00\x0f\x84\x00\x00\xb6\xc4XYZ \x00\x00\x00\x00\x00\x00b\x97\x00\x00\xb7\x87\x00\x00\x18\xd9para\x00\x00\x00\x00\x00\x03\x00\x00\x00\x02ff\x00\x00\xf2\xa7\x00\x00\rY\x00\x00\x13\xd0\x00\x00\n[chrm\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\xa3\xd7\x00\x00T|\x00\x00L\xcd\x00\x00\x99\x9a\x00\x00&g\x00\x00\x0f\\mluc\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0cenUS\x00\x00\x00\x08\x00\x00\x00\x1c\x00G\x00I\x00M\x00Pmluc\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0cenUS\x00\x00\x00\x08\x00\x00\x00\x1c\x00s\x00R\x00G\x00B\xff\xdb\x00C\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\xff\xdb\x00C\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\xff\xc2\x00\x11\x08\x00\x01\x00\x01\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x14\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\xff\xc4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x0c\x03\x01\x00\x02\x10\x03\x10\x00\x00\x01\x7f\x0f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x01\x05\x02\x7f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x03\x01\x01?\x01\x7f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x02\x01\x01?\x01\x7f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x06?\x02\x7f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x01?!\x7f\xff\xda\x00\x0c\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x03\x01\x01?\x10\x7f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x02\x01\x01?\x10\x7f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x01?\x10\x7f\xff\xd9"
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
from canaille.models import User
|
||||
from webtest import Upload
|
||||
|
||||
|
||||
def test_edition(
|
||||
testclient, slapd_server, slapd_connection, logged_user, admin, foo_group, bar_group
|
||||
testclient,
|
||||
slapd_server,
|
||||
slapd_connection,
|
||||
logged_user,
|
||||
admin,
|
||||
foo_group,
|
||||
bar_group,
|
||||
jpeg_photo,
|
||||
):
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert set(res.form["groups"].options) == set(
|
||||
|
@ -27,6 +35,7 @@ def test_edition(
|
|||
"cn=foo,ou=groups,dc=slapd-test,dc=python-ldap,dc=org",
|
||||
"cn=bar,ou=groups,dc=slapd-test,dc=python-ldap,dc=org",
|
||||
]
|
||||
res.form["jpegPhoto"] = Upload("logo.jpg", jpeg_photo)
|
||||
res = res.form.submit(name="action", value="edit", status=200)
|
||||
assert "Profile updated successfuly." in res, str(res)
|
||||
|
||||
|
@ -40,6 +49,7 @@ def test_edition(
|
|||
assert ["email@mydomain.tld"] == logged_user.mail
|
||||
assert ["555-666-777"] == logged_user.telephoneNumber
|
||||
assert "666" == logged_user.employeeNumber
|
||||
assert [jpeg_photo] == logged_user.jpegPhoto
|
||||
|
||||
foo_group.reload(slapd_connection)
|
||||
bar_group.reload(slapd_connection)
|
||||
|
@ -312,3 +322,58 @@ def test_email_reset_button(smtpd, testclient, slapd_connection, logged_admin):
|
|||
)
|
||||
assert "Send again" in res
|
||||
assert len(smtpd.messages) == 1
|
||||
|
||||
|
||||
def test_photo_edition(
|
||||
testclient,
|
||||
slapd_server,
|
||||
slapd_connection,
|
||||
logged_user,
|
||||
jpeg_photo,
|
||||
):
|
||||
|
||||
# Add a photo
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
res.form["jpegPhoto"] = Upload("logo.jpg", jpeg_photo)
|
||||
res.form["jpegPhoto_delete"] = False
|
||||
res = res.form.submit(name="action", value="edit", status=200)
|
||||
assert "Profile updated successfuly." in res, str(res)
|
||||
|
||||
with testclient.app.app_context():
|
||||
logged_user = User.get(dn=logged_user.dn, conn=slapd_connection)
|
||||
|
||||
assert [jpeg_photo] == logged_user.jpegPhoto
|
||||
|
||||
# No change
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
res.form["jpegPhoto_delete"] = False
|
||||
res = res.form.submit(name="action", value="edit", status=200)
|
||||
assert "Profile updated successfuly." in res, str(res)
|
||||
|
||||
with testclient.app.app_context():
|
||||
logged_user = User.get(dn=logged_user.dn, conn=slapd_connection)
|
||||
|
||||
assert [jpeg_photo] == logged_user.jpegPhoto
|
||||
|
||||
# Photo deletion
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
res.form["jpegPhoto_delete"] = True
|
||||
res = res.form.submit(name="action", value="edit", status=200)
|
||||
assert "Profile updated successfuly." in res, str(res)
|
||||
|
||||
with testclient.app.app_context():
|
||||
logged_user = User.get(dn=logged_user.dn, conn=slapd_connection)
|
||||
|
||||
assert [] == logged_user.jpegPhoto
|
||||
|
||||
# Photo deletion AND upload, this should never happen
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
res.form["jpegPhoto"] = Upload("logo.jpg", jpeg_photo)
|
||||
res.form["jpegPhoto_delete"] = True
|
||||
res = res.form.submit(name="action", value="edit", status=200)
|
||||
assert "Profile updated successfuly." in res, str(res)
|
||||
|
||||
with testclient.app.app_context():
|
||||
logged_user = User.get(dn=logged_user.dn, conn=slapd_connection)
|
||||
|
||||
assert [] == logged_user.jpegPhoto
|
||||
|
|
Loading…
Reference in a new issue