diff --git a/addons/project/security/project_security.xml b/addons/project/security/project_security.xml index 6bc0c514544..02ce3a99fe4 100644 --- a/addons/project/security/project_security.xml +++ b/addons/project/security/project_security.xml @@ -82,10 +82,12 @@ Project/Task: employees: follow required for follower-only projects [ - '|', - ('project_id.privacy_visibility', '!=', 'followers'), '|', - ('project_id.message_partner_ids', 'in', [user.partner_id.id]), + '&', + ('project_id', '!=', False), + '|', + ('project_id.privacy_visibility', '!=', 'followers'), + ('project_id.message_partner_ids', 'in', [user.partner_id.id]), '|', ('message_partner_ids', 'in', [user.partner_id.id]), # to subscribe check access to the record, follower is not enough at creation diff --git a/addons/project/tests/test_access_rights.py b/addons/project/tests/test_access_rights.py index ff1c29f69ed..d32f3349043 100644 --- a/addons/project/tests/test_access_rights.py +++ b/addons/project/tests/test_access_rights.py @@ -3,6 +3,7 @@ from odoo.addons.mail.tests.common import mail_new_test_user from odoo.addons.project.tests.test_project_base import TestProjectCommon +from odoo import Command from odoo.exceptions import AccessError, ValidationError from odoo.tests.common import users from odoo.tools import mute_logger @@ -324,3 +325,63 @@ class TestPortalProject(TestProjectPortalCommon): # Do: project user can create a task without project self.assertRaises(AccessError, self.env['project.task'].with_user(self.user_projectuser).with_context({ 'mail_create_nolog': True}).create, {'name': 'Pigs task', 'project_id': pigs.id}) + + +class TestAccessRightsPrivateTask(TestAccessRights): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.private_task = cls.env['project.task'].create({'name': 'OdooBot Private Task'}) + + def setUp(self): + super().setUp() + self.project_user = mail_new_test_user(self.env, 'Project user', groups='project.group_project_user') + + def create_private_task(self, name, with_user=None, **kwargs): + user = with_user or self.env.user + values = {'name': name, 'user_ids': [Command.set(user.ids)], **kwargs} + return self.env['project.task'].with_user(user).create(values) + + @users('Internal user', 'Portal user') + def test_internal_cannot_crud_private_task(self): + with self.assertRaises(AccessError): + self.create_private_task('Private task') + + with self.assertRaises(AccessError): + self.private_task.with_user(self.env.user).write({'name': 'Test write'}) + + with self.assertRaises(AccessError): + self.private_task.with_user(self.env.user).unlink() + + with self.assertRaises(AccessError): + self.private_task.with_user(self.env.user).read(['name']) + + @users('Project user') + def test_project_user_crud_own_private_task(self): + private_task = self.create_private_task('Private task') + + private_task.with_user(self.env.user).write({'name': 'Test write'}) + vals = private_task.with_user(self.env.user).read(['name']) + self.assertEqual(vals[0]['id'], private_task.id) + self.assertEqual(vals[0]['name'], private_task.name) + + @users('Project user') + def test_project_user_cannot_create_private_task_for_another_user(self): + with self.assertRaises(AccessError): + self.create_private_task('test private for another user', self.env.user, user_ids=[Command.set(self.user_projectuser.ids)]) + + @users('Project user') + def test_project_user_cannot_write_private_task_of_another_user(self): + with self.assertRaises(AccessError): + self.private_task.with_user(self.env.user).write({'name': 'Test write'}) + + @users('Project user') + def test_project_user_cannot_read_private_task_of_another_user(self): + with self.assertRaises(AccessError): + self.private_task.with_user(self.env.user).read(['name']) + + @users('Project user') + def test_project_user_cannot_unlink_private_task_of_another_user(self): + with self.assertRaises(AccessError): + self.private_task.with_user(self.env.user).unlink() diff --git a/addons/sale_timesheet/tests/test_sale_service.py b/addons/sale_timesheet/tests/test_sale_service.py index 907aafa030b..03303846f62 100644 --- a/addons/sale_timesheet/tests/test_sale_service.py +++ b/addons/sale_timesheet/tests/test_sale_service.py @@ -602,11 +602,12 @@ class TestSaleService(TestCommonSaleTimesheet): 'gram': 0.0, } + project = self.project_global.copy({'tasks': False}) Product = self.env['product.product'] product_vals = { 'type': 'service', 'service_type': 'timesheet', - 'project_id': self.project_global.id, + 'project_id': project.id, 'service_tracking': 'task_global_project', } @@ -617,7 +618,6 @@ class TestSaleService(TestCommonSaleTimesheet): 'order_id': self.sale_order.id, } - self.project_global.task_ids = False for uom_name in planned_hours_for_uom: uom_id = self.env.ref('uom.product_uom_%s' % uom_name) @@ -637,7 +637,7 @@ class TestSaleService(TestCommonSaleTimesheet): self.sale_order.action_confirm() - tasks = self.project_global.task_ids + tasks = project.task_ids for task in tasks: self.assertEqual(task.planned_hours, planned_hours_for_uom[task.sale_line_id.name])