Skip to content

Commit 11dfc9f

Browse files
committed
✨(backend) add is_masked to document view
We added the `is_masked` annotation to the document view to indicate whether a document is masked for the current user. This will allow the frontend to handle masked documents appropriately in the UI.
1 parent 67a195f commit 11dfc9f

File tree

6 files changed

+58
-1
lines changed

6 files changed

+58
-1
lines changed

src/backend/core/api/serializers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class ListDocumentSerializer(serializers.ModelSerializer):
6666
"""Serialize documents with limited fields for display in lists."""
6767

6868
is_favorite = serializers.BooleanField(read_only=True)
69+
is_masked = serializers.BooleanField(read_only=True)
6970
nb_accesses_ancestors = serializers.IntegerField(read_only=True)
7071
nb_accesses_direct = serializers.IntegerField(read_only=True)
7172
user_role = serializers.SerializerMethodField(read_only=True)
@@ -85,6 +86,7 @@ class Meta:
8586
"depth",
8687
"excerpt",
8788
"is_favorite",
89+
"is_masked",
8890
"link_role",
8991
"link_reach",
9092
"nb_accesses_ancestors",
@@ -107,6 +109,7 @@ class Meta:
107109
"depth",
108110
"excerpt",
109111
"is_favorite",
112+
"is_masked",
110113
"link_role",
111114
"link_reach",
112115
"nb_accesses_ancestors",
@@ -176,6 +179,7 @@ class Meta:
176179
"depth",
177180
"excerpt",
178181
"is_favorite",
182+
"is_masked",
179183
"link_role",
180184
"link_reach",
181185
"nb_accesses_ancestors",

src/backend/core/api/viewsets.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ def filter_queryset(self, queryset):
405405
queryset = super().filter_queryset(queryset)
406406
user = self.request.user
407407
queryset = queryset.annotate_is_favorite(user)
408+
queryset = queryset.annotate_is_masked(user)
408409
queryset = queryset.annotate_user_roles(user)
409410
return queryset
410411

@@ -453,8 +454,9 @@ def list(self, request, *args, **kwargs):
453454
)
454455
queryset = queryset.filter(path__in=root_paths)
455456

456-
# Annotate favorite status and filter if applicable as late as possible
457+
# Annotate favorite and masked status and filter if applicable as late as possible
457458
queryset = queryset.annotate_is_favorite(user)
459+
queryset = queryset.annotate_is_masked(user)
458460
for field in ["is_favorite", "is_masked"]:
459461
queryset = filterset.filters[field].filter(queryset, filter_data[field])
460462

src/backend/core/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,18 @@ def annotate_is_favorite(self, user):
326326

327327
return self.annotate(is_favorite=models.Value(False))
328328

