[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
This commit is contained in:
Xavier BOL (xbo)
2022-02-14 13:22:36 +01:00
parent 0829316038
commit 70e5f6ccbb
6 changed files with 54 additions and 11 deletions
+2 -2
View File
@@ -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
+11 -6
View File
@@ -147,19 +147,22 @@ class ProjectCustomerPortal(CustomerPortal):
return request.render("project.portal_my_projects", values)
@http.route(['/my/project/<int:project_id>'], 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/<int:project_id>/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/<int:project_id>/task/<int:task_id>', type='http', auth='public', website=True)
+34
View File
@@ -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 = {
@@ -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);
}
}
}
@@ -9,7 +9,7 @@
</template>
<template id="project_sharing" name="Project Sharing View">
<iframe width="100%" height="100%" frameborder="0" t-attf-src="/my/project/{{ project_id }}/project_sharing"/>
<iframe width="100%" height="100%" frameborder="0" t-attf-src="/my/project/{{ project_id }}{{ '/' + task_id if task_id else '' }}/project_sharing"/>
</template>
<template id="project_sharing_embed" name="Project Sharing View Embed">
@@ -159,7 +159,8 @@
</header>
<sheet string="Task">
<div class="oe_button_box" name="button_box">
<button name="action_open_parent_task" type="object" special="cancel" class="oe_stat_button o_debounce_disabled" icon="fa-tasks" string="Parent Task" attrs="{'invisible': [('parent_id', '=', False)]}"/>
<field name="display_parent_task_button" invisible="1"/>
<button name="action_project_sharing_view_parent_task" type="object" class="oe_stat_button" icon="fa-tasks" string="Parent Task" attrs="{'invisible': [('display_parent_task_button', '=', False)]}"/>
</div>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<div class="oe_title pr-0">