From 70e5f6ccbb8c2efdf3645cb129a7824454cb40d1 Mon Sep 17 00:00:00 2001 From: "Xavier BOL (xbo)" Date: Fri, 24 Sep 2021 11:19:42 +0200 Subject: [PATCH] [IMP] project: get parent task of another project in project sharing Before this commit, the portal user can see the parent stat button in project sharing form view of task if the parent is in the same project. This button can be clicked and it redirects the user to the parent task form view in the project sharing. This commit improves this button and its visibility in project sharing feature. The button is visible only if the current user has access to the project of the parent task. That is the privacy visibility of the project should be set to 'portal'. If the portal user has access to the project of the parent task and he is not a collaborator of this project, then the current user will be redirected to the classic portal view of the parent task. If it is a collaborator then we display the parent task in the project sharing feature. task-2648955 Closes #82379 --- addons/hr_timesheet/controllers/project.py | 4 +-- addons/project/controllers/portal.py | 17 ++++++---- addons/project/models/project.py | 34 +++++++++++++++++++ .../src/project_sharing/project_sharing.js | 5 ++- .../views/project_sharing_templates.xml | 2 +- .../project/views/project_sharing_views.xml | 3 +- 6 files changed, 54 insertions(+), 11 deletions(-) diff --git a/addons/hr_timesheet/controllers/project.py b/addons/hr_timesheet/controllers/project.py index 970ae2fdb0f..102b6cfe530 100644 --- a/addons/hr_timesheet/controllers/project.py +++ b/addons/hr_timesheet/controllers/project.py @@ -10,8 +10,8 @@ from odoo.addons.project.controllers.portal import CustomerPortal class ProjectCustomerPortal(CustomerPortal): - def _prepare_project_sharing_session_info(self, project): - session_info = super()._prepare_project_sharing_session_info(project) + def _prepare_project_sharing_session_info(self, project, task=None): + session_info = super()._prepare_project_sharing_session_info(project, task) company = project.company_id timesheet_encode_uom = company.timesheet_encode_uom_id diff --git a/addons/project/controllers/portal.py b/addons/project/controllers/portal.py index 63cd3bd2a22..b7e108713d6 100644 --- a/addons/project/controllers/portal.py +++ b/addons/project/controllers/portal.py @@ -147,19 +147,22 @@ class ProjectCustomerPortal(CustomerPortal): return request.render("project.portal_my_projects", values) @http.route(['/my/project/'], type='http', auth="public", website=True) - def portal_my_project(self, project_id=None, access_token=None, page=1, date_begin=None, date_end=None, sortby=None, search=None, search_in='content', groupby=None, **kw): + def portal_my_project(self, project_id=None, access_token=None, page=1, date_begin=None, date_end=None, sortby=None, search=None, search_in='content', groupby=None, task_id=None, **kw): try: project_sudo = self._document_check_access('project.project', project_id, access_token) except (AccessError, MissingError): return request.redirect('/my') if project_sudo.with_user(request.env.user)._check_project_sharing_access(): - return request.render("project.project_sharing_portal", {'project_id': project_id}) + values = {'project_id': project_id} + if task_id: + values['task_id'] = task_id + return request.render("project.project_sharing_portal", values) project_sudo = project_sudo if access_token else project_sudo.with_user(request.env.user) values = self._project_get_page_view_values(project_sudo, access_token, page, date_begin, date_end, sortby, search, search_in, groupby, **kw) values['task_url'] = 'project/%s/task' % project_id return request.render("project.portal_my_project", values) - def _prepare_project_sharing_session_info(self, project): + def _prepare_project_sharing_session_info(self, project, task=None): session_info = request.env['ir.http'].session_info() user_context = request.session.get_context() if request.session.uid else {} mods = conf.server_wide_modules or [] @@ -188,17 +191,19 @@ class ProjectCustomerPortal(CustomerPortal): # FIXME: See if we prefer to give only the currency that the portal user just need to see the correct information in project sharing currencies=request.env['ir.http'].get_currencies(), ) + if task: + session_info['open_task_action'] = task.action_project_sharing_open_task() return session_info @http.route("/my/project//project_sharing", type="http", auth="user", methods=['GET']) - def render_project_backend_view(self, project_id): + def render_project_backend_view(self, project_id, task_id=None): project = request.env['project.project'].sudo().browse(project_id) if not project.exists() or not project.with_user(request.env.user)._check_project_sharing_access(): return request.not_found() - + task = task_id and request.env['project.task'].browse(int(task_id)) return request.render( 'project.project_sharing_embed', - {'session_info': self._prepare_project_sharing_session_info(project)}, + {'session_info': self._prepare_project_sharing_session_info(project, task)}, ) @http.route('/my/project//task/', type='http', auth='public', website=True) diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 00faf9fed40..29b2dbfc3f5 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -44,6 +44,7 @@ PROJECT_TASK_READABLE_FIELDS = { 'legend_blocked', 'legend_done', 'user_ids', + 'display_parent_task_button', } PROJECT_TASK_WRITABLE_FIELDS = { @@ -1038,6 +1039,9 @@ class Task(models.Model): domain="[('allow_task_dependencies', '=', True), ('id', '!=', id)]") dependent_tasks_count = fields.Integer(string="Dependent Tasks", compute='_compute_dependent_tasks_count') + # Project sharing fields + display_parent_task_button = fields.Boolean(compute='_compute_display_parent_task_button', compute_sudo=True) + # recurrence fields allow_recurring_tasks = fields.Boolean(related='project_id.allow_recurring_tasks') recurring_task = fields.Boolean(string="Recurrent") @@ -1470,6 +1474,11 @@ class Task(models.Model): """ return [('id', 'inselect', (query, [f'%{value}%']))] + def _compute_display_parent_task_button(self): + accessible_parent_tasks = self.parent_id.with_user(self.env.user)._filter_access_rules('read') + for task in self: + task.display_parent_task_button = task.parent_id in accessible_parent_tasks + @api.returns('self', lambda value: value.id) def copy(self, default=None): if default is None: @@ -2113,6 +2122,26 @@ class Task(models.Model): 'context': self._context } + def action_project_sharing_view_parent_task(self): + if self.parent_id.project_id != self.project_id and self.user_has_groups('base.group_portal'): + project = self.parent_id.project_id._filter_access_rules_python('read') + if project: + url = f"/my/projects/{self.parent_id.project_id.id}/task/{self.parent_id.id}" + if project._check_project_sharing_access(): + url = f"/my/projects/{self.parent_id.project_id.id}?task_id={self.parent_id.id}" + return { + "name": "Portal Parent Task", + "type": "ir.actions.act_url", + "url": url, + } + elif self.display_parent_task_button: + return self.parent_id.get_portal_url() + # The portal user has no access to the parent task, so normally the button should be invisible. + return {} + action = self.action_open_parent_task() + action['views'] = [(self.env.ref('project.project_sharing_project_task_view_form').id, 'form')] + return action + # ------------ # Actions # ------------ @@ -2126,6 +2155,11 @@ class Task(models.Model): 'context': self._context } + def action_project_sharing_open_task(self): + action = self.action_open_task() + action['views'] = [[self.env.ref('project.project_sharing_project_task_view_form').id, 'form']] + return action + def action_dependent_tasks(self): self.ensure_one() action = { diff --git a/addons/project/static/src/project_sharing/project_sharing.js b/addons/project/static/src/project_sharing/project_sharing.js index 0f9a53db202..98d4118cffd 100644 --- a/addons/project/static/src/project_sharing/project_sharing.js +++ b/addons/project/static/src/project_sharing/project_sharing.js @@ -43,7 +43,7 @@ export class ProjectSharingWebClient extends Component { } async _showView() { - const { action_name, project_id } = session; + const { action_name, project_id, open_task_action } = session; await this.actionService.doAction( action_name, { @@ -53,6 +53,9 @@ export class ProjectSharingWebClient extends Component { } } ); + if (open_task_action) { + await this.actionService.doAction(open_task_action); + } } } diff --git a/addons/project/views/project_sharing_templates.xml b/addons/project/views/project_sharing_templates.xml index 38dda9405d8..3759ba7fcdf 100644 --- a/addons/project/views/project_sharing_templates.xml +++ b/addons/project/views/project_sharing_templates.xml @@ -9,7 +9,7 @@