From ccf606e026a49a77731df20345f109aa0c64ef49 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Tue, 5 Jul 2016 23:03:32 +0200 Subject: [PATCH 1/4] [ADD] website_project: Portal access to Projects Split project to move portal features to a new module named website_project. Portal users may now access their projects and tasks throught the website_portal My account page. The Backend portal menuitem is removed. Simplify the privacy settings of project, to be visible to portal users the project must be in 'portal' mode. Original authors: Vipul Bhatt, Florian Wintjens --- addons/project/__openerp__.py | 1 - addons/project/data/project_demo.xml | 4 - addons/project/models/project.py | 27 +- addons/project/security/ir.model.access.csv | 5 - addons/project/security/project_security.xml | 48 +-- addons/project/tests/test_access_rights.py | 51 +-- addons/project/tests/test_project_base.py | 4 +- addons/project/views/project_views.xml | 7 +- addons/website_portal/__openerp__.py | 1 - addons/website_portal/views/templates.xml | 5 +- addons/website_project/__init__.py | 4 + addons/website_project/__openerp__.py | 20 ++ .../website_project/controllers/__init__.py | 4 + addons/website_project/controllers/main.py | 130 ++++++++ addons/website_project/demo/project_demo.xml | 12 + .../security/ir.model.access.csv | 6 + .../security/project_security.xml | 31 ++ addons/website_project/tests/__init__.py | 4 + .../tests/test_access_rights.py | 39 +++ .../views/project_templates.xml | 295 ++++++++++++++++++ 20 files changed, 569 insertions(+), 129 deletions(-) create mode 100644 addons/website_project/__init__.py create mode 100644 addons/website_project/__openerp__.py create mode 100644 addons/website_project/controllers/__init__.py create mode 100644 addons/website_project/controllers/main.py create mode 100644 addons/website_project/demo/project_demo.xml create mode 100644 addons/website_project/security/ir.model.access.csv create mode 100644 addons/website_project/security/project_security.xml create mode 100644 addons/website_project/tests/__init__.py create mode 100644 addons/website_project/tests/test_access_rights.py create mode 100644 addons/website_project/views/project_templates.xml diff --git a/addons/project/__openerp__.py b/addons/project/__openerp__.py index 2f44c5ef01d..23614d67313 100644 --- a/addons/project/__openerp__.py +++ b/addons/project/__openerp__.py @@ -13,7 +13,6 @@ 'product', 'analytic', 'mail', - 'portal', 'resource', 'web_kanban', 'web_planner', diff --git a/addons/project/data/project_demo.xml b/addons/project/data/project_demo.xml index 95ba9da9078..f2201f6fed5 100644 --- a/addons/project/data/project_demo.xml +++ b/addons/project/data/project_demo.xml @@ -65,14 +65,10 @@ Website for Sales & WMS 3 - - portal project.task - Research & Development diff --git a/addons/project/models/project.py b/addons/project/models/project.py index a979fd74317..a2a17937ff4 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -104,14 +104,6 @@ class Project(models.Model): """ Overriden in project_issue to offer more options """ return [('project.task', "Tasks")] - def _get_visibility_selection(self): - """ Overriden in portal_project to offer more options """ - return [ - ('employees', _('Visible by all employees')), - ('followers', _('On invitation only')), - ('portal', _('Shared with a customer')) - ] - @api.multi def attachment_tree_view(self): self.ensure_one() @@ -171,7 +163,6 @@ class Project(models.Model): # Lambda indirection method to avoid passing a copy of the overridable method when declaring the field _alias_models = lambda self: self._get_alias_models() - _visibility_selection = lambda self: self._get_visibility_selection() active = fields.Boolean(default=True, help="If the active field is set to False, it will allow you to hide the project without removing it.") @@ -203,15 +194,19 @@ class Project(models.Model): "with Tasks (or optionally Issues if the Issue Tracker module is installed).") alias_model = fields.Selection(_alias_models, string="Alias Model", index=True, required=True, default='project.task', help="The kind of document created when an email is received on this project's email alias") - privacy_visibility = fields.Selection(_visibility_selection, string='Privacy', required=True, + privacy_visibility = fields.Selection([ + ('followers', _('On invitation only')), + ('employees', _('Visible by all employees')), + ('portal', _('Visible by following customers')), + ], + string='Privacy', required=True, default='employees', help="Holds visibility of the tasks or issues that belong to the current project:\n" - "- Portal : employees see everything;\n" - " if portal is activated, portal users see the tasks or issues followed by\n" - " them or by someone of their company\n" - "- Employees Only: employees see all tasks or issues\n" - "- Followers Only: employees see only the followed tasks or issues; if portal\n" - " is activated, portal users see the followed tasks or issues.") + "- On invitation only: Employees may only see the followed project, tasks or issues\n" + "- Visible by all employees: Employees may see all project, tasks or issues\n" + "- Visible by following customers: employees see everything;\n" + " if website is activated, portal users may see project, tasks or issues followed by\n" + " them or by someone of their company\n") doc_count = fields.Integer(compute='_compute_attached_docs_count', string="Number of documents attached") date_start = fields.Date(string='Start Date') date = fields.Date(string='Expiration Date', index=True, track_visibility='onchange') diff --git a/addons/project/security/ir.model.access.csv b/addons/project/security/ir.model.access.csv index 5e6a9c682e6..6825917202e 100644 --- a/addons/project/security/ir.model.access.csv +++ b/addons/project/security/ir.model.access.csv @@ -3,7 +3,6 @@ access_project_project,project.project,model_project_project,project.group_proje access_project_project_manager,project.project,model_project_project,project.group_project_manager,1,1,1,1 access_account_analytic_account_user,account.analytic.account,analytic.model_account_analytic_account,project.group_project_user,1,0,0,0 access_account_analytic_account_manager,account.analytic.account,analytic.model_account_analytic_account,project.group_project_manager,1,1,1,1 -access_account_analytic_account_portal,account_analytic_account,analytic.model_account_analytic_account,base.group_portal,1,0,0,0 access_project_task_type_user,project.task.type.user,model_project_task_type,base.group_user,1,0,0,0 access_project_task_type_project_user,project.task.type.project.user,model_project_task_type,project.group_project_user,1,0,0,0 access_project_task_type_manager,project.task.type manager,model_project_task_type,project.group_project_manager,1,1,1,1 @@ -21,8 +20,4 @@ access_resource_calendar_attendance,project.resource_calendar_attendance user,re access_resource_calendar_leaves_user,resource.calendar.leaves user,resource.model_resource_calendar_leaves,project.group_project_user,1,1,1,1 access_project_tags_all,project.project_tags_all,model_project_tags,,1,0,0,0 access_project_tags_manager,project.project_tags_manager,model_project_tags,project.group_project_manager,1,1,1,1 -access_project_tags_portal,project_tags_portal,project.model_project_tags,base.group_portal,1,0,0,0 access_mail_alias,mail.alias,mail.model_mail_alias,project.group_project_manager,1,1,1,1 -access_project_portal,project__portal,project.model_project_project,base.group_portal,1,0,0,0 -access_task_portal,task_portal,project.model_project_task,base.group_portal,1,0,0,0 -access_task_type_portal,task_type_portal,project.model_project_task_type,base.group_portal,1,0,0,0 diff --git a/addons/project/security/project_security.xml b/addons/project/security/project_security.xml index 56c51d7eea2..7f06484836c 100644 --- a/addons/project/security/project_security.xml +++ b/addons/project/security/project_security.xml @@ -43,10 +43,10 @@ - Project: employees: portal, employees or followers + Project: employees: following required for follower-only projects ['|', - ('privacy_visibility', 'in', ['portal', 'employees']), + ('privacy_visibility', '!=', 'followers'), ('message_partner_ids', 'in', [user.partner_id.id]) ] @@ -63,15 +63,13 @@ - Project/Task: employees: portal or employee or (followers and following) + Project/Task: employees: follow required for follower-only projects [ '|', - ('project_id.privacy_visibility', 'in', ['portal', 'employees']), + ('project_id.privacy_visibility', '!=', 'followers'), '|', - '&', - ('project_id.privacy_visibility', '=', 'followers'), - ('project_id.message_partner_ids', 'in', [user.partner_id.id]), + ('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 @@ -87,42 +85,6 @@ - - - Project: portal users: portal or following - - [ - '|', - '&', - ('privacy_visibility', '=', 'portal'), - ('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]), - '&', - ('privacy_visibility', '=', 'followers'), - ('message_partner_ids', 'in', [user.partner_id.id]) - ] - - - - - Project/Task: portal users: (portal and colleagues following) or (followers and following) - - [ - '|', - '|', - '&', - ('project_id.privacy_visibility', '=', 'portal'), - ('project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]), - '&', - ('project_id.privacy_visibility', '=', 'followers'), - ('project_id.message_partner_ids', 'in', [user.partner_id.id]), - '&', - # on employee project can receive messages but not access the object - ('project_id.privacy_visibility', '!=', 'employees'), - ('message_partner_ids', 'in', [user.partner_id.id]) - ] - - - Task Analysis multi-company diff --git a/addons/project/tests/test_access_rights.py b/addons/project/tests/test_access_rights.py index 4add7a186c3..db77ecc92cb 100644 --- a/addons/project/tests/test_access_rights.py +++ b/addons/project/tests/test_access_rights.py @@ -31,37 +31,6 @@ class TestPortalProjectBase(TestProjectBase): class TestPortalProject(TestPortalProjectBase): - @mute_logger('openerp.addons.base.ir.ir_model') - def test_portal_project_access_rights(self): - pigs = self.project_pigs - pigs.write({'privacy_visibility': 'portal'}) - - # Do: Alfred reads project -> ok (employee ok public) - pigs.sudo(self.user_projectuser).read(['user_id']) - # Test: all project tasks visible - tasks = self.env['project.task'].sudo(self.user_projectuser).search([('project_id', '=', pigs.id)]) - self.assertEqual(tasks, self.task_1 | self.task_2 | self.task_3 | self.task_4 | self.task_5 | self.task_6, - 'access rights: project user should see all tasks of a portal project') - - # Do: Bert reads project -> crash, no group - self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['user_id']) - # Test: no project task searchable - self.assertRaises(AccessError, self.env['project.task'].sudo(self.user_noone).search, [('project_id', '=', pigs.id)]) - - # Data: task follower - pigs.sudo(self.user_projectmanager).message_subscribe_users(user_ids=[self.user_portal.id]) - self.task_1.sudo(self.user_projectuser).message_subscribe_users(user_ids=[self.user_portal.id]) - self.task_3.sudo(self.user_projectuser).message_subscribe_users(user_ids=[self.user_portal.id]) - # Do: Chell reads project -> ok (portal ok public) - pigs.sudo(self.user_portal).read(['user_id']) - # Do: Donovan reads project -> ko (public ko portal) - self.assertRaises(AccessError, pigs.sudo(self.user_public).read, ['user_id']) - # Test: no access right to project.task - self.assertRaises(AccessError, self.env['project.task'].sudo(self.user_public).search, []) - # Data: task follower cleaning - self.task_1.sudo(self.user_projectuser).message_unsubscribe_users(user_ids=[self.user_portal.id]) - self.task_3.sudo(self.user_projectuser).message_unsubscribe_users(user_ids=[self.user_portal.id]) - @mute_logger('openerp.addons.base.ir.ir_model') def test_employee_project_access_rights(self): pigs = self.project_pigs @@ -76,11 +45,6 @@ class TestPortalProject(TestPortalProjectBase): 'access rights: project user cannot see all tasks of an employees project') # Do: Bert reads project -> crash, no group self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['user_id']) - # Do: Chell reads project -> ko (portal ko employee) - self.assertRaises(AccessError, pigs.sudo(self.user_portal).read, ['user_id']) - # Test: no project task visible + assigned - tasks = self.env['project.task'].sudo(self.user_portal).search([('project_id', '=', pigs.id)]) - self.assertFalse(tasks.ids, 'access rights: portal user should not see tasks of an employees project, even if assigned') # Do: Donovan reads project -> ko (public ko employee) self.assertRaises(AccessError, pigs.sudo(self.user_public).read, ['user_id']) # Do: project user is employee and can create a task @@ -104,27 +68,16 @@ class TestPortalProject(TestPortalProjectBase): # Do: Bert reads project -> crash, no group self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['user_id']) - # Do: Chell reads project -> ko (portal ko employee) - self.assertRaises(AccessError, pigs.sudo(self.user_portal).read, ['user_id']) - # Test: no project task visible - tasks = self.env['project.task'].sudo(self.user_portal).search([('project_id', '=', pigs.id)]) - self.assertEqual(tasks, self.task_3, - 'access rights: portal user should not see tasks of a not-followed followers project, only assigned') - # Do: Donovan reads project -> ko (public ko employee) self.assertRaises(AccessError, pigs.sudo(self.user_public).read, ['user_id']) - # Data: subscribe Alfred, Chell and Donovan as follower - pigs.message_subscribe_users(user_ids=[self.user_projectuser.id, self.user_portal.id, self.user_public.id]) - self.task_1.sudo(self.user_projectmanager).message_subscribe_users(user_ids=[self.user_portal.id, self.user_projectuser.id]) - self.task_3.sudo(self.user_projectmanager).message_subscribe_users(user_ids=[self.user_portal.id, self.user_projectuser.id]) + pigs.message_subscribe_users(user_ids=[self.user_projectuser.id]) # Do: Alfred reads project -> ok (follower ok followers) prout = pigs.sudo(self.user_projectuser) prout.invalidate_cache() prout.read(['user_id']) - # Do: Chell reads project -> ok (follower ok follower) - pigs.sudo(self.user_portal).read(['user_id']) + # Do: Donovan reads project -> ko (public ko follower even if follower) self.assertRaises(AccessError, pigs.sudo(self.user_public).read, ['user_id']) # Do: project user is follower of the project and can create a task diff --git a/addons/project/tests/test_project_base.py b/addons/project/tests/test_project_base.py index 189fc0cab21..ed354fa4bb5 100644 --- a/addons/project/tests/test_project_base.py +++ b/addons/project/tests/test_project_base.py @@ -32,7 +32,7 @@ class TestProjectBase(TestMail): # Test 'Pigs' project cls.project_pigs = cls.env['project.project'].with_context({'mail_create_nolog': True}).create({ 'name': 'Pigs', - 'privacy_visibility': 'portal', + 'privacy_visibility': 'employees', 'alias_name': 'project+pigs', 'partner_id': cls.partner_1.id}) # Already-existing tasks in Pigs @@ -48,7 +48,7 @@ class TestProjectBase(TestMail): # Test 'Goats' project, same as 'Pigs', but with 2 stages cls.project_goats = cls.env['project.project'].with_context({'mail_create_nolog': True}).create({ 'name': 'Goats', - 'privacy_visibility': 'portal', + 'privacy_visibility': 'followers', 'alias_name': 'project+goats', 'partner_id': cls.partner_1.id, 'type_ids': [ diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index 4937c41d29e..b75ef74a358 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -107,8 +107,7 @@ - + @@ -744,10 +743,6 @@ - - -
  • - +
  • @@ -77,7 +77,7 @@ -