forked from Github-Mirrors/canaille
feat: group member removal can be achieved from the group edition page
This commit is contained in:
parent
69b565e1ad
commit
69019763d4
9 changed files with 410 additions and 77 deletions
|
@ -1,3 +1,7 @@
|
|||
Added
|
||||
^^^^^
|
||||
- Group member removal can be achieved from the group edition page :issue:`192`
|
||||
|
||||
Changed
|
||||
^^^^^^^
|
||||
- Model `identifier_attributes` are fixed.
|
||||
|
|
|
@ -251,12 +251,15 @@ def set_writable(field):
|
|||
|
||||
|
||||
class IDToModel:
|
||||
def __init__(self, model_name):
|
||||
def __init__(self, model_name, raise_on_errors=True):
|
||||
self.model_name = model_name
|
||||
self.raise_on_errors = raise_on_errors
|
||||
|
||||
def __call__(self, data):
|
||||
model = getattr(models, self.model_name)
|
||||
instance = data if isinstance(data, model) else model.get(data)
|
||||
if not instance:
|
||||
if instance:
|
||||
return instance
|
||||
|
||||
if self.raise_on_errors:
|
||||
raise wtforms.ValidationError()
|
||||
return instance
|
||||
|
|
|
@ -15,6 +15,7 @@ from canaille.app.forms import is_uri
|
|||
from canaille.app.forms import phone_number
|
||||
from canaille.app.forms import set_readonly
|
||||
from canaille.app.forms import unique_values
|
||||
from canaille.app.i18n import gettext
|
||||
from canaille.app.i18n import lazy_gettext as _
|
||||
from canaille.app.i18n import native_language_name_from_code
|
||||
from canaille.backends import BaseBackend
|
||||
|
@ -56,6 +57,20 @@ def existing_login(form, field):
|
|||
)
|
||||
|
||||
|
||||
def existing_group_member(form, field):
|
||||
if field.data is None:
|
||||
raise wtforms.ValidationError(
|
||||
gettext("The user you are trying to remove does not exist.")
|
||||
)
|
||||
|
||||
if field.data not in form.group.members:
|
||||
raise wtforms.ValidationError(
|
||||
gettext(
|
||||
"The user '{user}' has already been removed from the group '{group}'"
|
||||
).format(user=field.data.formatted_name, group=form.group.display_name)
|
||||
)
|
||||
|
||||
|
||||
def non_empty_groups(form, field):
|
||||
"""LDAP groups cannot be empty because groupOfNames.member is a MUST
|
||||
attribute.
|
||||
|
@ -373,6 +388,13 @@ class EditGroupForm(Form):
|
|||
)
|
||||
|
||||
|
||||
class DeleteGroupMemberForm(Form):
|
||||
member = wtforms.StringField(
|
||||
filters=[IDToModel("User", raise_on_errors=False)],
|
||||
validators=[existing_group_member],
|
||||
)
|
||||
|
||||
|
||||
class JoinForm(Form):
|
||||
email = wtforms.EmailField(
|
||||
_("Email address"),
|
||||
|
|
|
@ -13,6 +13,7 @@ from canaille.app.i18n import gettext as _
|
|||
from canaille.app.themes import render_template
|
||||
|
||||
from .forms import CreateGroupForm
|
||||
from .forms import DeleteGroupMemberForm
|
||||
from .forms import EditGroupForm
|
||||
|
||||
bp = Blueprint("groups", __name__, url_prefix="/groups")
|
||||
|
@ -72,6 +73,12 @@ def group(user, group):
|
|||
if request.form.get("action") == "delete":
|
||||
return delete_group(group)
|
||||
|
||||
if request.form.get("action") == "confirm-remove-member":
|
||||
return delete_member(group)
|
||||
|
||||
if request.form.get("action") == "remove-member":
|
||||
return delete_member(group)
|
||||
|
||||
abort(400, f"bad form action: {request.form.get('action')}")
|
||||
|
||||
|
||||
|
@ -88,7 +95,11 @@ def edit_group(group):
|
|||
},
|
||||
)
|
||||
|
||||
if request.form and not request.form.get("page"):
|
||||
if (
|
||||
request.form
|
||||
and request.form.get("action") == "edit"
|
||||
and not request.form.get("page")
|
||||
):
|
||||
if form.validate():
|
||||
group.description = form.description.data
|
||||
group.save()
|
||||
|
@ -105,7 +116,7 @@ def edit_group(group):
|
|||
|
||||
return render_htmx_template(
|
||||
"group.html",
|
||||
"partial/users.html",
|
||||
"partial/group-members.html",
|
||||
form=form,
|
||||
menuitem="groups",
|
||||
edited_group=group,
|
||||
|
@ -113,6 +124,36 @@ def edit_group(group):
|
|||
)
|
||||
|
||||
|
||||
def delete_member(group):
|
||||
form = DeleteGroupMemberForm(request.form or None)
|
||||
form.group = group
|
||||
|
||||
if not form.validate():
|
||||
flash(
|
||||
"\n".join(form.errors.get("member")),
|
||||
"error",
|
||||
)
|
||||
|
||||
elif request.form.get("action") == "confirm-remove-member":
|
||||
return render_template(
|
||||
"modals/remove-group-member.html", group=group, form=form
|
||||
)
|
||||
|
||||
else:
|
||||
flash(
|
||||
_(
|
||||
f"{form.member.data.formatted_name} has been removed from the group {group.display_name}"
|
||||
),
|
||||
"success",
|
||||
)
|
||||
group.members = [
|
||||
member for member in group.members if member != form.member.data
|
||||
]
|
||||
group.save()
|
||||
|
||||
return edit_group(group)
|
||||
|
||||
|
||||
def delete_group(group):
|
||||
flash(
|
||||
_("The group %(group)s has been sucessfully deleted", group=group.display_name),
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
|
||||
{{ table.search(table_form, "table.users") }}
|
||||
</div>
|
||||
{% include "partial/users.html" %}
|
||||
{% include "partial/group-members.html" %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
31
canaille/core/templates/modals/remove-group-member.html
Normal file
31
canaille/core/templates/modals/remove-group-member.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import 'macro/form.html' as fui %}
|
||||
|
||||
{% block content %}
|
||||
<div class="ui warning message" id="modal-remove-member">
|
||||
{% call fui.render_form(form) %}
|
||||
<input type="hidden" name="member" value="{{ form.member.data }}">
|
||||
<div class="ui icon header">
|
||||
<i class="user minus alternate icon"></i>
|
||||
{% trans %}Group member deletion{% endtrans %}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>
|
||||
{% trans group_name=group.display_name, user_name=form.member.data.formatted_name %}
|
||||
Are you sure you want to remove {{ user_name }} from the group "{{ group_name }}"?
|
||||
{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui center aligned container">
|
||||
<div class="ui stackable buttons">
|
||||
<a href="{{ request.url }}" class="ui cancel button">
|
||||
{% trans %}Cancel{% endtrans %}
|
||||
</a>
|
||||
<button name="action" value="remove-member" id="remove-member" class="ui red approve button">
|
||||
{% trans %}Remove{% endtrans %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endcall %}
|
||||
</div>
|
||||
{% endblock %}
|
104
canaille/core/templates/partial/group-members.html
Normal file
104
canaille/core/templates/partial/group-members.html
Normal file
|
@ -0,0 +1,104 @@
|
|||
{% import "macro/table.html" as table %}
|
||||
<table class="ui bottom attached table users">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if user.can_read("photo") %}
|
||||
<th></th>
|
||||
{% endif %}
|
||||
{% if user.can_read("user_name") %}
|
||||
<th>{% trans %}Login{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if user.can_read("family_name") or user.can_read("given_name") %}
|
||||
<th>{% trans %}Name{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if user.can_manage_groups %}
|
||||
<th>{% trans %}Groups{% endtrans %}</th>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for watched_user in table_form.items_slice %}
|
||||
<tr>
|
||||
{% if user.can_read("photo") %}
|
||||
<td class="collapsing">
|
||||
<a href="{{ url_for('core.account.profile_edition', edited_user=watched_user) }}">
|
||||
{% if user.can_manage_users and watched_user.locked %}
|
||||
<i class="lock circle big black icon" title="{% trans %}This account is locked{% endtrans %}"></i>
|
||||
{% elif watched_user.photo and watched_user.photo %}
|
||||
<img class="ui avatar image" src="{{ url_for("core.account.photo", user=watched_user, field="photo") }}" alt="User photo">
|
||||
{% else %}
|
||||
<i class="user circle big black icon"></i>
|
||||
{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if user.can_read("user_name") %}
|
||||
<td>
|
||||
<a href="{{ url_for('core.account.profile_edition', edited_user=watched_user) }}">
|
||||
{% if watched_user.user_name %}
|
||||
{{ watched_user.user_name }}
|
||||
{% else %}
|
||||
{{ watched_user.identifier }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if user.can_read("family_name") or user.can_read("given_name") %}
|
||||
<td>{{ watched_user.formatted_name }}</td>
|
||||
{% endif %}
|
||||
{% if user.can_manage_groups %}
|
||||
<td>
|
||||
{% for group in watched_user.groups %}
|
||||
<a class="ui label" href="{{ url_for('core.groups.group', group=group) }}"{% if group.description %} title="{{ group.description }}"{% endif %}>
|
||||
{{ group.display_name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% if edited_group.members|len > 1 %}
|
||||
<form id="deletegroupmemberform-{{ watched_user.id }}" action="{{ url_for(request.url_rule.endpoint, **request.view_args) }}" method="POST">
|
||||
{{ form.hidden_tag() if form.hidden_tag }}
|
||||
<input type="hidden" name="member" value="{{ watched_user.id }}">
|
||||
<button class="basic negative ui button" name="action" value="confirm-remove-member">
|
||||
{% trans %}Remove{% endtrans %}
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<button class="basic negative ui button" title="{% trans %}Groups must have at least one member{% endtrans %}" disabled>
|
||||
{% trans %}Remove{% endtrans %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="ui icon message">
|
||||
<i class="exclamation icon"></i>
|
||||
<div class="content">
|
||||
{% if request.headers.get("Hx-Request") %}
|
||||
<div class="header">
|
||||
{% trans %}No item matches your request{% endtrans %}
|
||||
</div>
|
||||
<p>{% trans %}Maybe try with different criterias?{% endtrans %}</p>
|
||||
{% else %}
|
||||
<div class="header">
|
||||
{% trans %}There is nothing here{% endtrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
{{ table.pagination(table_form) }}
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-04-27 14:07+0200\n"
|
||||
"POT-Creation-Date: 2024-04-28 19:05+0200\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"
|
||||
|
@ -53,8 +53,8 @@ msgstr ""
|
|||
msgid "John Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/backends/ldap/backend.py:176 canaille/core/endpoints/forms.py:149
|
||||
#: canaille/core/endpoints/forms.py:398
|
||||
#: canaille/backends/ldap/backend.py:176 canaille/core/endpoints/forms.py:164
|
||||
#: canaille/core/endpoints/forms.py:420
|
||||
msgid "jdoe"
|
||||
msgstr ""
|
||||
|
||||
|
@ -128,9 +128,10 @@ msgstr ""
|
|||
msgid "You are already logged in, you cannot create an account."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/account.py:297 canaille/core/endpoints/forms.py:298
|
||||
#: canaille/core/endpoints/forms.py:416 canaille/core/templates/groups.html:5
|
||||
#: canaille/core/endpoints/account.py:297 canaille/core/endpoints/forms.py:313
|
||||
#: canaille/core/endpoints/forms.py:438 canaille/core/templates/groups.html:5
|
||||
#: canaille/core/templates/groups.html:23
|
||||
#: canaille/core/templates/partial/group-members.html:15
|
||||
#: canaille/core/templates/partial/users.html:18
|
||||
#: canaille/templates/base.html:58
|
||||
msgid "Groups"
|
||||
|
@ -253,10 +254,10 @@ msgstr ""
|
|||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/admin.py:29 canaille/core/endpoints/forms.py:82
|
||||
#: canaille/core/endpoints/forms.py:105 canaille/core/endpoints/forms.py:194
|
||||
#: canaille/core/endpoints/forms.py:384 canaille/core/endpoints/forms.py:410
|
||||
#: canaille/core/endpoints/forms.py:431 canaille/core/endpoints/forms.py:447
|
||||
#: canaille/core/endpoints/admin.py:29 canaille/core/endpoints/forms.py:97
|
||||
#: canaille/core/endpoints/forms.py:120 canaille/core/endpoints/forms.py:209
|
||||
#: canaille/core/endpoints/forms.py:406 canaille/core/endpoints/forms.py:432
|
||||
#: canaille/core/endpoints/forms.py:453 canaille/core/endpoints/forms.py:469
|
||||
msgid "jane@doe.com"
|
||||
msgstr ""
|
||||
|
||||
|
@ -325,57 +326,67 @@ msgstr ""
|
|||
msgid "Your password has been updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:30
|
||||
#: canaille/core/endpoints/forms.py:31
|
||||
msgid "The user name '{user_name}' already exists"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:39
|
||||
#: canaille/core/endpoints/forms.py:40
|
||||
msgid "The email '{email}' is already used"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:46
|
||||
#: canaille/core/endpoints/forms.py:47
|
||||
msgid "The group '{group}' already exists"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:55
|
||||
#: canaille/core/endpoints/forms.py:56
|
||||
msgid "The login '{login}' does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:71
|
||||
#: canaille/core/endpoints/forms.py:63
|
||||
msgid "The user you are trying to remove does not exist."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:68
|
||||
msgid "The user '{user}' has already been removed from the group '{group}'"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:86
|
||||
msgid ""
|
||||
"The group '{group}' cannot be removed, because it must have at least one "
|
||||
"user left."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:79 canaille/core/endpoints/forms.py:102
|
||||
#: canaille/core/endpoints/forms.py:94 canaille/core/endpoints/forms.py:117
|
||||
#: canaille/core/templates/partial/group-members.html:9
|
||||
#: canaille/core/templates/partial/users.html:9
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:92 canaille/core/endpoints/forms.py:114
|
||||
#: canaille/core/endpoints/forms.py:248
|
||||
#: canaille/core/endpoints/forms.py:107 canaille/core/endpoints/forms.py:129
|
||||
#: canaille/core/endpoints/forms.py:263
|
||||
#: canaille/core/templates/profile_settings.html:63
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:121 canaille/core/endpoints/forms.py:258
|
||||
#: canaille/core/endpoints/forms.py:136 canaille/core/endpoints/forms.py:273
|
||||
msgid "Password confirmation"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:124 canaille/core/endpoints/forms.py:261
|
||||
#: canaille/core/endpoints/forms.py:139 canaille/core/endpoints/forms.py:276
|
||||
msgid "Password and confirmation do not match."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:143
|
||||
#: canaille/core/endpoints/forms.py:158
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:148
|
||||
#: canaille/core/endpoints/forms.py:163
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:152 canaille/core/endpoints/forms.py:347
|
||||
#: canaille/core/endpoints/forms.py:361
|
||||
#: canaille/core/endpoints/forms.py:167 canaille/core/endpoints/forms.py:362
|
||||
#: canaille/core/endpoints/forms.py:376
|
||||
#: canaille/core/templates/partial/group-members.html:12
|
||||
#: canaille/core/templates/partial/groups.html:6
|
||||
#: canaille/core/templates/partial/users.html:12
|
||||
#: canaille/oidc/endpoints/forms.py:26
|
||||
|
@ -383,187 +394,187 @@ msgstr ""
|
|||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:154
|
||||
#: canaille/core/endpoints/forms.py:169
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:154
|
||||
#: canaille/core/endpoints/forms.py:169
|
||||
msgid "Vice president"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:157
|
||||
#: canaille/core/endpoints/forms.py:172
|
||||
msgid "Given name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:159
|
||||
#: canaille/core/endpoints/forms.py:174
|
||||
msgid "John"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:165
|
||||
#: canaille/core/endpoints/forms.py:180
|
||||
msgid "Family Name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:168
|
||||
#: canaille/core/endpoints/forms.py:183
|
||||
msgid "Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:174
|
||||
#: canaille/core/endpoints/forms.py:189
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:177
|
||||
#: canaille/core/endpoints/forms.py:192
|
||||
msgid "Johnny"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:184 canaille/core/endpoints/forms.py:437
|
||||
#: canaille/core/endpoints/forms.py:199 canaille/core/endpoints/forms.py:459
|
||||
#: canaille/core/templates/profile_edit.html:176
|
||||
msgid "Email addresses"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:190 canaille/core/endpoints/forms.py:427
|
||||
#: canaille/core/endpoints/forms.py:205 canaille/core/endpoints/forms.py:449
|
||||
msgid ""
|
||||
"This email will be used as a recovery address to reset the password if "
|
||||
"needed"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:204
|
||||
#: canaille/core/endpoints/forms.py:219
|
||||
msgid "Phone numbers"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:205
|
||||
#: canaille/core/endpoints/forms.py:220
|
||||
msgid "555-000-555"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:212
|
||||
#: canaille/core/endpoints/forms.py:227
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:214
|
||||
#: canaille/core/endpoints/forms.py:229
|
||||
msgid "132, Foobar Street, Gotham City 12401, XX"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:218
|
||||
#: canaille/core/endpoints/forms.py:233
|
||||
msgid "Street"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:220
|
||||
#: canaille/core/endpoints/forms.py:235
|
||||
msgid "132, Foobar Street"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:224
|
||||
#: canaille/core/endpoints/forms.py:239
|
||||
msgid "Postal Code"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:230
|
||||
#: canaille/core/endpoints/forms.py:245
|
||||
msgid "Locality"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:232
|
||||
#: canaille/core/endpoints/forms.py:247
|
||||
msgid "Gotham City"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:236
|
||||
#: canaille/core/endpoints/forms.py:251
|
||||
msgid "Region"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:238
|
||||
#: canaille/core/endpoints/forms.py:253
|
||||
msgid "North Pole"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:242
|
||||
#: canaille/core/endpoints/forms.py:257
|
||||
msgid "Photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:246
|
||||
#: canaille/core/endpoints/forms.py:261
|
||||
#: canaille/core/templates/profile_add.html:56
|
||||
#: canaille/core/templates/profile_edit.html:64
|
||||
msgid "Delete the photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:269
|
||||
#: canaille/core/endpoints/forms.py:284
|
||||
msgid "User number"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:271 canaille/core/endpoints/forms.py:277
|
||||
#: canaille/core/endpoints/forms.py:286 canaille/core/endpoints/forms.py:292
|
||||
msgid "1234"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:275
|
||||
#: canaille/core/endpoints/forms.py:290
|
||||
msgid "Department"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:281
|
||||
#: canaille/core/endpoints/forms.py:296
|
||||
msgid "Organization"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:283
|
||||
#: canaille/core/endpoints/forms.py:298
|
||||
msgid "Cogip LTD."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:287
|
||||
#: canaille/core/endpoints/forms.py:302
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:289
|
||||
#: canaille/core/endpoints/forms.py:304
|
||||
msgid "https://mywebsite.tld"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:294
|
||||
#: canaille/core/endpoints/forms.py:309
|
||||
msgid "Preferred language"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:301
|
||||
#: canaille/core/endpoints/forms.py:316
|
||||
msgid "users, admins …"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:326
|
||||
#: canaille/core/endpoints/forms.py:341
|
||||
msgid "Account expiration"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:350
|
||||
#: canaille/core/endpoints/forms.py:365
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:354 canaille/core/endpoints/forms.py:371
|
||||
#: canaille/core/endpoints/forms.py:369 canaille/core/endpoints/forms.py:386
|
||||
#: canaille/core/templates/partial/groups.html:7
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:378 canaille/core/endpoints/forms.py:403
|
||||
#: canaille/core/endpoints/forms.py:400 canaille/core/endpoints/forms.py:425
|
||||
msgid "Email address"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:397
|
||||
#: canaille/core/endpoints/forms.py:419
|
||||
msgid "User name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:401
|
||||
#: canaille/core/endpoints/forms.py:423
|
||||
msgid "Username editable by the invitee"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/forms.py:440
|
||||
#: canaille/core/endpoints/forms.py:462
|
||||
msgid "New email address"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/groups.py:38
|
||||
#: canaille/core/endpoints/groups.py:39
|
||||
msgid "Group creation failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/groups.py:46
|
||||
#: canaille/core/endpoints/groups.py:47
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully created"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/groups.py:96
|
||||
#: canaille/core/endpoints/groups.py:107
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully edited."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/groups.py:104
|
||||
#: canaille/core/endpoints/groups.py:115
|
||||
msgid "Group edition failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/endpoints/groups.py:118
|
||||
#: canaille/core/endpoints/groups.py:159
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully deleted"
|
||||
msgstr ""
|
||||
|
@ -1262,6 +1273,7 @@ msgstr ""
|
|||
#: canaille/core/templates/modals/delete-account.html:26
|
||||
#: canaille/core/templates/modals/delete-group.html:22
|
||||
#: canaille/core/templates/modals/lock-account.html:26
|
||||
#: canaille/core/templates/modals/remove-group-member.html:22
|
||||
#: canaille/oidc/templates/modals/delete-client.html:20
|
||||
#: canaille/oidc/templates/modals/revoke-token.html:20
|
||||
msgid "Cancel"
|
||||
|
@ -1305,10 +1317,32 @@ msgstr ""
|
|||
msgid "Lock"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/groups.html:8
|
||||
msgid "Number of members"
|
||||
#: canaille/core/templates/modals/remove-group-member.html:10
|
||||
msgid "Group member deletion"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/modals/remove-group-member.html:14
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Are you sure you want to remove %(user_name)s from the group "
|
||||
"\"%(group_name)s\"?"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/modals/remove-group-member.html:25
|
||||
#: canaille/core/templates/partial/group-members.html:64
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/group-members.html:16
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/group-members.html:27
|
||||
#: canaille/core/templates/partial/users.html:29
|
||||
msgid "This account is locked"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/group-members.html:79
|
||||
#: canaille/core/templates/partial/groups.html:31
|
||||
#: canaille/core/templates/partial/users.html:73
|
||||
#: canaille/oidc/templates/partial/authorization_list.html:31
|
||||
|
@ -1317,6 +1351,7 @@ msgstr ""
|
|||
msgid "No item matches your request"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/group-members.html:81
|
||||
#: canaille/core/templates/partial/groups.html:33
|
||||
#: canaille/core/templates/partial/users.html:75
|
||||
#: canaille/oidc/templates/partial/authorization_list.html:33
|
||||
|
@ -1325,6 +1360,7 @@ msgstr ""
|
|||
msgid "Maybe try with different criterias?"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/group-members.html:84
|
||||
#: canaille/core/templates/partial/groups.html:36
|
||||
#: canaille/core/templates/partial/users.html:78
|
||||
#: canaille/oidc/templates/partial/authorization_list.html:36
|
||||
|
@ -1334,8 +1370,8 @@ msgstr ""
|
|||
msgid "There is nothing here"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/core/templates/partial/users.html:29
|
||||
msgid "This account is locked"
|
||||
#: canaille/core/templates/partial/groups.html:8
|
||||
msgid "Number of members"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/utils.py:6
|
||||
|
|
|
@ -292,3 +292,95 @@ def test_user_list_search(testclient, logged_admin, foo_group, user, moderator):
|
|||
res.mustcontain(user.formatted_name)
|
||||
res.mustcontain(no=logged_admin.formatted_name)
|
||||
res.mustcontain(no=moderator.formatted_name)
|
||||
|
||||
|
||||
def test_remove_member(testclient, logged_admin, foo_group, user, moderator):
|
||||
foo_group.members = [user, moderator]
|
||||
foo_group.save()
|
||||
|
||||
res = testclient.get("/groups/foo")
|
||||
form = res.forms[f"deletegroupmemberform-{user.id}"]
|
||||
|
||||
res = form.submit(name="action", value="confirm-remove-member")
|
||||
res = res.form.submit(name="action", value="remove-member")
|
||||
assert (
|
||||
"success",
|
||||
"John (johnny) Doe has been removed from the group foo",
|
||||
) in res.flashes
|
||||
|
||||
foo_group.reload()
|
||||
assert user not in foo_group.members
|
||||
|
||||
|
||||
def test_remove_member_already_remove_from_group(
|
||||
testclient, logged_admin, foo_group, user, moderator
|
||||
):
|
||||
foo_group.members = [user, moderator]
|
||||
foo_group.save()
|
||||
|
||||
res = testclient.get("/groups/foo")
|
||||
form = res.forms[f"deletegroupmemberform-{user.id}"]
|
||||
foo_group.members = [moderator]
|
||||
foo_group.save()
|
||||
|
||||
res = form.submit(name="action", value="confirm-remove-member")
|
||||
assert (
|
||||
"error",
|
||||
"The user 'John (johnny) Doe' has already been removed from the group 'foo'",
|
||||
) in res.flashes
|
||||
|
||||
|
||||
def test_confirm_remove_member_already_removed_from_group(
|
||||
testclient, logged_admin, foo_group, user, moderator
|
||||
):
|
||||
foo_group.members = [user, moderator]
|
||||
foo_group.save()
|
||||
|
||||
res = testclient.get("/groups/foo")
|
||||
form = res.forms[f"deletegroupmemberform-{user.id}"]
|
||||
res = form.submit(name="action", value="confirm-remove-member")
|
||||
|
||||
foo_group.members = [moderator]
|
||||
foo_group.save()
|
||||
res = res.form.submit(name="action", value="remove-member")
|
||||
|
||||
assert (
|
||||
"error",
|
||||
"The user 'John (johnny) Doe' has already been removed from the group 'foo'",
|
||||
) in res.flashes
|
||||
|
||||
|
||||
def test_remove_member_already_deleted(
|
||||
testclient, logged_admin, foo_group, user, moderator
|
||||
):
|
||||
foo_group.members = [user, moderator]
|
||||
foo_group.save()
|
||||
|
||||
res = testclient.get("/groups/foo")
|
||||
form = res.forms[f"deletegroupmemberform-{user.id}"]
|
||||
user.delete()
|
||||
|
||||
res = form.submit(name="action", value="confirm-remove-member")
|
||||
assert (
|
||||
"error",
|
||||
"The user you are trying to remove does not exist.",
|
||||
) in res.flashes
|
||||
|
||||
|
||||
def test_confirm_remove_member_already_deleted(
|
||||
testclient, logged_admin, foo_group, user, moderator
|
||||
):
|
||||
foo_group.members = [user, moderator]
|
||||
foo_group.save()
|
||||
|
||||
res = testclient.get("/groups/foo")
|
||||
form = res.forms[f"deletegroupmemberform-{user.id}"]
|
||||
res = form.submit(name="action", value="confirm-remove-member")
|
||||
|
||||
user.delete()
|
||||
res = res.form.submit(name="action", value="remove-member")
|
||||
|
||||
assert (
|
||||
"error",
|
||||
"The user you are trying to remove does not exist.",
|
||||
) in res.flashes
|
||||
|
|
Loading…
Reference in a new issue