-
Notifications
You must be signed in to change notification settings - Fork 398
🐛(backend) fix wrong permission check on sub page duplicate action #1356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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
@@ -463,6 +474,42 @@ def is_leaf(self): | |||
""" | |||
return not self.has_deleted_children and self.numchild == 0 | |||
|
|||
def get_ancestors(self): |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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.
src/backend/core/models.py
Outdated
@@ -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): |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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? ^^'
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
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.
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
Fixes #1329