summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérome Maes <jem@openerp.com>2017-08-09 10:40:09 +0200
committerJérome Maes <jem@openerp.com>2017-08-16 14:56:41 +0200
commit424c16f11506664f9bf1a9aa5783a864d0cce8b4 (patch)
treebc78740494ffd80ece4ba3a69c576d4fc2c3ff22
parent3cfd64f63f6153c170c9c876fa65976a95da22cb (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__.py1
-rw-r--r--addons/project/__manifest__.py2
-rw-r--r--addons/project/controllers/__init__.py4
-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.xml5
-rw-r--r--addons/project/models/project.py93
-rw-r--r--addons/project/security/ir.model.access.csv7
-rw-r--r--addons/project/security/project_security.xml27
-rw-r--r--addons/project/tests/__init__.py2
-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.xml12
-rw-r--r--addons/website_rating_project/__manifest__.py4
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">[
+ '&amp;',
+ ('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">[
+ '|',
+ '&amp;',
+ ('project_id.privacy_visibility', '=', 'portal'),
+ ('project_id.message_partner_ids', 'child_of', [user.partner_id.commercial_partner_id.id]),
+ '&amp;',
+ ('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',