[FIX] project: sharing, restrict child_ids an tag_ids for portals
Oversight in 06919a232251cbd68a28500757aef5cd2e3363a0 Need to handle `default_child_ids` and `default_tag_ids` as well. closes odoo/odoo#153397 X-original-commit: 7d521b129c82e38afe50cd8b81cb2081c157aceb Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
This commit is contained in:
@@ -796,7 +796,7 @@ class Task(models.Model):
|
||||
error_message = _('You cannot write on %s fields in task.', ', '.join(unauthorized_fields))
|
||||
raise AccessError(error_message)
|
||||
|
||||
def _get_sudo_portal_vals(self, vals):
|
||||
def _get_portal_sudo_vals(self, vals, defaults=False):
|
||||
""" returns the values which must be written without and with sudo when a portal user creates / writes a task.
|
||||
:param vals: dict of {field: value}, the values to create/write
|
||||
:return: a tuple with 2 dicts:
|
||||
@@ -804,9 +804,25 @@ class Task(models.Model):
|
||||
- the second with the values to write with sudo
|
||||
"""
|
||||
vals_no_sudo = {key: val for key, val in vals.items() if self._fields[key].type in ('one2many', 'many2many')}
|
||||
if defaults:
|
||||
vals_no_sudo.update({
|
||||
key[8:]: value
|
||||
for key, value in self.env.context.items()
|
||||
if key.startswith('default_') and key[8:] in self.SELF_WRITABLE_FIELDS and self._fields[key[8:]].type in ('one2many', 'many2many')
|
||||
})
|
||||
vals_sudo = {key: val for key, val in vals.items() if key not in vals_no_sudo}
|
||||
return vals_no_sudo, vals_sudo
|
||||
|
||||
@api.model
|
||||
def _get_portal_sudo_context(self):
|
||||
return {
|
||||
key: value for key, value in self.env.context.items()
|
||||
if key == 'default_project_id'
|
||||
or key == 'default_user_ids' and value is False
|
||||
or not key.startswith('default_')
|
||||
or key[8:] in (field for field in self.SELF_WRITABLE_FIELDS if self._fields[field].type not in ('one2many', 'many2many'))
|
||||
}
|
||||
|
||||
def read(self, fields=None, load='_classic_read'):
|
||||
self._ensure_fields_are_accessible(fields)
|
||||
return super(Task, self).read(fields=fields, load=load)
|
||||
@@ -868,16 +884,6 @@ class Task(models.Model):
|
||||
|
||||
return tasks
|
||||
|
||||
@api.model
|
||||
def _get_portal_sudo_context(self):
|
||||
return {
|
||||
key: value for key, value in self.env.context.items()
|
||||
if key == 'default_project_id'
|
||||
or key == 'default_user_ids' and value is False
|
||||
or not key.startswith('default_')
|
||||
or key[8:] in self.SELF_WRITABLE_FIELDS
|
||||
}
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
new_context = dict(self.env.context)
|
||||
@@ -951,12 +957,12 @@ class Task(models.Model):
|
||||
# in order to compute the field tracking
|
||||
was_in_sudo = self.env.su
|
||||
if is_portal_user:
|
||||
self = self.sudo().with_context(self._get_portal_sudo_context())
|
||||
vals_list_no_sudo, vals_list = zip(*(self._get_sudo_portal_vals(vals) for vals in vals_list))
|
||||
vals_list_no_sudo, vals_list = zip(*(self._get_portal_sudo_vals(vals, defaults=True) for vals in vals_list))
|
||||
self_no_sudo, self = self, self.sudo().with_context(self._get_portal_sudo_context())
|
||||
tasks = super(Task, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
|
||||
if is_portal_user:
|
||||
for task, vals in zip(tasks, vals_list_no_sudo):
|
||||
task.sudo(was_in_sudo).write(vals)
|
||||
for task, vals in zip(tasks.with_env(self_no_sudo.env), vals_list_no_sudo):
|
||||
task.write(vals)
|
||||
tasks._populate_missing_personal_stages()
|
||||
self._task_message_auto_subscribe_notify({task: task.user_ids - self.env.user for task in tasks})
|
||||
|
||||
@@ -1103,7 +1109,7 @@ class Task(models.Model):
|
||||
# in order to keep the same name than the task.
|
||||
if portal_can_write:
|
||||
self_no_sudo, self = self, self.sudo().with_context(self._get_portal_sudo_context())
|
||||
vals_no_sudo, vals = self._get_sudo_portal_vals(vals)
|
||||
vals_no_sudo, vals = self._get_portal_sudo_vals(vals)
|
||||
|
||||
# Track user_ids to send assignment notifications
|
||||
old_user_ids = {t: t.user_ids for t in self.sudo()}
|
||||
|
||||
@@ -172,6 +172,18 @@ class TestProjectSharing(TestProjectSharingCommon):
|
||||
with self.assertRaisesRegex(AccessError, "top-secret records"):
|
||||
Task.create({'name': 'foo', 'child_ids': [Command.set([self.task_no_collabo.id])]})
|
||||
|
||||
# Same thing but using context defaults
|
||||
with self.assertRaisesRegex(AccessError, "top-secret records"):
|
||||
Task.with_context(default_child_ids=[Command.update(self.task_no_collabo.id, {'name': 'Foo'})]).create({'name': 'foo'})
|
||||
with self.assertRaisesRegex(AccessError, "top-secret records"):
|
||||
Task.with_context(default_child_ids=[Command.delete(self.task_no_collabo.id)]).create({'name': 'foo'})
|
||||
with self.assertRaisesRegex(AccessError, "top-secret records"):
|
||||
Task.with_context(default_child_ids=[Command.unlink(self.task_no_collabo.id)]).create({'name': 'foo'})
|
||||
with self.assertRaisesRegex(AccessError, "top-secret records"):
|
||||
Task.with_context(default_child_ids=[Command.link(self.task_no_collabo.id)]).create({'name': 'foo'})
|
||||
with self.assertRaisesRegex(AccessError, "top-secret records"):
|
||||
Task.with_context(default_child_ids=[Command.set([self.task_no_collabo.id])]).create({'name': 'foo'})
|
||||
|
||||
# Create/update a tag through tag_ids
|
||||
with self.assertRaisesRegex(AccessError, "not allowed to create 'Project Tags'"):
|
||||
Task.create({'name': 'foo', 'tag_ids': [Command.create({'name': 'Bar'})]})
|
||||
@@ -180,6 +192,14 @@ class TestProjectSharing(TestProjectSharingCommon):
|
||||
with self.assertRaisesRegex(AccessError, "not allowed to delete 'Project Tags'"):
|
||||
Task.create({'name': 'foo', 'tag_ids': [Command.delete(self.task_tag.id)]})
|
||||
|
||||
# Same thing but using context defaults
|
||||
with self.assertRaisesRegex(AccessError, "not allowed to create 'Project Tags'"):
|
||||
Task.with_context(default_tag_ids=[Command.create({'name': 'Bar'})]).create({'name': 'foo'})
|
||||
with self.assertRaisesRegex(AccessError, "not allowed to modify 'Project Tags'"):
|
||||
Task.with_context(default_tag_ids=[Command.update(self.task_tag.id, {'name': 'Bar'})]).create({'name': 'foo'})
|
||||
with self.assertRaisesRegex(AccessError, "not allowed to delete 'Project Tags'"):
|
||||
Task.with_context(default_tag_ids=[Command.delete(self.task_tag.id)]).create({'name': 'foo'})
|
||||
|
||||
task = Task.create({'name': 'foo', 'tag_ids': [Command.link(self.task_tag.id)]})
|
||||
self.assertEqual(task.tag_ids, self.task_tag)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user