♻️(backend) simplify further select options on link reach/role

We reduce the number of options even more by treating link reach
and link role independently: link reach must be higher than its
ancestors' equivalent link reach and link role must be higher than
its ancestors' link role.

This reduces the number of possibilities but we decided to start
with the most restrictive and simple offer and extend it if we
realize it faces too many criticism instead of risking to offer
too many options that are too complex and must be reduced afterwards.
This commit is contained in:
Samuel Paccoud - DINUM
2025-05-09 08:05:38 +02:00
committed by Anthony LC
parent d0eb2275e5
commit d232654c55
2 changed files with 16 additions and 46 deletions

View File

@@ -65,49 +65,22 @@ class LinkReachChoices(PriorityTextChoices):
def get_select_options(cls, link_reach, link_role):
"""
Determines the valid select options for link reach and link role depending on the
list of ancestors' link reach/role definitions.
ancestors' link reach/role given as arguments.
Returns:
Dictionary mapping possible reach levels to their corresponding possible roles.
"""
# If no ancestors, return all options
if not link_reach:
return {
reach: LinkRoleChoices.values if reach != cls.RESTRICTED else None
for reach in cls.values
}
# Initialize the result for all reaches with possible roles
result = {
reach: set(LinkRoleChoices.values) if reach != cls.RESTRICTED else None
for reach in cls.values
}
# Handle special rules directly with early returns for efficiency
if link_role == LinkRoleChoices.EDITOR:
# Rule 1: public/editor → override everything
if link_reach == cls.PUBLIC:
return {cls.PUBLIC: [LinkRoleChoices.EDITOR]}
# Rule 2: authenticated/editor
if link_reach == cls.AUTHENTICATED:
result[cls.AUTHENTICATED].discard(LinkRoleChoices.READER)
result.pop(cls.RESTRICTED, None)
if link_role == LinkRoleChoices.READER:
# Rule 3: public/reader
if link_reach == cls.PUBLIC:
result.pop(cls.AUTHENTICATED, None)
result.pop(cls.RESTRICTED, None)
# Rule 4: authenticated/reader
if link_reach == cls.AUTHENTICATED:
result.pop(cls.RESTRICTED, None)
# Convert sets to ordered lists where applicable
return {
reach: sorted(roles, key=LinkRoleChoices.get_priority) if roles else roles
for reach, roles in result.items()
reach: [
role
for role in LinkRoleChoices.values
if LinkRoleChoices.get_priority(role)
>= LinkRoleChoices.get_priority(link_role)
]
if reach != cls.RESTRICTED
else None
for reach in cls.values
if LinkReachChoices.get_priority(reach)
>= LinkReachChoices.get_priority(link_reach)
}

View File

@@ -1186,7 +1186,6 @@ def test_models_documents_restore_complex_bis(django_assert_num_queries):
@pytest.mark.parametrize(
"reach, role, select_options",
[
# One ancestor
(
"public",
"reader",
@@ -1206,7 +1205,7 @@ def test_models_documents_restore_complex_bis(django_assert_num_queries):
(
"authenticated",
"editor",
{"authenticated": ["editor"], "public": ["reader", "editor"]},
{"authenticated": ["editor"], "public": ["editor"]},
),
(
"restricted",
@@ -1222,18 +1221,16 @@ def test_models_documents_restore_complex_bis(django_assert_num_queries):
"editor",
{
"restricted": None,
"authenticated": ["reader", "editor"],
"public": ["reader", "editor"],
"authenticated": ["editor"],
"public": ["editor"],
},
),
# No ancestors (edge case)
# Edge cases
(
"public",
None,
{
"public": ["reader", "editor"],
"authenticated": ["reader", "editor"],
"restricted": None,
},
),
(