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
"""
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.

"""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.

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 🤷‍♂️

"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 ^^'

}

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

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

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
@sampaccoud
Copy link
Member

sampaccoud commented Sep 15, 2025

The philosophy behind the duplicate feature is: "if you can see it you can duplicate it".
This is to avoid tricky copies which were raising bugs (media access, etc) and removing the possibility to link copies.
So I don't think this is a bug and i think we should not merge this PR.

More generally on the implementation, heritage is more complex than looking at the parent and caching get_abilities is more complicated than proposed here. I think it would trigger tricky bugs, and complicate group sharing. Also, the heavy lifting is done in the queryset and the get_abilities method is not where the time is spent so I think we should cache higher in the view if one day we do. But that's far from necessary with our current traffic so let's keep it live until we face a problem ?

@lunika lunika changed the title 🐛(backend) fix wrong permission check on sub page duplicate action 🐛(backend) fix wrong permission check on sub page duplicate action [DO NOT MERGE] Sep 15, 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
3 participants