diff options
| author | Jérome Maes <jem@openerp.com> | 2017-08-09 10:40:09 +0200 |
|---|---|---|
| committer | Jérome Maes <jem@openerp.com> | 2017-08-16 14:56:41 +0200 |
| commit | 424c16f11506664f9bf1a9aa5783a864d0cce8b4 (patch) | |
| tree | bc78740494ffd80ece4ba3a69c576d4fc2c3ff22 | |
| parent | 3cfd64f63f6153c170c9c876fa65976a95da22cb (diff) | |
[MOV] website_project,project: move all features
Making project depending on portal, makes website_project
useless. So move all feature from one module to the other.
| -rw-r--r-- | addons/project/__init__.py | 1 | ||||
| -rw-r--r-- | addons/project/__manifest__.py | 2 | ||||
| -rw-r--r-- | addons/project/controllers/__init__.py | 4 | ||||
| -rw-r--r-- | addons/project/controllers/portal.py (renamed from addons/website_project/controllers/main.py) | 21 | ||||
| -rw-r--r-- | addons/project/data/project_demo.xml | 5 | ||||
| -rw-r--r-- | addons/project/models/project.py | 93 | ||||
| -rw-r--r-- | addons/project/security/ir.model.access.csv | 7 | ||||
| -rw-r--r-- | addons/project/security/project_security.xml | 27 | ||||
| -rw-r--r-- | addons/project/tests/__init__.py | 2 | ||||
| -rw-r--r-- | addons/project/tests/test_portal.py (renamed from addons/website_project/tests/test_access_rights.py) | 0 | ||||
| -rw-r--r-- | addons/project/views/project_portal_templates.xml (renamed from addons/website_project/views/project_templates.xml) | 8 | ||||
| -rw-r--r-- | addons/website_project/demo/project_demo.xml | 12 | ||||
| -rw-r--r-- | addons/website_rating_project/__manifest__.py | 4 |
13 files changed, 153 insertions, 33 deletions
diff --git a/addons/project/__init__.py b/addons/project/__init__.py index 0c023b8d77a..7039d459cb8 100644 --- a/addons/project/__init__.py +++ b/addons/project/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import controllers from . import models from . import report from . import wizard
\ No newline at end of file diff --git a/addons/project/__manifest__.py b/addons/project/__manifest__.py index a279f96deb4..a4f95b3c203 100644 --- a/addons/project/__manifest__.py +++ b/addons/project/__manifest__.py @@ -13,6 +13,7 @@ 'product', 'analytic', 'mail', + 'portal', 'resource', 'web', 'web_planner', @@ -28,6 +29,7 @@ 'views/res_partner_views.xml', 'views/project_config_settings_views.xml', 'views/project_templates.xml', + 'views/project_portal_templates.xml', 'data/web_planner_data.xml', 'data/project_mail_template_data.xml', 'wizard/project_task_merge_wizard_views.xml', diff --git a/addons/project/controllers/__init__.py b/addons/project/controllers/__init__.py new file mode 100644 index 00000000000..903b755e71e --- /dev/null +++ b/addons/project/controllers/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import portal diff --git a/addons/website_project/controllers/main.py b/addons/project/controllers/portal.py index 4e29fb1ccf4..f3f16554b73 100644 --- a/addons/website_project/controllers/main.py +++ b/addons/project/controllers/portal.py @@ -6,14 +6,15 @@ from collections import OrderedDict from odoo import http, _ from odoo.http import request from odoo.addons.portal.controllers.portal import get_records_pager, CustomerPortal + from odoo.osv.expression import OR from odoo.tools import pycompat -class WebsiteAccount(CustomerPortal): +class CustomerPortal(CustomerPortal): def _prepare_portal_layout_values(self): - values = super(WebsiteAccount, self)._prepare_portal_layout_values() + values = super(CustomerPortal, self)._prepare_portal_layout_values() values.update({ 'project_count': request.env['project.project'].search_count([('privacy_visibility', '=', 'portal')]), 'task_count': request.env['project.task'].search_count([('project_id.privacy_visibility', '=', 'portal')]) @@ -21,7 +22,7 @@ class WebsiteAccount(CustomerPortal): return values @http.route(['/my/projects', '/my/projects/page/<int:page>'], type='http', auth="user", website=True) - def my_projects(self, page=1, date_begin=None, date_end=None, sortby=None, **kw): + def portal_my_projects(self, page=1, date_begin=None, date_end=None, sortby=None, **kw): values = self._prepare_portal_layout_values() Project = request.env['project.project'] domain = [('privacy_visibility', '=', 'portal')] @@ -64,17 +65,17 @@ class WebsiteAccount(CustomerPortal): 'searchbar_sortings': searchbar_sortings, 'sortby': sortby }) - return request.render("website_project.my_projects", values) + return request.render("project.portal_my_projects", values) @http.route(['/my/project/<model("project.project"):project>'], type='http', auth="user", website=True) - def my_project(self, project=None, **kw): + def portal_my_project(self, project=None, **kw): vals = {'project': project, } history = request.session.get('my_projects_history', []) vals.update(get_records_pager(history, project)) - return request.render("website_project.my_project", vals) + return request.render("project.portal_my_project", vals) @http.route(['/my/tasks', '/my/tasks/page/<int:page>'], type='http', auth="user", website=True) - def my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', **kw): + def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', **kw): values = self._prepare_portal_layout_values() domain = [('project_id.privacy_visibility', '=', 'portal')] @@ -158,11 +159,11 @@ class WebsiteAccount(CustomerPortal): 'searchbar_filters': OrderedDict(sorted(pycompat.items(searchbar_filters))), 'filterby': filterby, }) - return request.render("website_project.my_tasks", values) + return request.render("project.portal_my_tasks", values) @http.route(['/my/task/<model("project.task"):task>'], type='http', auth="user", website=True) - def my_task(self, task=None, **kw): + def portal_my_task(self, task=None, **kw): vals = {'task': task, 'user': request.env.user} history = request.session.get('my_tasks_history', []) vals.update(get_records_pager(history, task)) - return request.render("website_project.my_task", vals) + return request.render("project.portal_my_task", vals) diff --git a/addons/project/data/project_demo.xml b/addons/project/data/project_demo.xml index ba068404bdf..f5e53c769df 100644 --- a/addons/project/data/project_demo.xml +++ b/addons/project/data/project_demo.xml @@ -67,6 +67,8 @@ <field name="color">3</field> <field name="user_id" ref="base.user_demo"/> <field name="type_ids" eval="[(4, ref('project_stage_0')), (4, ref('project_stage_1')), (4, ref('project_stage_2')), (4, ref('project_stage_3'))]"/> + <field name="partner_id" ref="base.partner_demo_portal"/> + <field name="privacy_visibility">portal</field> </record> <record id="project_project_2" model="project.project"> @@ -425,5 +427,8 @@ Send it ASAP, its urgent.</field> <field name="author_id" ref="base.partner_root"/> </record> + <function model="project.project" name="message_subscribe" + eval="[ref('project.project_project_1')], [ref('base.partner_demo_portal')]"/> + </data> </odoo> diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 49014a07481..1980009cf06 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -4,7 +4,7 @@ from lxml import etree from odoo import api, fields, models, tools, SUPERUSER_ID, _ -from odoo.exceptions import UserError, ValidationError +from odoo.exceptions import UserError, AccessError from odoo.tools.safe_eval import safe_eval @@ -272,6 +272,30 @@ class Project(models.Model): return res @api.multi + def get_access_action(self, access_uid=None): + """ Instead of the classic form view, redirect to website for portal users + that can read the project. """ + self.ensure_one() + user, record = self.env.user, self + if access_uid: + user = self.env['res.users'].sudo().browse(access_uid) + record = self.sudo(user) + + if user.share: + try: + record.check_access_rule('read') + except AccessError: + pass + else: + return { + 'type': 'ir.actions.act_url', + 'url': '/my/project/%s' % self.id, + 'target': 'self', + 'res_id': self.id, + } + return super(Project, self).get_access_action(access_uid) + + @api.multi def message_subscribe(self, partner_ids=None, channel_ids=None, subtype_ids=None, force=True): """ Subscribe to all existing active tasks when subscribing to a project """ res = super(Project, self).message_subscribe(partner_ids=partner_ids, channel_ids=channel_ids, subtype_ids=subtype_ids, force=force) @@ -291,6 +315,28 @@ class Project(models.Model): return super(Project, self).message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids) @api.multi + def _notification_recipients(self, message, groups): + groups = super(Project, self)._notification_recipients(message, groups) + + for group_name, group_method, group_data in groups: + group_data['has_button_access'] = True + + return groups + + @api.multi + def toggle_favorite(self): + favorite_projects = not_fav_projects = self.env['project.project'].sudo() + for project in self: + if self.env.user in project.favorite_user_ids: + favorite_projects |= project + else: + not_fav_projects |= project + + # Project User has no write access for project. + not_fav_projects.write({'favorite_user_ids': [(4, self.env.uid)]}) + favorite_projects.write({'favorite_user_ids': [(3, self.env.uid)]}) + + @api.multi def close_dialog(self): return {'type': 'ir.actions.act_window_close'} @@ -383,7 +429,8 @@ class Task(models.Model): default=lambda self: self.env['res.company']._company_default_get()) color = fields.Integer(string='Color Index') user_email = fields.Char(related='user_id.email', string='User Email', readonly=True) - attachment_ids = fields.One2many('ir.attachment', 'res_id', domain=lambda self: [('res_model', '=', self._name)], auto_join=True, string='Attachments') + attachment_ids = fields.One2many('ir.attachment', compute='_compute_attachment_ids', string="Main Attachments", + help="Attachment that don't come from message.") # In the domain of displayed_image_id, we couln't use attachment_ids because a one2many is represented as a list of commands so we used res_model & res_id displayed_image_id = fields.Many2one('ir.attachment', domain="[('res_model', '=', 'project.task'), ('res_id', '=', id), ('mimetype', 'ilike', 'image')]", string='Cover Image') legend_blocked = fields.Char(related='stage_id.legend_blocked', string='Kanban Blocked Explanation', readonly=True) @@ -402,6 +449,14 @@ class Task(models.Model): working_days_open = fields.Float(compute='_compute_elapsed', string='Working days to assign', store=True, group_operator="avg") working_days_close = fields.Float(compute='_compute_elapsed', string='Working days to close', store=True, group_operator="avg") + website_url = fields.Char('Website URL', compute='_compute_website_url', help='The full URL to access the document through the website.') + + def _compute_attachment_ids(self): + for task in self: + attachment_ids = self.env['ir.attachment'].search([('res_id', '=', task.id), ('res_model', '=', 'project.task')]).ids + message_attachment_ids = self.mapped('message_ids.attachment_ids').ids # from mail_thread + task.attachment_ids = list(set(attachment_ids) - set(message_attachment_ids)) + @api.multi @api.depends('create_date', 'date_end', 'date_assign') def _compute_elapsed(self): @@ -436,6 +491,10 @@ class Task(models.Model): else: task.kanban_state_label = task.legend_done + def _compute_website_url(self): + for task in self: + task.website_url = '/my/task/%s' % task.id + @api.onchange('partner_id') def _onchange_partner_id(self): self.email_from = self.partner_id.email @@ -601,6 +660,30 @@ class Task(models.Model): return {'date_end': fields.Datetime.now()} return {'date_end': False} + @api.multi + def get_access_action(self, access_uid=None): + """ Instead of the classic form view, redirect to website for portal users + that can read the task. """ + self.ensure_one() + user, record = self.env.user, self + if access_uid: + user = self.env['res.users'].sudo().browse(access_uid) + record = self.sudo(user) + + if user.share: + try: + record.check_access_rule('read') + except AccessError: + pass + else: + return { + 'type': 'ir.actions.act_url', + 'url': '/my/task/%s' % self.id, + 'target': 'self', + 'res_id': self.id, + } + return super(Task, self).get_access_action(access_uid) + # --------------------------------------------------- # Mail gateway # --------------------------------------------------- @@ -647,7 +730,11 @@ class Task(models.Model): 'actions': project_actions, }) - return [new_group] + groups + groups = [new_group] + groups + for group_name, group_method, group_data in groups: + group_data['has_button_access'] = True + + return groups @api.model def message_get_reply_to(self, res_ids, default=None): diff --git a/addons/project/security/ir.model.access.csv b/addons/project/security/ir.model.access.csv index 38cfb7fb212..327c32aeb11 100644 --- a/addons/project/security/ir.model.access.csv +++ b/addons/project/security/ir.model.access.csv @@ -3,18 +3,23 @@ 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 +access_project_task_type_portal,task_type_portal,project.model_project_task_type,base.group_portal,1,0,0,0 access_project_task,project.task,model_project_task,project.group_project_user,1,1,1,1 access_report_project_task_user,report.project.task.user,model_report_project_task_user,project.group_project_manager,1,1,1,1 access_partner_task user,base.res.partner user,base.model_res_partner,project.group_project_user,1,0,0,0 access_task_on_partner,project.task on partners,model_project_task,base.group_user,1,0,0,0 -access_project_on_partner,project.project on partners,model_project_project,base.group_user,1,0,0,0 +access_task_portal,task_portal,project.model_project_task,base.group_portal,1,0,0,0 +access_project_user,project.project on partners,model_project_project,base.group_user,1,0,0,0 +access_project_portal,project_portal,project.model_project_project,base.group_portal,1,0,0,0 access_account_analytic_line_project,account.analytic.line project,analytic.model_account_analytic_line,project.group_project_manager,1,1,1,1 access_resource_calendar,project.resource_calendar user,resource.model_resource_calendar,project.group_project_user,1,0,0,0 access_resource_calendar_attendance,project.resource_calendar_attendance user,resource.model_resource_calendar_attendance,project.group_project_user,1,0,0,0 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 diff --git a/addons/project/security/project_security.xml b/addons/project/security/project_security.xml index 680d459bd82..5651bc4b2d5 100644 --- a/addons/project/security/project_security.xml +++ b/addons/project/security/project_security.xml @@ -96,5 +96,32 @@ <field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field> </record> + <!-- Portal --> + <record id="project_project_rule_portal" model="ir.rule"> + <field name="name">Project: portal users: portal and following</field> + <field name="model_id" ref="project.model_project_project"/> + <field name="domain_force">[ + '&', + ('privacy_visibility', '=', 'portal'), + ('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]), + ]</field> + <field name="groups" eval="[(4, ref('base.group_portal'))]"/> + </record> + + <record id="project_task_rule_portal" model="ir.rule"> + <field name="name">Project/Task: portal users: (portal and following project) or (portal and following task)</field> + <field name="model_id" ref="project.model_project_task"/> + <field name="domain_force">[ + '|', + '&', + ('project_id.privacy_visibility', '=', 'portal'), + ('project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]), + '&', + ('project_id.privacy_visibility', '=', 'portal'), + ('message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]), + ]</field> + <field name="groups" eval="[(4, ref('base.group_portal'))]"/> + </record> + </data> </odoo> diff --git a/addons/project/tests/__init__.py b/addons/project/tests/__init__.py index 8e85c184df2..a5fce7273f7 100644 --- a/addons/project/tests/__init__.py +++ b/addons/project/tests/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -from . import test_project_base, test_project_flow, test_access_rights, test_project_ui +from . import test_project_base, test_project_flow, test_access_rights, test_project_ui, test_portal diff --git a/addons/website_project/tests/test_access_rights.py b/addons/project/tests/test_portal.py index fe446760744..fe446760744 100644 --- a/addons/website_project/tests/test_access_rights.py +++ b/addons/project/tests/test_portal.py diff --git a/addons/website_project/views/project_templates.xml b/addons/project/views/project_portal_templates.xml index dca48749e88..c4f90d3f174 100644 --- a/addons/website_project/views/project_templates.xml +++ b/addons/project/views/project_portal_templates.xml @@ -32,7 +32,7 @@ </xpath> </template> - <template id="my_projects" name="My Projects"> + <template id="portal_my_projects" name="My Projects"> <t t-call="portal.portal_layout"> <h3>Projects <t t-call="portal.portal_searchbar"/> @@ -71,7 +71,7 @@ </t> </template> - <template id="my_project" name="My Project"> + <template id="portal_my_project" name="My Project"> <t t-call="portal.portal_layout"> <div class="panel panel-default"> <div class="panel-heading"> @@ -125,7 +125,7 @@ </t> </template> - <template id="my_tasks" name="My Tasks"> + <template id="portal_my_tasks" name="My Tasks"> <t t-call="portal.portal_layout"> <h3>Tasks <t t-call="portal.portal_searchbar"/> @@ -163,7 +163,7 @@ </t> </template> - <template id="my_task" name="My Task"> + <template id="portal_my_task" name="My Task"> <t t-call="portal.portal_layout"> <div class="panel panel-default"> <div class="panel-heading"> diff --git a/addons/website_project/demo/project_demo.xml b/addons/website_project/demo/project_demo.xml index afdd792eb74..e69de29bb2d 100644 --- a/addons/website_project/demo/project_demo.xml +++ b/addons/website_project/demo/project_demo.xml @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<odoo> - <data noupdate="1"> - <record id="project.project_project_1" model="project.project"> - <field name="partner_id" ref="base.partner_demo_portal"/> - <field name="privacy_visibility">portal</field> - </record> - - <function model="project.project" name="message_subscribe" - eval="[ref('project.project_project_1')], [ref('base.partner_demo_portal')]"/> - </data> -</odoo> diff --git a/addons/website_rating_project/__manifest__.py b/addons/website_rating_project/__manifest__.py index 3ba897df104..b3649c6b731 100644 --- a/addons/website_rating_project/__manifest__.py +++ b/addons/website_rating_project/__manifest__.py @@ -10,8 +10,8 @@ This module display project customer satisfaction on your website. ================================================================== """, 'depends': [ - 'website_project', - 'rating_project' + 'website', + 'rating_project', ], 'data': [ 'views/website_rating_project.xml', |
