Skip to content

Commit 28dac80

Browse files
committed
✨(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.
1 parent 26cafd4 commit 28dac80

File tree

5 files changed

+50
-16
lines changed

5 files changed

+50
-16
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to
1010

1111
## Added
1212

13+
- ✨(backend) add ancestors links definitions to document abilities #846
1314
- 🚩(backend) add feature flag for the footer #841
1415
- 🔧(backend) add view to manage footer json #841
1516

src/backend/core/models.py

+23-11
Original file line numberDiff line numberDiff line change
@@ -749,17 +749,16 @@ def get_roles(self, user):
749749
roles = []
750750
return roles
751751

752-
def get_links_definitions(self, ancestors_links):
753-
"""Get links reach/role definitions for the current document and its ancestors."""
752+
def get_ancestors_links_definitions(self, ancestors_links):
753+
"""Get links reach/role definitions for ancestors of the current document."""
754754

755-
links_definitions = defaultdict(set)
756-
links_definitions[self.link_reach].add(self.link_role)
757-
758-
# Merge ancestor link definitions
755+
ancestors_links_definitions = defaultdict(set)
759756
for ancestor in ancestors_links:
760-
links_definitions[ancestor["link_reach"]].add(ancestor["link_role"])
757+
ancestors_links_definitions[ancestor["link_reach"]].add(
758+
ancestor["link_role"]
759+
)
761760

762-
return dict(links_definitions) # Convert defaultdict back to a normal dict
761+
return ancestors_links_definitions
763762

764763
def compute_ancestors_links(self, user):
765764
"""
@@ -815,10 +814,20 @@ def get_abilities(self, user, ancestors_links=None):
815814
) and not is_deleted
816815

817816
# Add roles provided by the document link, taking into account its ancestors
818-
links_definitions = self.get_links_definitions(ancestors_links)
819-
public_roles = links_definitions.get(LinkReachChoices.PUBLIC, set())
817+
ancestors_links_definitions = self.get_ancestors_links_definitions(
818+
ancestors_links
819+
)
820+
821+
public_roles = ancestors_links_definitions.get(
822+
LinkReachChoices.PUBLIC, set()
823+
) | ({self.link_role} if self.link_reach == LinkReachChoices.PUBLIC else set())
820824
authenticated_roles = (
821-
links_definitions.get(LinkReachChoices.AUTHENTICATED, set())
825+
ancestors_links_definitions.get(LinkReachChoices.AUTHENTICATED, set())
826+
| (
827+
{self.link_role}
828+
if self.link_reach == LinkReachChoices.AUTHENTICATED
829+
else set()
830+
)
822831
if user.is_authenticated
823832
else set()
824833
)
@@ -862,6 +871,9 @@ def get_abilities(self, user, ancestors_links=None):
862871
"restore": is_owner,
863872
"retrieve": can_get,
864873
"media_auth": can_get,
874+
"ancestors_links_definitions": {
875+
k: list(v) for k, v in ancestors_links_definitions.items()
876+
},
865877
"link_select_options": LinkReachChoices.get_select_options(ancestors_links),
866878
"tree": can_get,
867879
"update": can_update,

src/backend/core/tests/documents/test_api_documents_retrieve.py

+12
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def test_api_documents_retrieve_anonymous_public_standalone():
4242
"favorite": False,
4343
"invite_owner": False,
4444
"link_configuration": False,
45+
"ancestors_links_definitions": {},
4546
"link_select_options": {
4647
"authenticated": ["reader", "editor"],
4748
"public": ["reader", "editor"],
@@ -97,6 +98,10 @@ def test_api_documents_retrieve_anonymous_public_parent():
9798
"accesses_view": False,
9899
"ai_transform": False,
99100
"ai_translate": False,
101+
"ancestors_links_definitions": {
102+
"public": [grand_parent.link_role],
103+
parent.link_reach: [parent.link_role],
104+
},
100105
"attachment_upload": grand_parent.link_role == "editor",
101106
"children_create": False,
102107
"children_list": True,
@@ -193,6 +198,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated(
193198
"accesses_view": False,
194199
"ai_transform": document.link_role == "editor",
195200
"ai_translate": document.link_role == "editor",
201+
"ancestors_links_definitions": {},
196202
"attachment_upload": document.link_role == "editor",
197203
"children_create": document.link_role == "editor",
198204
"children_list": True,
@@ -267,6 +273,10 @@ def test_api_documents_retrieve_authenticated_public_or_authenticated_parent(rea
267273
"accesses_view": False,
268274
"ai_transform": grand_parent.link_role == "editor",
269275
"ai_translate": grand_parent.link_role == "editor",
276+
"ancestors_links_definitions": {
277+
grand_parent.link_reach: [grand_parent.link_role],
278+
"restricted": [parent.link_role],
279+
},
270280
"attachment_upload": grand_parent.link_role == "editor",
271281
"children_create": grand_parent.link_role == "editor",
272282
"children_list": True,
@@ -440,13 +450,15 @@ def test_api_documents_retrieve_authenticated_related_parent():
440450
)
441451
assert response.status_code == 200
442452
links = document.get_ancestors().values("link_reach", "link_role")
453+
ancestors_roles = list({grand_parent.link_role, parent.link_role})
443454
assert response.json() == {
444455
"id": str(document.id),
445456
"abilities": {
446457
"accesses_manage": access.role in ["administrator", "owner"],
447458
"accesses_view": True,
448459
"ai_transform": access.role != "reader",
449460
"ai_translate": access.role != "reader",
461+
"ancestors_links_definitions": {"restricted": ancestors_roles},
450462
"attachment_upload": access.role != "reader",
451463
"children_create": access.role != "reader",
452464
"children_list": True,

src/backend/core/tests/documents/test_api_documents_trashbin.py

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def test_api_documents_trashbin_format():
7474
"accesses_view": True,
7575
"ai_transform": True,
7676
"ai_translate": True,
77+
"ancestors_links_definitions": {},
7778
"attachment_upload": True,
7879
"children_create": True,
7980
"children_list": True,

src/backend/core/tests/test_models_documents.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ def test_models_documents_get_abilities_forbidden(
154154
"accesses_view": False,
155155
"ai_transform": False,
156156
"ai_translate": False,
157+
"ancestors_links_definitions": {},
157158
"attachment_upload": False,
158159
"children_create": False,
159160
"children_list": False,
@@ -214,6 +215,7 @@ def test_models_documents_get_abilities_reader(
214215
"accesses_view": False,
215216
"ai_transform": False,
216217
"ai_translate": False,
218+
"ancestors_links_definitions": {},
217219
"attachment_upload": False,
218220
"children_create": False,
219221
"children_list": True,
@@ -250,7 +252,7 @@ def test_models_documents_get_abilities_reader(
250252
assert all(
251253
value is False
252254
for key, value in document.get_abilities(user).items()
253-
if key != "link_select_options"
255+
if key not in ["link_select_options", "ancestors_links_definitions"]
254256
)
255257

256258

@@ -276,6 +278,7 @@ def test_models_documents_get_abilities_editor(
276278
"accesses_view": False,
277279
"ai_transform": is_authenticated,
278280
"ai_translate": is_authenticated,
281+
"ancestors_links_definitions": {},
279282
"attachment_upload": True,
280283
"children_create": is_authenticated,
281284
"children_list": True,
@@ -311,7 +314,7 @@ def test_models_documents_get_abilities_editor(
311314
assert all(
312315
value is False
313316
for key, value in document.get_abilities(user).items()
314-
if key != "link_select_options"
317+
if key not in ["link_select_options", "ancestors_links_definitions"]
315318
)
316319

317320

@@ -327,6 +330,7 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries):
327330
"accesses_view": True,
328331
"ai_transform": True,
329332
"ai_translate": True,
333+
"ancestors_links_definitions": {},
330334
"attachment_upload": True,
331335
"children_create": True,
332336
"children_list": True,
@@ -375,6 +379,7 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
375379
"accesses_view": True,
376380
"ai_transform": True,
377381
"ai_translate": True,
382+
"ancestors_links_definitions": {},
378383
"attachment_upload": True,
379384
"children_create": True,
380385
"children_list": True,
@@ -410,7 +415,7 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
410415
assert all(
411416
value is False
412417
for key, value in document.get_abilities(user).items()
413-
if key != "link_select_options"
418+
if key not in ["link_select_options", "ancestors_links_definitions"]
414419
)
415420

416421

@@ -426,6 +431,7 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
426431
"accesses_view": True,
427432
"ai_transform": True,
428433
"ai_translate": True,
434+
"ancestors_links_definitions": {},
429435
"attachment_upload": True,
430436
"children_create": True,
431437
"children_list": True,
@@ -461,7 +467,7 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
461467
assert all(
462468
value is False
463469
for key, value in document.get_abilities(user).items()
464-
if key != "link_select_options"
470+
if key not in ["link_select_options", "ancestors_links_definitions"]
465471
)
466472

467473

@@ -484,6 +490,7 @@ def test_models_documents_get_abilities_reader_user(
484490
# You should not access AI if it's restricted to users with specific access
485491
"ai_transform": access_from_link and ai_access_setting != "restricted",
486492
"ai_translate": access_from_link and ai_access_setting != "restricted",
493+
"ancestors_links_definitions": {},
487494
"attachment_upload": access_from_link,
488495
"children_create": access_from_link,
489496
"children_list": True,
@@ -521,7 +528,7 @@ def test_models_documents_get_abilities_reader_user(
521528
assert all(
522529
value is False
523530
for key, value in document.get_abilities(user).items()
524-
if key != "link_select_options"
531+
if key not in ["link_select_options", "ancestors_links_definitions"]
525532
)
526533

527534

@@ -540,6 +547,7 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries):
540547
"accesses_view": True,
541548
"ai_transform": False,
542549
"ai_translate": False,
550+
"ancestors_links_definitions": {},
543551
"attachment_upload": False,
544552
"children_create": False,
545553
"children_list": True,

0 commit comments

Comments
 (0)