Renamed group attributes to match SCIM naming convention

This commit is contained in:
Éloi Rivard 2023-02-05 19:39:52 +01:00
parent 41edb53ff4
commit 3406428f13
14 changed files with 58 additions and 47 deletions

View file

@ -334,7 +334,7 @@ def registration(data, hash):
if "groups" not in form and invitation.groups:
form["groups"] = wtforms.SelectMultipleField(
_("Groups"),
choices=[(group.id, group.name) for group in Group.query()],
choices=[(group.id, group.display_name) for group in Group.query()],
render_kw={"readonly": "true"},
)
form.process(CombinedMultiDict((request.files, request.form)) or None, data=data)

View file

@ -235,7 +235,7 @@ def profile_form(write_field_names, readonly_field_names):
if "groups" in write_field_names | readonly_field_names and Group.query():
fields["groups"] = wtforms.SelectMultipleField(
_("Groups"),
choices=[(group.id, group.name) for group in Group.query()],
choices=[(group.id, group.display_name) for group in Group.query()],
render_kw={"placeholder": _("users, admins …")},
)
@ -248,7 +248,7 @@ def profile_form(write_field_names, readonly_field_names):
class CreateGroupForm(FlaskForm):
name = wtforms.StringField(
display_name = wtforms.StringField(
_("Name"),
validators=[wtforms.validators.DataRequired(), unique_group],
render_kw={
@ -262,7 +262,7 @@ class CreateGroupForm(FlaskForm):
class EditGroupForm(FlaskForm):
name = wtforms.StringField(
display_name = wtforms.StringField(
_("Name"),
validators=[wtforms.validators.DataRequired()],
render_kw={
@ -297,6 +297,6 @@ class InvitationForm(FlaskForm):
)
groups = wtforms.SelectMultipleField(
_("Groups"),
choices=lambda: [(group.id, group.name) for group in Group.query()],
choices=lambda: [(group.id, group.display_name) for group in Group.query()],
render_kw={},
)

View file

@ -38,15 +38,18 @@ def create_group(user):
flash(_("Group creation failed."), "error")
else:
group = Group()
group.member = [user]
group.cn = [form.name.data]
group.members = [user]
group.display_name = [form.display_name.data]
group.description = [form.description.data]
group.save()
flash(
_("The group %(group)s has been sucessfully created", group=group.name),
_(
"The group %(group)s has been sucessfully created",
group=group.display_name,
),
"success",
)
return redirect(url_for("groups.group", groupname=group.name))
return redirect(url_for("groups.group", groupname=group.display_name))
return render_template("group.html", form=form, edited_group=None, members=None)
@ -80,7 +83,7 @@ def edit_group(group):
form = EditGroupForm(
request.form or None,
data={
"name": group.name,
"display_name": group.display_name,
"description": group.description[0] if group.description else "",
},
)
@ -90,10 +93,13 @@ def edit_group(group):
group.description = [form.description.data]
group.save()
flash(
_("The group %(group)s has been sucessfully edited.", group=group.name),
_(
"The group %(group)s has been sucessfully edited.",
group=group.display_name,
),
"success",
)
return redirect(url_for("groups.group", groupname=group.name))
return redirect(url_for("groups.group", groupname=group.display_name))
else:
flash(_("Group edition failed."), "error")
@ -108,7 +114,7 @@ def edit_group(group):
def delete_group(group):
flash(
_("The group %(group)s has been sucessfully deleted", group=group.name),
_("The group %(group)s has been sucessfully deleted", group=group.display_name),
"success",
)
group.delete()

View file

@ -154,8 +154,8 @@ def validate_configuration(config):
user.save(conn)
group = Group(
cn=f"canaille_{uuid.uuid4()}",
member=[user],
display_name=f"canaille_{uuid.uuid4()}",
members=[user],
)
group.save(conn)
group.delete(conn)

View file

@ -111,8 +111,10 @@ class LDAPObject(metaclass=LDAPObjectMetaclass):
setattr(self, name, value)
def __repr__(self):
reverse_attributes = {v: k for k, v in (self.attribute_table or {}).items()}
attribute_name = reverse_attributes.get(self.rdn_attribute, self.rdn_attribute)
return (
f"<{self.__class__.__name__} {self.rdn_attribute}={self.rdn_value}>"
f"<{self.__class__.__name__} {attribute_name}={self.rdn_value}>"
if self.rdn_attribute
else "<LDAPOBject>"
)

View file

@ -183,6 +183,9 @@ class Group(LDAPObject):
attribute_table = {
"id": "dn",
"display_name": "cn",
"members": "member",
"description": "description",
}
def __init__(self, *args, **kwargs):
@ -193,17 +196,17 @@ class Group(LDAPObject):
super().__init__(*args, **kwargs)
@property
def name(self):
def display_name(self):
attribute = current_app.config["LDAP"].get(
"GROUP_NAME_ATTRIBUTE", Group.DEFAULT_NAME_ATTRIBUTE
)
return self[attribute][0]
def get_members(self, conn=None):
return [member for member in self.member if member]
return [member for member in self.members if member]
def add_member(self, user):
self.member = self.member + [user]
self.members = self.members + [user]
def remove_member(self, user):
self.member = [m for m in self.member if m != user]
self.members = [m for m in self.members if m != user]

View file

@ -119,7 +119,7 @@ def generate_user_claims(user, claims, jwt_mapping_config=None):
# it's better to not insert a null or empty string value
data[claim] = formatted_claim
if claim == "groups":
data[claim] = [group.name for group in user.groups]
data[claim] = [group.display_name for group in user.groups]
return data

View file

@ -60,7 +60,7 @@
class="ui form"
>
{{ form.hidden_tag() if form.hidden_tag }}
{{ sui.render_field(form.name) }}
{{ sui.render_field(form.display_name) }}
{{ sui.render_field(form.description) }}
{% if not edited_group %}

View file

@ -12,11 +12,11 @@
{% for group in table_form.items_slice %}
<tr>
<td>
<a href="{{ url_for('groups.group', groupname=group.name) }}">
<a href="{{ url_for('groups.group', groupname=group.display_name) }}">
<i class="users circular black inverted icon"></i>
</a>
</td>
<td><a href="{{ url_for('groups.group', groupname=group.name) }}">{{ group.name }}</a></td>
<td><a href="{{ url_for('groups.group', groupname=group.display_name) }}">{{ group.display_name }}</a></td>
<td>{% if group.description %}{{ group.description[0] }}{% endif %}</td>
<td>{{ group.member|len }}</td>
</tr>

View file

@ -45,8 +45,8 @@
{% if user.can_manage_groups %}
<td>
{% for group in watched_user.groups %}
<a class="ui label" href="{{ url_for('groups.group', groupname=group.name) }}"{% if group.description %} title="{{ group.description[0] }}"{% endif %}>
{{ group.name }}
<a class="ui label" href="{{ url_for('groups.group', groupname=group.display_name) }}"{% if group.description %} title="{{ group.description[0] }}"{% endif %}>
{{ group.display_name }}
</a>
{% endfor %}
</td>

View file

@ -233,8 +233,8 @@ def logged_moderator(moderator, testclient):
def foo_group(app, user, slapd_connection):
Group.ldap_object_classes(slapd_connection)
group = Group(
member=[user],
cn="foo",
members=[user],
display_name="foo",
)
group.save()
user.load_groups()
@ -247,8 +247,8 @@ def foo_group(app, user, slapd_connection):
def bar_group(app, admin, slapd_connection):
Group.ldap_object_classes(slapd_connection)
group = Group(
member=[admin],
cn="bar",
members=[admin],
display_name="bar",
)
group.save()
admin.load_groups()

View file

@ -29,7 +29,7 @@ def test_object_creation(slapd_connection):
def test_repr(slapd_connection, foo_group, user):
assert repr(foo_group) == "<Group cn=foo>"
assert repr(foo_group) == "<Group display_name=foo>"
assert repr(user) == "<User cn=John (johnny) Doe>"

View file

@ -51,16 +51,16 @@ def test_group_list_bad_pages(testclient, logged_admin):
def test_group_list_search(testclient, logged_admin, foo_group, bar_group):
res = testclient.get("/groups")
assert "2 items" in res
assert foo_group.name in res
assert bar_group.name in res
assert foo_group.display_name in res
assert bar_group.display_name in res
form = res.forms["search"]
form["query"] = "oo"
res = form.submit()
assert "1 items" in res, res.text
assert foo_group.name in res
assert bar_group.name not in res
assert foo_group.display_name in res
assert bar_group.display_name not in res
def test_set_groups(app, user, foo_group, bar_group):
@ -125,14 +125,14 @@ def test_moderator_can_create_edit_and_delete_group(
# Fill the form for a new group
res = testclient.get("/groups/add", status=200)
form = res.forms["creategroupform"]
form["name"] = "bar"
form["display_name"] = "bar"
form["description"] = "yolo"
# Group has been created
res = form.submit(status=302).follow(status=200)
bar_group = Group.get("bar")
assert bar_group.name == "bar"
assert bar_group.display_name == "bar"
assert bar_group.description == ["yolo"]
assert [member.id for member in bar_group.get_members()] == [
logged_moderator.id
@ -142,13 +142,13 @@ def test_moderator_can_create_edit_and_delete_group(
# Group name can not be edited
res = testclient.get("/groups/bar", status=200)
form = res.forms["editgroupform"]
form["name"] = "bar2"
form["display_name"] = "bar2"
form["description"] = ["yolo2"]
res = form.submit(name="action", value="edit").follow()
bar_group = Group.get("bar")
assert bar_group.name == "bar"
assert bar_group.display_name == "bar"
assert bar_group.description == ["yolo2"]
assert Group.get("bar2") is None
members = bar_group.get_members()
@ -162,7 +162,7 @@ def test_moderator_can_create_edit_and_delete_group(
def test_cannot_create_already_existing_group(testclient, logged_moderator, foo_group):
res = testclient.post("/groups/add", {"name": "foo"}, status=200)
res = testclient.post("/groups/add", {"display_name": "foo"}, status=200)
assert "Group creation failed." in res
assert "The group &#39;foo&#39; already exists" in res
@ -206,7 +206,7 @@ def test_edition_failed(testclient, logged_moderator, foo_group):
res = form.submit(name="action", value="edit")
assert "Group edition failed." in res
foo_group = Group.get(foo_group.id)
assert foo_group.name == "foo"
assert foo_group.display_name == "foo"
def test_user_list_pagination(testclient, logged_admin, foo_group):

View file

@ -90,8 +90,8 @@ def test_edition(
("cn=bar,ou=groups,dc=mydomain,dc=tld", False, "bar"),
}
assert logged_user.groups == [foo_group]
assert foo_group.member == [logged_user]
assert bar_group.member == [admin]
assert foo_group.members == [logged_user]
assert bar_group.members == [admin]
assert res.form["groups"].attrs["readonly"]
assert res.form["uid"].attrs["readonly"]
@ -130,8 +130,8 @@ def test_edition(
foo_group.reload()
bar_group.reload()
assert logged_user.groups == [foo_group]
assert foo_group.member == [logged_user]
assert bar_group.member == [admin]
assert foo_group.members == [logged_user]
assert bar_group.members == [admin]
assert logged_user.check_password("correct horse battery staple")
@ -339,8 +339,8 @@ def test_user_creation_edition_and_deletion(
foo_group.reload()
bar_group.reload()
assert george in set(foo_group.member)
assert george in set(bar_group.member)
assert george in set(foo_group.members)
assert george in set(bar_group.members)
assert set(george.groups) == {foo_group, bar_group}
assert "george" in testclient.get("/users", status=200).text
assert "george" in testclient.get("/users", status=200).text