(backend) add ancestors links definitions to document abilities

The frontend needs to display inherited link accesses when it displays
possible selection options. We need to return this information to the
client.
This commit is contained in:
Samuel Paccoud - DINUM
2025-04-06 21:20:04 +02:00
committed by Anthony LC
parent 0499aec624
commit 26c7af0dbf
5 changed files with 50 additions and 16 deletions

View File

@@ -749,17 +749,16 @@ class Document(MP_Node, BaseModel):
roles = []
return roles
def get_links_definitions(self, ancestors_links):
"""Get links reach/role definitions for the current document and its ancestors."""
def get_ancestors_links_definitions(self, ancestors_links):
"""Get links reach/role definitions for ancestors of the current document."""
links_definitions = defaultdict(set)
links_definitions[self.link_reach].add(self.link_role)
# Merge ancestor link definitions
ancestors_links_definitions = defaultdict(set)
for ancestor in ancestors_links:
links_definitions[ancestor["link_reach"]].add(ancestor["link_role"])
ancestors_links_definitions[ancestor["link_reach"]].add(
ancestor["link_role"]
)
return dict(links_definitions) # Convert default dict back to a normal dict
return ancestors_links_definitions
def compute_ancestors_links(self, user):
"""
@@ -815,10 +814,20 @@ class Document(MP_Node, BaseModel):
) and not is_deleted
# Add roles provided by the document link, taking into account its ancestors
links_definitions = self.get_links_definitions(ancestors_links)
public_roles = links_definitions.get(LinkReachChoices.PUBLIC, set())
ancestors_links_definitions = self.get_ancestors_links_definitions(
ancestors_links
)
public_roles = ancestors_links_definitions.get(
LinkReachChoices.PUBLIC, set()
) | ({self.link_role} if self.link_reach == LinkReachChoices.PUBLIC else set())
authenticated_roles = (
links_definitions.get(LinkReachChoices.AUTHENTICATED, set())
ancestors_links_definitions.get(LinkReachChoices.AUTHENTICATED, set())
| (
{self.link_role}
if self.link_reach == LinkReachChoices.AUTHENTICATED
else set()
)
if user.is_authenticated
else set()
)
@@ -864,6 +873,9 @@ class Document(MP_Node, BaseModel):
"restore": is_owner,
"retrieve": can_get,
"media_auth": can_get,
"ancestors_links_definitions": {
k: list(v) for k, v in ancestors_links_definitions.items()
},
"link_select_options": LinkReachChoices.get_select_options(ancestors_links),
"tree": can_get,
"update": can_update,

View File

@@ -43,6 +43,7 @@ def test_api_documents_retrieve_anonymous_public_standalone():
"favorite": False,
"invite_owner": False,
"link_configuration": False,
"ancestors_links_definitions": {},
"link_select_options": {
"authenticated": ["reader", "editor"],
"public": ["reader", "editor"],
@@ -99,6 +100,10 @@ def test_api_documents_retrieve_anonymous_public_parent():
"accesses_view": False,
"ai_transform": False,
"ai_translate": False,
"ancestors_links_definitions": {
"public": [grand_parent.link_role],
parent.link_reach: [parent.link_role],
},
"attachment_upload": grand_parent.link_role == "editor",
"can_edit": grand_parent.link_role == "editor",
"children_create": False,
@@ -197,6 +202,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated(
"accesses_view": False,
"ai_transform": document.link_role == "editor",
"ai_translate": document.link_role == "editor",
"ancestors_links_definitions": {},
"attachment_upload": document.link_role == "editor",
"can_edit": document.link_role == "editor",
"children_create": document.link_role == "editor",
@@ -273,6 +279,10 @@ def test_api_documents_retrieve_authenticated_public_or_authenticated_parent(rea
"accesses_view": False,
"ai_transform": grand_parent.link_role == "editor",
"ai_translate": grand_parent.link_role == "editor",
"ancestors_links_definitions": {
grand_parent.link_reach: [grand_parent.link_role],
"restricted": [parent.link_role],
},
"attachment_upload": grand_parent.link_role == "editor",
"can_edit": grand_parent.link_role == "editor",
"children_create": grand_parent.link_role == "editor",
@@ -448,6 +458,7 @@ def test_api_documents_retrieve_authenticated_related_parent():
)
assert response.status_code == 200
links = document.get_ancestors().values("link_reach", "link_role")
ancestors_roles = list({grand_parent.link_role, parent.link_role})
assert response.json() == {
"id": str(document.id),
"abilities": {
@@ -455,6 +466,7 @@ def test_api_documents_retrieve_authenticated_related_parent():
"accesses_view": True,
"ai_transform": access.role != "reader",
"ai_translate": access.role != "reader",
"ancestors_links_definitions": {"restricted": ancestors_roles},
"attachment_upload": access.role != "reader",
"can_edit": access.role != "reader",
"children_create": access.role != "reader",

View File

@@ -74,6 +74,7 @@ def test_api_documents_trashbin_format():
"accesses_view": True,
"ai_transform": True,
"ai_translate": True,
"ancestors_links_definitions": {},
"attachment_upload": True,
"can_edit": True,
"children_create": True,

View File

@@ -154,6 +154,7 @@ def test_models_documents_get_abilities_forbidden(
"accesses_view": False,
"ai_transform": False,
"ai_translate": False,
"ancestors_links_definitions": {},
"attachment_upload": False,
"can_edit": False,
"children_create": False,
@@ -216,6 +217,7 @@ def test_models_documents_get_abilities_reader(
"accesses_view": False,
"ai_transform": False,
"ai_translate": False,
"ancestors_links_definitions": {},
"attachment_upload": False,
"can_edit": False,
"children_create": False,
@@ -254,7 +256,7 @@ def test_models_documents_get_abilities_reader(
assert all(
value is False
for key, value in document.get_abilities(user).items()
if key != "link_select_options"
if key not in ["link_select_options", "ancestors_links_definitions"]
)
@@ -280,6 +282,7 @@ def test_models_documents_get_abilities_editor(
"accesses_view": False,
"ai_transform": is_authenticated,
"ai_translate": is_authenticated,
"ancestors_links_definitions": {},
"attachment_upload": True,
"can_edit": True,
"children_create": is_authenticated,
@@ -317,7 +320,7 @@ def test_models_documents_get_abilities_editor(
assert all(
value is False
for key, value in document.get_abilities(user).items()
if key != "link_select_options"
if key not in ["link_select_options", "ancestors_links_definitions"]
)
@@ -333,6 +336,7 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries):
"accesses_view": True,
"ai_transform": True,
"ai_translate": True,
"ancestors_links_definitions": {},
"attachment_upload": True,
"can_edit": True,
"children_create": True,
@@ -383,6 +387,7 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
"accesses_view": True,
"ai_transform": True,
"ai_translate": True,
"ancestors_links_definitions": {},
"attachment_upload": True,
"can_edit": True,
"children_create": True,
@@ -420,7 +425,7 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
assert all(
value is False
for key, value in document.get_abilities(user).items()
if key != "link_select_options"
if key not in ["link_select_options", "ancestors_links_definitions"]
)
@@ -436,6 +441,7 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
"accesses_view": True,
"ai_transform": True,
"ai_translate": True,
"ancestors_links_definitions": {},
"attachment_upload": True,
"can_edit": True,
"children_create": True,
@@ -473,7 +479,7 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
assert all(
value is False
for key, value in document.get_abilities(user).items()
if key != "link_select_options"
if key not in ["link_select_options", "ancestors_links_definitions"]
)
@@ -496,6 +502,7 @@ def test_models_documents_get_abilities_reader_user(
# You should not access AI if it's restricted to users with specific access
"ai_transform": access_from_link and ai_access_setting != "restricted",
"ai_translate": access_from_link and ai_access_setting != "restricted",
"ancestors_links_definitions": {},
"attachment_upload": access_from_link,
"can_edit": access_from_link,
"children_create": access_from_link,
@@ -535,7 +542,7 @@ def test_models_documents_get_abilities_reader_user(
assert all(
value is False
for key, value in document.get_abilities(user).items()
if key != "link_select_options"
if key not in ["link_select_options", "ancestors_links_definitions"]
)
@@ -554,6 +561,7 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries):
"accesses_view": True,
"ai_transform": False,
"ai_translate": False,
"ancestors_links_definitions": {},
"attachment_upload": False,
"can_edit": False,
"children_create": False,