329+
def annotate_is_masked(self, user):
330+
"""
331+
Annotate document queryset with the masked status for the current user.
332+
"""
333+
if user.is_authenticated:
334+
masked_exists_subquery = LinkTrace.objects.filter(
335+
document_id=models.OuterRef("pk"), user=user, is_masked=True
336+
)
337+
return self.annotate(is_masked=models.Exists(masked_exists_subquery))
338+
339+
return self.annotate(is_masked=models.Value(False))
340+
329341
def annotate_user_roles(self, user):
330342
"""
331343
Annotate document queryset with the roles of the current user

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def test_api_documents_children_list_anonymous_public_standalone(
4545
"excerpt": child1.excerpt,
4646
"id": str(child1.id),
4747
"is_favorite": False,
48+
"is_masked": False,
4849
"link_reach": child1.link_reach,
4950
"link_role": child1.link_role,
5051
"numchild": 0,
@@ -67,6 +68,7 @@ def test_api_documents_children_list_anonymous_public_standalone(
6768
"excerpt": child2.excerpt,
6869
"id": str(child2.id),
6970
"is_favorite": False,
71+
"is_masked": False,
7072
"link_reach": child2.link_reach,
7173
"link_role": child2.link_role,
7274
"numchild": 0,
@@ -119,6 +121,7 @@ def test_api_documents_children_list_anonymous_public_parent(django_assert_num_q
119121
"excerpt": child1.excerpt,
120122
"id": str(child1.id),
121123
"is_favorite": False,
124+
"is_masked": False,
122125
"link_reach": child1.link_reach,
123126
"link_role": child1.link_role,
124127
"numchild": 0,
@@ -141,6 +144,7 @@ def test_api_documents_children_list_anonymous_public_parent(django_assert_num_q
141144
"excerpt": child2.excerpt,
142145
"id": str(child2.id),
143146
"is_favorite": False,
147+
"is_masked": False,
144148
"link_reach": child2.link_reach,
145149
"link_role": child2.link_role,
146150
"numchild": 0,
@@ -212,6 +216,7 @@ def test_api_documents_children_list_authenticated_unrelated_public_or_authentic
212216
"excerpt": child1.excerpt,
213217
"id": str(child1.id),
214218
"is_favorite": False,
219+
"is_masked": False,
215220
"link_reach": child1.link_reach,
216221
"link_role": child1.link_role,
217222
"numchild": 0,
@@ -234,6 +239,7 @@ def test_api_documents_children_list_authenticated_unrelated_public_or_authentic
234239
"excerpt": child2.excerpt,
235240
"id": str(child2.id),
236241
"is_favorite": False,
242+
"is_masked": False,
237243
"link_reach": child2.link_reach,
238244
"link_role": child2.link_role,
239245
"numchild": 0,
@@ -291,6 +297,7 @@ def test_api_documents_children_list_authenticated_public_or_authenticated_paren
291297
"excerpt": child1.excerpt,
292298
"id": str(child1.id),
293299
"is_favorite": False,
300+
"is_masked": False,
294301
"link_reach": child1.link_reach,
295302
"link_role": child1.link_role,
296303
"numchild": 0,
@@ -313,6 +320,7 @@ def test_api_documents_children_list_authenticated_public_or_authenticated_paren
313320
"excerpt": child2.excerpt,
314321
"id": str(child2.id),
315322
"is_favorite": False,
323+
"is_masked": False,
316324
"link_reach": child2.link_reach,
317325
"link_role": child2.link_role,
318326
"numchild": 0,
@@ -397,6 +405,7 @@ def test_api_documents_children_list_authenticated_related_direct(
397405
"excerpt": child1.excerpt,
398406
"id": str(child1.id),
399407
"is_favorite": False,
408+
"is_masked": False,
400409
"link_reach": child1.link_reach,
401410
"link_role": child1.link_role,
402411
"numchild": 0,
@@ -419,6 +428,7 @@ def test_api_documents_children_list_authenticated_related_direct(
419428
"excerpt": child2.excerpt,
420429
"id": str(child2.id),
421430
"is_favorite": False,
431+
"is_masked": False,
422432
"link_reach": child2.link_reach,
423433
"link_role": child2.link_role,
424434
"numchild": 0,
@@ -479,6 +489,7 @@ def test_api_documents_children_list_authenticated_related_parent(
479489
"excerpt": child1.excerpt,
480490
"id": str(child1.id),
481491
"is_favorite": False,
492+
"is_masked": False,
482493
"link_reach": child1.link_reach,
483494
"link_role": child1.link_role,
484495
"numchild": 0,
@@ -501,6 +512,7 @@ def test_api_documents_children_list_authenticated_related_parent(
501512
"excerpt": child2.excerpt,
502513
"id": str(child2.id),
503514
"is_favorite": False,
515+
"is_masked": False,
504516
"link_reach": child2.link_reach,
505517
"link_role": child2.link_role,
506518
"numchild": 0,
@@ -613,6 +625,7 @@ def test_api_documents_children_list_authenticated_related_team_members(
613625
"excerpt": child1.excerpt,
614626
"id": str(child1.id),
615627
"is_favorite": False,
628+
"is_masked": False,
616629
"link_reach": child1.link_reach,
617630
"link_role": child1.link_role,
618631
"numchild": 0,
@@ -635,6 +648,7 @@ def test_api_documents_children_list_authenticated_related_team_members(
635648
"excerpt": child2.excerpt,
636649
"id": str(child2.id),
637650
"is_favorite": False,
651+
"is_masked": False,
638652
"link_reach": child2.link_reach,
639653
"link_role": child2.link_role,
640654
"numchild": 0,

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def test_api_documents_descendants_list_anonymous_public_standalone():
4242
"excerpt": child1.excerpt,
4343
"id": str(child1.id),
4444
"is_favorite": False,
45+
"is_masked": False,
4546
"link_reach": child1.link_reach,
4647
"link_role": child1.link_role,
4748
"numchild": 1,
@@ -66,6 +67,7 @@ def test_api_documents_descendants_list_anonymous_public_standalone():
6667
"excerpt": grand_child.excerpt,
6768
"id": str(grand_child.id),
6869
"is_favorite": False,
70+
"is_masked": False,
6971
"link_reach": grand_child.link_reach,
7072
"link_role": grand_child.link_role,
7173
"numchild": 0,
@@ -88,6 +90,7 @@ def test_api_documents_descendants_list_anonymous_public_standalone():
8890
"excerpt": child2.excerpt,
8991
"id": str(child2.id),
9092
"is_favorite": False,
93+
"is_masked": False,
9194
"link_reach": child2.link_reach,
9295
"link_role": child2.link_role,
9396
"numchild": 0,
@@ -139,6 +142,7 @@ def test_api_documents_descendants_list_anonymous_public_parent():
139142
"excerpt": child1.excerpt,
140143
"id": str(child1.id),
141144
"is_favorite": False,
145+
"is_masked": False,
142146
"link_reach": child1.link_reach,
143147
"link_role": child1.link_role,
144148
"numchild": 1,
@@ -161,6 +165,7 @@ def test_api_documents_descendants_list_anonymous_public_parent():
161165
"excerpt": grand_child.excerpt,
162166
"id": str(grand_child.id),
163167
"is_favorite": False,
168+
"is_masked": False,
164169
"link_reach": grand_child.link_reach,
165170
"link_role": grand_child.link_role,
166171
"numchild": 0,
@@ -183,6 +188,7 @@ def test_api_documents_descendants_list_anonymous_public_parent():
183188
"excerpt": child2.excerpt,
184189
"id": str(child2.id),
185190
"is_favorite": False,
191+
"is_masked": False,
186192
"link_reach": child2.link_reach,
187193
"link_role": child2.link_role,
188194
"numchild": 0,
@@ -255,6 +261,7 @@ def test_api_documents_descendants_list_authenticated_unrelated_public_or_authen
255261
"excerpt": child1.excerpt,
256262
"id": str(child1.id),
257263
"is_favorite": False,
264+
"is_masked": False,
258265
"link_reach": child1.link_reach,
259266
"link_role": child1.link_role,
260267
"numchild": 1,
@@ -277,6 +284,7 @@ def test_api_documents_descendants_list_authenticated_unrelated_public_or_authen
277284
"excerpt": grand_child.excerpt,
278285
"id": str(grand_child.id),
279286
"is_favorite": False,
287+
"is_masked": False,
280288
"link_reach": grand_child.link_reach,
281289
"link_role": grand_child.link_role,
282290
"numchild": 0,
@@ -299,6 +307,7 @@ def test_api_documents_descendants_list_authenticated_unrelated_public_or_authen
299307
"excerpt": child2.excerpt,
300308
"id": str(child2.id),
301309
"is_favorite": False,
310+
"is_masked": False,
302311
"link_reach": child2.link_reach,
303312
"link_role": child2.link_role,
304313
"numchild": 0,
@@ -356,6 +365,7 @@ def test_api_documents_descendants_list_authenticated_public_or_authenticated_pa
356365
"excerpt": child1.excerpt,
357366
"id": str(child1.id),
358367
"is_favorite": False,
368+
"is_masked": False,
359369
"link_reach": child1.link_reach,
360370
"link_role": child1.link_role,
361371
"numchild": 1,
@@ -378,6 +388,7 @@ def test_api_documents_descendants_list_authenticated_public_or_authenticated_pa
378388
"excerpt": grand_child.excerpt,
379389
"id": str(grand_child.id),
380390
"is_favorite": False,
391+
"is_masked": False,
381392
"link_reach": grand_child.link_reach,
382393
"link_role": grand_child.link_role,
383394
"numchild": 0,
@@ -400,6 +411,7 @@ def test_api_documents_descendants_list_authenticated_public_or_authenticated_pa
400411
"excerpt": child2.excerpt,
401412
"id": str(child2.id),
402413
"is_favorite": False,
414+
"is_masked": False,
403415
"link_reach": child2.link_reach,
404416
"link_role": child2.link_role,
405417
"numchild": 0,
@@ -478,6 +490,7 @@ def test_api_documents_descendants_list_authenticated_related_direct():
478490
"excerpt": child1.excerpt,
479491
"id": str(child1.id),
480492
"is_favorite": False,
493+
"is_masked": False,
481494
"link_reach": child1.link_reach,
482495
"link_role": child1.link_role,
483496
"numchild": 1,
@@ -500,6 +513,7 @@ def test_api_documents_descendants_list_authenticated_related_direct():
500513
"excerpt": grand_child.excerpt,
501514
"id": str(grand_child.id),
502515
"is_favorite": False,
516+
"is_masked": False,
503517
"link_reach": grand_child.link_reach,
504518
"link_role": grand_child.link_role,
505519
"numchild": 0,
@@ -522,6 +536,7 @@ def test_api_documents_descendants_list_authenticated_related_direct():
522536
"excerpt": child2.excerpt,
523537
"id": str(child2.id),
524538
"is_favorite": False,
539+
"is_masked": False,
525540
"link_reach": child2.link_reach,
526541
"link_role": child2.link_role,
527542
"numchild": 0,
@@ -580,6 +595,7 @@ def test_api_documents_descendants_list_authenticated_related_parent():
580595
"excerpt": child1.excerpt,
581596
"id": str(child1.id),
582597
"is_favorite": False,
598+
"is_masked": False,
583599
"link_reach": child1.link_reach,
584600
"link_role": child1.link_role,
585601
"numchild": 1,
@@ -602,6 +618,7 @@ def test_api_documents_descendants_list_authenticated_related_parent():
602618
"excerpt": grand_child.excerpt,
603619
"id": str(grand_child.id),
604620
"is_favorite": False,
621+
"is_masked": False,
605622
"link_reach": grand_child.link_reach,
606623
"link_role": grand_child.link_role,
607624
"numchild": 0,
@@ -624,6 +641,7 @@ def test_api_documents_descendants_list_authenticated_related_parent():
624641
"excerpt": child2.excerpt,
625642
"id": str(child2.id),
626643
"is_favorite": False,
644+
"is_masked": False,
627645
"link_reach": child2.link_reach,
628646
"link_role": child2.link_role,
629647
"numchild": 0,
@@ -728,6 +746,7 @@ def test_api_documents_descendants_list_authenticated_related_team_members(
728746
"excerpt": child1.excerpt,
729747
"id": str(child1.id),
730748
"is_favorite": False,
749+
"is_masked": False,
731750
"link_reach": child1.link_reach,
732751
"link_role": child1.link_role,
733752
"numchild": 1,
@@ -750,6 +769,7 @@ def test_api_documents_descendants_list_authenticated_related_team_members(
750769
"excerpt": grand_child.excerpt,
751770
"id": str(grand_child.id),
752771
"is_favorite": False,
772+
"is_masked": False,
753773
"link_reach": grand_child.link_reach,
754774
"link_role": grand_child.link_role,
755775
"numchild": 0,
@@ -772,6 +792,7 @@ def test_api_documents_descendants_list_authenticated_related_team_members(
772792
"excerpt": child2.excerpt,
773793
"id": str(child2.id),
774794
"is_favorite": False,
795+
"is_masked": False,
775796
"link_reach": child2.link_reach,
776797
"link_role": child2.link_role,
777798
"numchild": 0,

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def test_api_documents_list_format():
7272
"depth": 1,
7373
"excerpt": document.excerpt,
7474
"is_favorite": True,
75+
"is_masked": False,
7576
"link_reach": document.link_reach,
7677
"link_role": document.link_role,
7778
"nb_accesses_ancestors": 3,
@@ -408,6 +409,7 @@ def test_api_documents_list_favorites_no_extra_queries(django_assert_num_queries
408409
assert len(results) == 5
409410

410411
assert all(result["is_favorite"] is False for result in results)
412+
assert all(result["is_masked"] is False for result in results)
411413

412414
# Mark documents as favorite and check results again
413415
for document in special_documents:
@@ -427,3 +429,5 @@ def test_api_documents_list_favorites_no_extra_queries(django_assert_num_queries
427429
assert result["is_favorite"] is True
428430
else:
429431
assert result["is_favorite"] is False
432+
# All documents should be unmasked in this test
433+
assert result["is_masked"] is False

0 commit comments

Comments
 (0)