(backend) normalize explicit link reach on restriction deactivation

The reach kept from the restriction period is reset to inherit when
the reattached parent already grants as much or more. A more open
explicit reach survives, matching the role normalization rule.
This commit is contained in:
Nicolas Clerc
2026-08-13 17:53:37 +02:00
parent a65e03fab1
commit b3f7c9c1ea
2 changed files with 54 additions and 1 deletions
+12
View File
@@ -1672,6 +1672,17 @@ class Item(TreeModel, BaseModel):
if redundant_ids:
ItemAccess.objects.filter(id__in=redundant_ids).delete()
def _normalize_explicit_link_reach(self):
"""Reset the link reach to inherit when inferior or equal to the inherited one."""
# The cached ancestors definition predates the move, recompute it
self._ancestors_link_definition = None
inherited_reach = self.ancestors_link_definition["link_reach"]
if LinkReachChoices.get_priority(self.link_reach) <= LinkReachChoices.get_priority(
inherited_reach
):
self.link_reach = None
self.save(update_fields=["link_reach"])
@transaction.atomic
def unrestrict(self):
"""Lift restriction and reattach the folder at its shortcut location."""
@@ -1706,6 +1717,7 @@ class Item(TreeModel, BaseModel):
self.save(update_fields=["title"])
self.move(parent)
self._normalize_explicit_accesses()
self._normalize_explicit_link_reach()
self.invalidate_nb_accesses_cache()
@@ -429,7 +429,48 @@ def test_models_items_restricted_unrestrict_keeps_access_without_inheritance():
assert models.ItemAccess.objects.filter(item=folder, user=user, role="owner").exists()
def test_models_items_restricted_deactivate_restriction_deduplicates_title():
def test_models_items_restricted_unrestrict_resets_redundant_link_reach():
"""Deactivating restriction resets a link reach inferior or equal to inherited."""
user = factories.UserFactory()
parent = factories.ItemFactory(
type=models.ItemTypeChoices.FOLDER,
link_reach=LinkReachChoices.PUBLIC,
link_role="reader",
)
folder = factories.ItemFactory(
parent=parent,
type=models.ItemTypeChoices.FOLDER,
link_reach=None,
)
folder = folder.restrict(user)
assert folder.link_reach == LinkReachChoices.RESTRICTED
folder = folder.unrestrict()
assert folder.link_reach is None
def test_models_items_restricted_unrestrict_keeps_superior_link_reach():
"""Deactivating restriction keeps a link reach superior to inherited."""
user = factories.UserFactory()
parent = factories.ItemFactory(
type=models.ItemTypeChoices.FOLDER,
link_reach=LinkReachChoices.AUTHENTICATED,
link_role="reader",
)
folder = factories.ItemFactory(
parent=parent,
type=models.ItemTypeChoices.FOLDER,
link_reach=LinkReachChoices.PUBLIC,
)
folder = folder.restrict(user)
folder = folder.unrestrict()
assert folder.link_reach == LinkReachChoices.PUBLIC
def test_models_items_restricted_unrestrict_deduplicates_title():
"""Deactivating restriction renames the folder when its title was reused."""
user = factories.UserFactory()
parent = factories.ItemFactory(type=models.ItemTypeChoices.FOLDER)