Skip to content

Conversation

lunika
Copy link
Member

@lunika lunika commented Sep 9, 2025

Purpose

A user with only read access to a document and its sub documents should not be able to duplicate a sub document in the document tree. To avoid this we have to compute the direct parent abilities to determine if it can create a new children. Doing so computes the abilities in cascade from the document to the root tree. To save some queries and not compute again and again the same ability, we create a abilities cache. The hard part is to invalidate this cache. The cache is invalidated if a related DocumentAccess instance is updated or deleted and also if the document link_reach or link_role is updated. To introspect the modification made on the model itself when the user saves it, we decided to use the library django-dirtyfields

Proposal

  • 🐛(backend) fix wrong permission checj on sub page duplicate action

Fixes #1329

A user with only read access to a document and it sub documents should
not be able to duplicate a sub document in the document tree. To avoid
this we have to compute the direct parent abilities to determine if it
can create a new children. Doing so computes the abilities in cascase
from the document to the root tree. To asave some quesries and not
compute again and again the same ability, we create a abilities cache.
The hard part is to invalidate this cache. The cache is invalidated if a
related DocumentAccess instance is updated or deleted and also if the
document link_reach or link_role is updated. To introspect the
modification made on the model it self when the user save it, we decided
to use the library django-dirtyfields
@lunika lunika requested review from sampaccoud and qbey September 9, 2025 13:10
@lunika lunika self-assigned this Sep 9, 2025
@lunika lunika added bug Something isn't working enhancement improve an existing feature backend labels Sep 9, 2025
@@ -463,6 +474,42 @@ def is_leaf(self):
"""
return not self.has_deleted_children and self.numchild == 0

def get_ancestors(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to override the base MP_Node method ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To add the select_releated("creator") to save one query. The creator is used in the abilities.

@@ -712,10 +759,44 @@ def computed_link_role(self):
"""Actual link role on the document."""
return self.computed_link_definition["link_role"]

def _compute_abilities_cache_key(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "compute" what a big word for a simple function... "get"? or even simply a property?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I will change it for get.

@@ -267,10 +267,10 @@ def test_api_documents_children_list_authenticated_public_or_authenticated_paren
child1, child2 = factories.DocumentFactory.create_batch(2, parent=document)
factories.UserDocumentAccessFactory(document=child1)

with django_assert_num_queries(10):
with django_assert_num_queries(17):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it's under control? ^^'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With out the cache it will be 36 🤷‍♂️

@@ -500,7 +500,7 @@ def test_api_documents_retrieve_authenticated_related_parent():
"cors_proxy": True,
"content": True,
"destroy": access.role in ["administrator", "owner"],
"duplicate": True,
"duplicate": access.role != "reader",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading the test, I don't even know if it's what we want or not... this has become too complexe for me ^^'

@@ -808,6 +808,12 @@ class Base(Configuration):
),
}

DOCUMENT_ABILITIES_CACHE_TIMEOUT = values.IntegerValue(
default=60 * 60, # 1 hour
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could even be 12 hours, no? Leave it like that, we will fine tune in deployment

@@ -98,7 +98,7 @@ def test_api_documents_children_list_anonymous_public_parent(django_assert_num_q

with django_assert_num_queries(9):
APIClient().get(f"/api/v1.0/documents/{document.id!s}/children/")
with django_assert_num_queries(5):
with django_assert_num_queries(4):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The abilities are in cache, there is no need to make a query to retrieve the roles in the accesses

@@ -187,7 +187,7 @@ def test_api_documents_children_list_authenticated_unrelated_public_or_authentic
child1, child2 = factories.DocumentFactory.create_batch(2, parent=document)
factories.UserDocumentAccessFactory(document=child1)

with django_assert_num_queries(9):
with django_assert_num_queries(11):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This number of queries depends on the number of children. There is one more query for each child.

@lunika lunika requested a review from qbey September 12, 2025 07:22
@lunika lunika changed the title 🐛(backend) fix wrong permission checj on sub page duplicate action 🐛(backend) fix wrong permission check on sub page duplicate action Sep 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend bug Something isn't working enhancement improve an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

wrong permission check on sub page duplicate action
2 participants