[FW][FIX] knowledge: correctly handle desync status when detaching children

This commit fixes the case when we have desynchronized children for which the
current user does not have write access and we move the parent to the private
section (or archive the parent).

In that case, children that are desynchronized should not have the members from
their parents copied onto them when detaching.

See '_detach_unwritable_descendants' and associated tests for more details.

Task-2859616

X-original-commit: odoo/odoo@348740fa9f
Part-of: odoo/odoo#95471
This commit is contained in:
Aurélien Warnon
2022-07-07 17:31:03 +02:00
committed by Thibault Delavallée
parent 57d04db7e1
commit 48b99e2f0c
2 changed files with 84 additions and 3 deletions
+12 -3
View File
@@ -1156,6 +1156,10 @@ class Article(models.Model):
This method takes care of correctly detaching those children and returns
a subset of children to which the user effectively has write access to.
As the children are moved to "root" articles we also reset their desync
status. Indeed, a root article cannot be desyncronized as stated by SQL
constraints.
Note: this might produce funny results when involving a hierarchy with
invisible nodes in it (A-B-C where B is not achievable). You might
archive / privatize articles and break hierarchy without knowing it.
@@ -1167,18 +1171,23 @@ class Article(models.Model):
other_descendants_sudo = all_descendants_sudo - writable_descendants
# copy rights to allow breaking the hierarchy while keeping access for members
for article_sudo in other_descendants_sudo:
# do this on synchronized articles as desynchronized one do not inherit from parent
for article_sudo in other_descendants_sudo.filtered(lambda article: not article.is_desynchronized):
article_sudo.write({
'article_member_ids': article_sudo._copy_access_from_parents_commands()
})
# create new root articles: direct children of these articles
# create new root articles: direct children of these articles, reset desync
new_roots_woperm = other_descendants_sudo.filtered(lambda article: article.parent_id in self and not article.internal_permission)
new_roots_wperm = other_descendants_sudo.filtered(lambda article: article.parent_id in self and article.internal_permission)
if new_roots_wperm:
new_roots_wperm.write({'parent_id': False})
new_roots_wperm.write({
'is_desynchronized': False,
'parent_id': False
})
for new_root in new_roots_woperm:
new_root.write({
'is_desynchronized': False,
'internal_permission': new_root.inherited_permission,
'parent_id': False,
})
@@ -607,6 +607,78 @@ class TestKnowledgeArticleBusiness(KnowledgeCommonWData):
wkspace_child_no_access.with_env(self.env).body
wkspace_child_no_access.with_user(self.user_employee2).body
@mute_logger('odoo.addons.base.models.ir_rule', 'odoo.models.unlink')
@users('employee')
def test_article_make_private_w_desynchronized(self):
""" Test a special case when making private: we have desynchronized children.
Children that are de-synchronized should NOT have members from their parent(s)
copied onto them when they are detached.
Specific setup for this test
# - Playground workspace w+ (customer-r+,employee-w+)
# - Child1 " w+DES (customer-r+,employee-r+)
# - Gd Child1 " "
# - Gd Child2 " "
# - GdGd Child1 " "
# - Child2 " "
# - Gd Child1 " "
# - GdGd Child " "
"""
# add employee on playground and desynchronize its child
self.article_workspace._add_members(self.partner_employee, 'write')
self.workspace_children[0]._set_member_permission(
self.article_workspace.article_member_ids.filtered(
lambda member: member.partner_id == self.partner_employee
),
'read',
is_based_on=True,
)
# check updated data
self.assertTrue(self.workspace_children[0].is_desynchronized)
self.assertMembers(
self.article_workspace,
'write',
{self.partner_employee: 'write'}
)
self.assertMembers(
self.workspace_children[0],
'write',
{self.partner_employee: 'read'}
)
article_workspace = self.article_workspace.with_env(self.env)
[workspace_child_desync, workspace_child_tosync] = self.workspace_children.with_env(self.env)
# add a member on the parent, it will NOT be propagated to the desync child
article_workspace._add_members(self.customer, 'read')
self.assertMembers(
article_workspace,
'write',
{self.customer: 'read', self.partner_employee: 'write'}
)
# now move the article to private and check the post-processing
article_workspace._move_and_make_private()
# 1. desync article: moved to root (as employee does not have write access)
# and is not desynchronized (root articles are never desynchornized)
# should be moved to root (as employee does not have write access)
self.assertEqual(workspace_child_desync.category, "workspace")
self.assertFalse(workspace_child_desync.is_desynchronized)
self.assertFalse(workspace_child_desync.parent_id)
# it should NOT have had customer access copied onto it as it was desync when we moved it
self.assertMembers(
workspace_child_desync,
"write",
{self.partner_employee: 'read'}
)
# 2. sync article: NOT moved to root (as employee has write access) and is
# still sunchronized
self.assertEqual(workspace_child_tosync.category, "private")
self.assertFalse(workspace_child_desync.is_desynchronized)
self.assertEqual(workspace_child_tosync.parent_id, article_workspace)
@mute_logger('odoo.addons.base.models.ir_rule', 'odoo.models.unlink')
@users('employee_manager')
def test_article_make_private_w_parent(self):