diff options
| author | Robot Odoo <xmo+roboto@odoo.com> | 2018-12-12 18:35:02 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-12 18:35:02 +0100 |
| commit | ff0c71f373864cf80b79da23e7386ad45b20cd4f (patch) | |
| tree | 79a6c0d4352642dfeb9f6e478968f9d80f16fad2 | |
| parent | 13eb9b9c5b77cb42616f91dc4db48e0a6aab014e (diff) | |
| parent | abc212f59a51d7b1de99201d5bb07c871021e766 (diff) | |
[MERGE][REF] mail: clean access right check on activities
This merge improves code of access rights checks when creating or updating
activities. Several points triggers this commit
* we would like to use _filter_access_rules and override it on activities
model in order to be more standard;
* we would like to get rid of sudo used in various CRUD overrides as using
standard ORM method allows to correctly use current user;
* we would like to get rid of create_user_id field once we can keep the
current user as create_uid;
Access rights are a bit updated. They are now the following
* you can create activities for documents like posting messages (using
_mail_post_access attribute; if not defined, write access on document
is required);
* you can read activities for documents you can read;
* you can write and unlink activities either following the defined access
rule (created OR assigned), and otherwise like posting messages (
using _mail_post_access attribute; if not defined, write access on
document is required);
In this merge we also hide edit / mark as done / cancel buttons for
activities the current user cannot modify.
Finally create_user_id field related to activities is replaced by create_uid
everywhere.
This commit is linked to task ID 1856417.
closes odoo/odoo#27619
| -rw-r--r-- | addons/crm/data/crm_lead_demo.xml | 24 | ||||
| -rw-r--r-- | addons/hr_recruitment/data/hr_recruitment_demo.xml | 14 | ||||
| -rw-r--r-- | addons/mail/data/mail_data.xml | 2 | ||||
| -rw-r--r-- | addons/mail/models/mail_activity.py | 115 | ||||
| -rw-r--r-- | addons/mail/security/mail_security.xml | 4 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/activity.xml | 10 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/web_kanban_activity.xml | 4 | ||||
| -rw-r--r-- | addons/mail/static/tests/activity_tests.js | 5 | ||||
| -rw-r--r-- | addons/mail/static/tests/chatter_tests.js | 31 | ||||
| -rw-r--r-- | addons/mail/views/mail_activity_views.xml | 2 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_mail_activity.py | 33 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_performance.py | 8 |
12 files changed, 146 insertions, 106 deletions
diff --git a/addons/crm/data/crm_lead_demo.xml b/addons/crm/data/crm_lead_demo.xml index 6f3191d39fb..4f638a42f0e 100644 --- a/addons/crm/data/crm_lead_demo.xml +++ b/addons/crm/data/crm_lead_demo.xml @@ -1176,7 +1176,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_call" /> <field name="summary">Meeting to go over pricing information.</field> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=3)).strftime('%Y-%m-%d %H:%M')"/> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_2" model="mail.activity"> @@ -1185,7 +1185,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_email"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=3)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Send Catalog by Email</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_3" model="mail.activity"> @@ -1194,7 +1194,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_call"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=1)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Call to get system requirements</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_4" model="mail.activity"> @@ -1203,7 +1203,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_call"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=2)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Convert to quote</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_5" model="mail.activity"> @@ -1213,7 +1213,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_email"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=-1)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Send our service pricelist</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> </record> <record id="activity_6" model="mail.activity"> <field name="res_id" ref="crm.crm_case_18" /> @@ -1221,7 +1221,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_call"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=1)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Call to get training needs</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_7" model="mail.activity"> @@ -1231,7 +1231,7 @@ Andrew</p>]]></field> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=-2)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Followup on the proposal</field> <field name="user_id" ref="base.user_demo"/> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> </record> <record id="activity_8" model="mail.activity"> <field name="res_id" ref="crm.crm_case_20" /> @@ -1250,7 +1250,7 @@ Andrew</p>]]></field> <field name="res_model_id" ref="crm.model_crm_lead"/> <field name="activity_type_id" ref="mail.mail_activity_data_email"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=-2)).strftime('%Y-%m-%d %H:%M')" /> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_11" model="mail.activity"> @@ -1258,7 +1258,7 @@ Andrew</p>]]></field> <field name="res_model_id" ref="crm.model_crm_lead"/> <field name="activity_type_id" ref="mail.mail_activity_data_email"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=1)).strftime('%Y-%m-%d %H:%M')" /> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_12" model="mail.activity"> @@ -1266,7 +1266,7 @@ Andrew</p>]]></field> <field name="res_model_id" ref="crm.model_crm_lead"/> <field name="activity_type_id" ref="mail.mail_activity_data_email"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=2)).strftime('%Y-%m-%d %H:%M')" /> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_13" model="mail.activity"> @@ -1275,7 +1275,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_call"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=0)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Conf call with technical service</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="activity_14" model="mail.activity"> @@ -1285,7 +1285,7 @@ Andrew</p>]]></field> <field name="activity_type_id" ref="mail.mail_activity_data_email"/> <field name="date_deadline" eval="(DateTime.today() + relativedelta(days=0)).strftime('%Y-%m-%d %H:%M')" /> <field name="summary">Send Catalog by Email</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> </record> </data> diff --git a/addons/hr_recruitment/data/hr_recruitment_demo.xml b/addons/hr_recruitment/data/hr_recruitment_demo.xml index 82c6165549e..bd1bbdc00a8 100644 --- a/addons/hr_recruitment/data/hr_recruitment_demo.xml +++ b/addons/hr_recruitment/data/hr_recruitment_demo.xml @@ -359,7 +359,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_email" /> <field name="date_deadline" eval="time.strftime('%Y-%m-27 18:15:00')"/> <field name="summary">Send mail regarding our interview</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="mail_activity_1" model="mail.activity"> @@ -368,7 +368,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_email" /> <field name="date_deadline" eval="time.strftime('%Y-%m-%d')"/> <field name="summary">Send mail for first interview</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="mail_activity_2" model="mail.activity"> @@ -377,7 +377,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_email" /> <field name="date_deadline" eval="time.strftime('%Y-%m-15 18:15:00')"/> <field name="summary">Send mail regarding our interview</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="mail_activity_3" model="mail.activity"> @@ -386,7 +386,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_call" /> <field name="date_deadline" eval="time.strftime('%Y-%m-10 18:15:00')"/> <field name="summary">Call to define real needs about training</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="mail_activity_4" model="mail.activity"> @@ -395,7 +395,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_call" /> <field name="date_deadline" eval="time.strftime('%Y-%m-24 18:15:00')"/> <field name="summary">Call to define real needs about training</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="mail_activity_5" model="mail.activity"> @@ -404,7 +404,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_call" /> <field name="date_deadline" eval="time.strftime('%Y-%m-26 18:15:00')"/> <field name="summary">Call to schedule a second interview</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> <record id="mail_activity_6" model="mail.activity"> @@ -413,7 +413,7 @@ <field name="activity_type_id" ref="mail.mail_activity_data_call" /> <field name="date_deadline" eval="time.strftime('%Y-%m-18 17:15:00')"/> <field name="summary">Call to propose a contract</field> - <field name="create_user_id" ref="base.user_admin"/> + <field name="create_uid" ref="base.user_admin"/> <field name="user_id" ref="base.user_admin"/> </record> diff --git a/addons/mail/data/mail_data.xml b/addons/mail/data/mail_data.xml index 9553cc5b69e..ec4868a9a75 100644 --- a/addons/mail/data/mail_data.xml +++ b/addons/mail/data/mail_data.xml @@ -327,7 +327,7 @@ <template id="message_activity_assigned"> <div style="margin: 0px; padding: 0px; font-size: 13px;"> - <span t-field="activity.create_user_id.name"/> assigned you an activity <span t-field="activity.activity_type_id.name"/> + <span t-field="activity.create_uid.name"/> assigned you an activity <span t-field="activity.activity_type_id.name"/> <t t-if="activity.summary">(<span t-field="activity.summary"/>)</t> on <span t-field="activity.res_name"/> to close for <span t-field="activity.date_deadline"/>.<br /> diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index b925f59b1be..c93d68c66b6 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -113,9 +113,9 @@ class MailActivity(models.Model): index=True, ondelete='cascade', required=True) res_model = fields.Char( 'Related Document Model', - index=True, related='res_model_id.model', store=True, readonly=True) + index=True, related='res_model_id.model', compute_sudo=True, store=True, readonly=True) res_name = fields.Char( - 'Document Name', compute='_compute_res_name', store=True, + 'Document Name', compute='_compute_res_name', compute_sudo=True, store=True, help="Display name of the related document.", readonly=True) # activity activity_type_id = fields.Many2one( @@ -136,10 +136,6 @@ class MailActivity(models.Model): 'res.users', 'Assigned to', default=lambda self: self.env.user, index=True, required=True) - create_user_id = fields.Many2one( - 'res.users', 'Creator', - default=lambda self: self.env.user, - index=True) state = fields.Selection([ ('overdue', 'Overdue'), ('today', 'Today'), @@ -153,6 +149,8 @@ class MailActivity(models.Model): help='Technical field for UX purpose') mail_template_ids = fields.Many2many(related='activity_type_id.mail_template_ids', readonly=False) force_next = fields.Boolean(related='activity_type_id.force_next', readonly=False) + # access + can_write = fields.Boolean(compute='_compute_can_write', help='Technical field to hide buttons if the current user has no access.') @api.multi @api.onchange('previous_activity_type_id') @@ -196,6 +194,12 @@ class MailActivity(models.Model): else: return 'planned' + @api.depends('res_model', 'res_id', 'user_id') + def _compute_can_write(self): + valid_records = self._filter_access_rules('write') + for record in self: + record.can_write = record in valid_records + @api.onchange('activity_type_id') def _onchange_activity_type_id(self): if self.activity_type_id: @@ -213,34 +217,60 @@ class MailActivity(models.Model): self.activity_type_id = self.recommended_activity_type_id @api.multi - def _check_access(self, operation): - """ Rule to access activities - - * create: check write rights on related document; - * write: rule OR write rights on document; - * unlink: rule OR write rights on document; + def _filter_access_rules(self, operation): + """ Return the subset of ``self`` for which ``operation`` is allowed. + A custom implementation is done on activities as this document has some + access rules and is based on related document for activities that are + not covered by those rules. + + Access on activities are the following : + + * create: (``mail_post_access`` or write) right on related documents; + * read: read rights on related documents; + * write: access rule OR + (``mail_post_access`` or write) rights on related documents); + * unlink: access rule OR + (``mail_post_access`` or write) rights on related documents); """ - self.check_access_rights(operation, raise_exception=True) # will raise an AccessError + if self.env.user._is_superuser(): + return self + if not self.check_access_rights(operation, raise_exception=False): + return self.env[self._name] + # write / unlink: valid for creator / assigned if operation in ('write', 'unlink'): - try: - self.check_access_rule(operation) - except exceptions.AccessError: - pass - else: - return - doc_operation = 'read' if operation == 'read' else 'write' + valid = super(MailActivity, self)._filter_access_rules(operation) + if valid and valid == self: + return self + else: # create / read: linked to document only, no access rules defined + valid = self.env[self._name] + + # compute remaining for hand-tailored rules + remaining = self - valid + remaining_sudo = remaining.sudo() + + # fall back on related document access right checks. Use the same as defined for mail.thread + # if available; otherwise fall back on read for read, write for other operations. activity_to_documents = dict() - for activity in self.sudo(): + for activity in remaining_sudo: + # write / unlink: if not updating self or assigned, limit to automated activities to avoid + # updating other people's activities. As unlinking a document bypasses access rights checks + # on related activities this will not prevent people from deleting documents with activities + # create / read: just check rights on related document activity_to_documents.setdefault(activity.res_model, list()).append(activity.res_id) - for model, res_ids in activity_to_documents.items(): - self.env[model].check_access_rights(doc_operation, raise_exception=True) - try: - self.env[model].browse(res_ids).check_access_rule(doc_operation) - except exceptions.AccessError: - raise exceptions.AccessError( - _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % - (self._description, operation)) + for doc_model, doc_ids in activity_to_documents.items(): + if hasattr(self.env[doc_model], '_mail_post_access'): + doc_operation = self.env[doc_model]._mail_post_access + elif operation == 'read': + doc_operation = 'read' + else: + doc_operation = 'write' + right = self.env[doc_model].check_access_rights(doc_operation, raise_exception=False) + if right: + valid_doc_ids = self.env[doc_model].browse(doc_ids)._filter_access_rules(doc_operation) + valid += remaining.filtered(lambda activity: activity.res_model == doc_model and activity.res_id in valid_doc_ids.ids) + + return valid @api.multi def _check_access_assignation(self): @@ -266,37 +296,29 @@ class MailActivity(models.Model): @api.model def create(self, values): - # already compute default values to be sure those are computed using the current user - values_w_defaults = self.default_get(self._fields.keys()) - values_w_defaults.update(values) - - # continue as sudo because activities are somewhat protected - activity = super(MailActivity, self.sudo()).create(values_w_defaults) - activity_user = activity.sudo(self.env.user) - activity_user._check_access('create') + activity = super(MailActivity, self).create(values) # send a notification to assigned user; in case of manually done activity also check # target has rights on document otherwise we prevent its creation. Automated activities # are checked since they are integrated into business flows that should not crash. - if activity_user.user_id != self.env.user: - if not activity_user.automated: - activity_user._check_access_assignation() + if activity.user_id != self.env.user: + if not activity.automated: + activity._check_access_assignation() if not self.env.context.get('mail_activity_quick_update', False): - activity_user.action_notify() + activity.action_notify() - self.env[activity_user.res_model].browse(activity_user.res_id).message_subscribe(partner_ids=[activity_user.user_id.partner_id.id]) + self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[activity.user_id.partner_id.id]) if activity.date_deadline <= fields.Date.today(): self.env['bus.bus'].sendone( (self._cr.dbname, 'res.partner', activity.user_id.partner_id.id), {'type': 'activity_updated', 'activity_created': True}) - return activity_user + return activity @api.multi def write(self, values): - self._check_access('write') if values.get('user_id'): pre_responsibles = self.mapped('user_id.partner_id') - res = super(MailActivity, self.sudo()).write(values) + res = super(MailActivity, self).write(values) if values.get('user_id'): if values['user_id'] != self.env.uid: @@ -320,13 +342,12 @@ class MailActivity(models.Model): @api.multi def unlink(self): - self._check_access('unlink') for activity in self: if activity.date_deadline <= fields.Date.today(): self.env['bus.bus'].sendone( (self._cr.dbname, 'res.partner', activity.user_id.partner_id.id), {'type': 'activity_updated', 'activity_deleted': True}) - return super(MailActivity, self.sudo()).unlink() + return super(MailActivity, self).unlink() @api.multi def action_notify(self): diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index 7a97925b42b..f4493dad93a 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -41,9 +41,9 @@ </record> <record id="mail_activity_rule_user" model="ir.rule"> - <field name="name">mail.activity: user: own only</field> + <field name="name">mail.activity: user: write/unlink only (created or assigned)</field> <field name="model_id" ref="model_mail_activity"/> - <field name="domain_force">[('user_id', '=', user.id)]</field> + <field name="domain_force">['|', ('user_id', '=', user.id), ('create_uid', '=', user.id)]</field> <field name="groups" eval="[(4, ref('base.group_user'))]"/> <field name="perm_create" eval="False"/> <field name="perm_read" eval="False"/> diff --git a/addons/mail/static/src/xml/activity.xml b/addons/mail/static/src/xml/activity.xml index cb7f8a5ae28..a327806883c 100644 --- a/addons/mail/static/src/xml/activity.xml +++ b/addons/mail/static/src/xml/activity.xml @@ -42,12 +42,12 @@ <dd class="mb8"> <t t-esc="activity.create_date.format(datetimeFormat)"/> by - <img t-attf-src="/web/image#{activity.create_user_id[0] >= 0 ? ('/res.users/' + activity.create_user_id[0] + '/image_small') : ''}" + <img t-attf-src="/web/image#{activity.create_uid[0] >= 0 ? ('/res.users/' + activity.create_uid[0] + '/image_small') : ''}" height="18" width="18" class="rounded-circle mr4" - t-att-title="activity.create_user_id[1]" - t-att-alt="activity.create_user_id[1]"/> - <b><t t-esc="activity.create_user_id[1]"/></b> + t-att-title="activity.create_uid[1]" + t-att-alt="activity.create_uid[1]"/> + <b><t t-esc="activity.create_uid[1]"/></b> </dd> <dt>Assigned to</dt> <dd class="mb8"> @@ -74,7 +74,7 @@ </t> </div> </t> - <div class="o_thread_message_tools btn-group"> + <div t-if="activity.can_write" class="o_thread_message_tools btn-group"> <span class="o_mark_as_done" data-toggle="popover" t-att-data-activity-id="activity.id" t-att-data-force-next-activity="activity.force_next" t-att-data-previous-activity-type-id="activity.activity_type_id[0]"> <a role="button" href="#" class="btn btn-link btn-success text-muted o_activity_link mr8"> <i class="fa fa-check"/> Mark Done </a> diff --git a/addons/mail/static/src/xml/web_kanban_activity.xml b/addons/mail/static/src/xml/web_kanban_activity.xml index 8f63b51cdfe..9ebed7ebce4 100644 --- a/addons/mail/static/src/xml/web_kanban_activity.xml +++ b/addons/mail/static/src/xml/web_kanban_activity.xml @@ -40,7 +40,7 @@ <div t-attf-class="o_activity_title_entry {{! log.force_next ? 'align-items-center' : 'mb-1'}}"> <span t-attf-class="fa #{log.icon ? log.icon : 'fa-bell' } fa-fw mr-2 text-center text-muted" role="img" aria-label="Log" title="Log"/> <strong class="text-dark"><t t-esc="log.title_action or log.activity_type_id[1]"/></strong> - <button t-if="! log.force_next" class="btn btn-sm btn-link py-0 o_edit_button"><i class="fa fa-pencil"/></button> + <button t-if="! log.force_next and log.can_write" class="btn btn-sm btn-link py-0 o_edit_button"><i class="fa fa-pencil"/></button> </div> <div class="o_activity_title_entry mt-1" t-if="log.state != 'today'"> <span class="fa fa-clock-o fa-fw mr-2 text-center text-muted" role="img" aria-label="Deadline" title="Deadline"/> @@ -62,7 +62,7 @@ <span><t t-esc="log.user_id[1]" /></span> </div> </div> - <div class="flex-grow-1 text-right"> + <div t-if="log.can_write" class="flex-grow-1 text-right"> <a t-att-data-force-next-activity="log.force_next" t-att-data-previous-activity-type-id="log.activity_type_id[0]" t-att-data-activity-id="log.id" diff --git a/addons/mail/static/tests/activity_tests.js b/addons/mail/static/tests/activity_tests.js index 85188a59f15..78e2bf9bba1 100644 --- a/addons/mail/static/tests/activity_tests.js +++ b/addons/mail/static/tests/activity_tests.js @@ -99,6 +99,7 @@ QUnit.module('activity view', { activity_type_id: { string: "Activity type", type: "many2one", relation: "mail.activity.type" }, display_name: { string: "Display name", type: "char" }, date_deadline: { string: "Due Date", type: "date" }, + can_write: { string: "Can write", type: "boolean" }, state: { string: 'State', type: 'selection', @@ -112,6 +113,8 @@ QUnit.module('activity view', { id: 1, display_name: "An activity", date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), // now + can_write: true, + state: "planned", activity_type_id: 1, mail_template_ids: [8, 9], @@ -120,6 +123,7 @@ QUnit.module('activity view', { id: 2, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", activity_type_id: 1, mail_template_ids: [8, 9], @@ -128,6 +132,7 @@ QUnit.module('activity view', { id: 3, display_name: "An activity", date_deadline: moment().subtract(2, "days").format("YYYY-MM-DD"), // now + can_write: true, state: "overdue", activity_type_id: 2, mail_template_ids: [], diff --git a/addons/mail/static/tests/chatter_tests.js b/addons/mail/static/tests/chatter_tests.js index ac9f715be5d..b6eec0cd5e4 100644 --- a/addons/mail/static/tests/chatter_tests.js +++ b/addons/mail/static/tests/chatter_tests.js @@ -72,8 +72,8 @@ QUnit.module('Chatter', { 'mail.activity': { fields: { activity_type_id: { string: "Activity type", type: "many2one", relation: "mail.activity.type" }, - create_uid: { string: "Assigned to", type: "many2one", relation: 'partner' }, - create_user_id: { string: "Creator", type: "many2one", relation: 'partner' }, + create_uid: { string: "Created By", type: "many2one", relation: 'partner' }, + can_write: { string: "Can write", type: "boolean" }, display_name: { string: "Display name", type: "char" }, date_deadline: { string: "Due Date", type: "date" }, user_id: { string: "Assigned to", type: "many2one", relation: 'partner' }, @@ -228,7 +228,7 @@ QUnit.test('Activity Done keep feedback on blur', function (assert) { var done = assert.async(); this.data['mail.activity'].records = [ - {activity_type_id: 1, id: 1, user_id: 2, state: 'today', note: 'But I\'m talkin\' about Shaft'}, + {activity_type_id: 1, id: 1, can_write: true, user_id: 2, state: 'today', note: 'But I\'m talkin\' about Shaft'}, ]; this.data.partner.records[0].activity_ids = [1]; @@ -512,9 +512,10 @@ QUnit.test('kanban activity widget with an activity', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 1, }]; var rpcCount = 0; @@ -586,9 +587,10 @@ QUnit.test('kanban activity widget popover test', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 1, }]; var rpcCount = 0; @@ -1477,9 +1479,10 @@ QUnit.test('form activity widget: read RPCs', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 2, }]; @@ -1562,9 +1565,10 @@ QUnit.test('form activity widget with another x2many field in view', function (a id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 2, }]; @@ -1596,9 +1600,10 @@ QUnit.test('form activity widget: schedule next activity', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 2, }]; @@ -1652,9 +1657,10 @@ QUnit.test('form activity widget: edit next activity', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 2, }]; @@ -1715,6 +1721,7 @@ QUnit.test('form activity widget: clic mail template', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, activity_type_id: 2, @@ -1833,17 +1840,19 @@ QUnit.test('form activity widget: mark as done and remove', function (assert) { id: 1, display_name: "An activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 1, }, { id: 2, display_name: "A second activity", date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, state: "today", user_id: 2, - create_user_id: 2, + create_uid: 2, activity_type_id: 1, }]; diff --git a/addons/mail/views/mail_activity_views.xml b/addons/mail/views/mail_activity_views.xml index b540844fc39..1c833db1bd3 100644 --- a/addons/mail/views/mail_activity_views.xml +++ b/addons/mail/views/mail_activity_views.xml @@ -168,7 +168,7 @@ <separator/> <group expand="0" string="Group By"> <filter string="Deadline" name="date_deadline" context="{'group_by': 'date_deadline'}"/> - <filter string="Created By" name="createdby" context="{'group_by': 'create_user_id'}"/> + <filter string="Created By" name="createdby" context="{'group_by': 'create_uid'}"/> <filter string="Activity Type" name="activittype" context="{'group_by': 'activity_type_id'}"/> </group> </search> diff --git a/addons/test_mail/tests/test_mail_activity.py b/addons/test_mail/tests/test_mail_activity.py index 4b3b2e98922..10cade0e0a5 100644 --- a/addons/test_mail/tests/test_mail_activity.py +++ b/addons/test_mail/tests/test_mail_activity.py @@ -31,13 +31,18 @@ class TestActivityCommon(BaseFunctionalTest): @tests.tagged('mail_activity') class TestActivityRights(TestActivityCommon): - def test_activity_security_user_access(self): - activity = self.test_record.activity_schedule( + def test_activity_security_user_access_other(self): + activity = self.test_record.sudo(self.user_employee).activity_schedule( 'test_mail.mail_act_test_todo', - user_id=self.user_employee.id) + user_id=self.user_admin.id) + self.assertTrue(activity.can_write) + activity.write({'user_id': self.user_employee.id}) - activity2 = self.test_record.activity_schedule('test_mail.mail_act_test_todo') - activity2.write({'user_id': self.user_employee.id}) + def test_activity_security_user_access_own(self): + activity = self.test_record.sudo(self.user_employee).activity_schedule( + 'test_mail.mail_act_test_todo') + self.assertTrue(activity.can_write) + activity.write({'user_id': self.user_admin.id}) def test_activity_security_user_noaccess_automated(self): def _employee_crash(*args, **kwargs): @@ -63,6 +68,7 @@ class TestActivityRights(TestActivityCommon): raise exceptions.AccessError('Hop hop hop Ernest, please step back.') return DEFAULT + # cannot create activities for people that cannot access record with patch.object(MailTestActivity, 'check_access_rights', autospec=True, side_effect=_employee_crash): with self.assertRaises(exceptions.UserError): activity = self.env['mail.activity'].create({ @@ -72,13 +78,12 @@ class TestActivityRights(TestActivityCommon): 'user_id': self.user_employee.id, }) - activity2 = self.env['mail.activity'].create({ - 'activity_type_id': self.env.ref('test_mail.mail_act_test_todo').id, - 'res_model_id': self.env.ref('test_mail.model_mail_test_activity').id, - 'res_id': self.test_record.id, - }) - with self.assertRaises(exceptions.UserError): - activity2.write({'user_id': self.user_employee.id}) + # cannot create activities if no access to the document + with patch.object(MailTestActivity, 'check_access_rights', autospec=True, side_effect=_employee_crash): + with self.assertRaises(exceptions.AccessError): + activity = self.test_record.sudo(self.user_employee).activity_schedule( + 'test_mail.mail_act_test_todo', + user_id=self.user_admin.id) @tests.tagged('mail_activity') @@ -133,7 +138,7 @@ class TestActivityFlow(TestActivityCommon): activity = rec.activity_schedule( 'test_mail.mail_act_test_todo', user_id=self.user_admin.id) - self.assertEqual(activity.create_user_id, self.user_employee) + self.assertEqual(activity.create_uid, self.user_employee) self.assertEqual(activity.user_id, self.user_admin) def test_activity_notify_same_user(self): @@ -143,7 +148,7 @@ class TestActivityFlow(TestActivityCommon): activity = rec.activity_schedule( 'test_mail.mail_act_test_todo', user_id=self.user_employee.id) - self.assertEqual(activity.create_user_id, self.user_employee) + self.assertEqual(activity.create_uid, self.user_employee) self.assertEqual(activity.user_id, self.user_employee) diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index 49befe45800..bb8b3437e84 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -172,7 +172,7 @@ class TestAdvMailPerformance(TransactionCase): 'default_res_model': 'mail.test.activity', }) - with self.assertQueryCount(__system__=10, emp=15): # com runbot: 9 - 15 // test_mail only: 10 - 14 + with self.assertQueryCount(__system__=10, emp=16): # com runbot: 9 - 15 // test_mail only: 10 - 14 activity = MailActivity.create({ 'summary': 'Test Activity', 'res_id': record.id, @@ -182,7 +182,7 @@ class TestAdvMailPerformance(TransactionCase): #voip module read activity_type during create leading to one less query in enterprise on action_feedback category = activity.activity_type_id.category - with self.assertQueryCount(__system__=26, emp=46): # com runbot: 25 - 46 // test_mail only: 26 - 46 + with self.assertQueryCount(__system__=26, emp=50): # com runbot: 25 - 46 // test_mail only: 26 - 46 activity.action_feedback(feedback='Zizisse Done !') @users('__system__', 'emp') @@ -191,7 +191,7 @@ class TestAdvMailPerformance(TransactionCase): def test_adv_activity_mixin(self): record = self.env['mail.test.activity'].create({'name': 'Test'}) - with self.assertQueryCount(__system__=10, emp=15): # com runbot: 9 - 15 // test_mail only: 10 - 14 + with self.assertQueryCount(__system__=10, emp=16): # com runbot: 9 - 15 // test_mail only: 10 - 14 activity = record.action_start('Test Start') #read activity_type to normalize cache between enterprise and community #voip module read activity_type during create leading to one less query in enterprise on action_close @@ -199,7 +199,7 @@ class TestAdvMailPerformance(TransactionCase): record.write({'name': 'Dupe write'}) - with self.assertQueryCount(__system__=28, emp=48): # com runbot: 27 - 86 // test_mail only: 28 - 48 + with self.assertQueryCount(__system__=28, emp=52): # com runbot: 27 - 86 // test_mail only: 28 - 48 record.action_close('Dupe feedback') self.assertEqual(record.activity_ids, self.env['mail.activity']) |
