summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/crm/models/crm_lead.py3
-rw-r--r--addons/hr_expense/models/hr_expense.py4
-rw-r--r--addons/hr_timesheet_attendance/models/hr_timesheet_sheet.py2
-rw-r--r--addons/mail/controllers/bus.py10
-rw-r--r--addons/mail/models/mail_activity.py55
-rw-r--r--addons/mail/models/mail_message.py35
-rw-r--r--addons/mail/models/res_partner.py2
-rw-r--r--addons/mail/security/ir.model.access.csv12
-rw-r--r--addons/mail/security/mail_security.xml11
-rw-r--r--addons/website_slides/controllers/main.py8
10 files changed, 107 insertions, 35 deletions
diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py
index 213cea0c6fa..9827da60063 100644
--- a/addons/crm/models/crm_lead.py
+++ b/addons/crm/models/crm_lead.py
@@ -327,6 +327,9 @@ class Lead(models.Model):
# Set date_open to today if it is an opp
default = default or {}
default['date_open'] = fields.Datetime.now() if self.type == 'opportunity' else False
+ # Do not assign to an archived user
+ if not self.user_id.active:
+ default['user_id'] = False
return super(Lead, self.with_context(context)).copy(default=default)
@api.model
diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py
index d3b56254d5a..7456aa7f533 100644
--- a/addons/hr_expense/models/hr_expense.py
+++ b/addons/hr_expense/models/hr_expense.py
@@ -530,6 +530,8 @@ class HrExpenseSheet(models.Model):
@api.multi
def refuse_expenses(self, reason):
+ if not self.user_has_groups('hr_expense.group_hr_expense_user'):
+ raise UserError(_("Only HR Officers can refuse expenses"))
self.write({'state': 'cancel'})
for sheet in self:
body = (_("Your Expense %s has been refused.<br/><ul class=o_timeline_tracking_value_list><li>Reason<span> : </span><span class=o_timeline_tracking_value>%s</span></li></ul>") % (sheet.name, reason))
@@ -537,6 +539,8 @@ class HrExpenseSheet(models.Model):
@api.multi
def approve_expense_sheets(self):
+ if not self.user_has_groups('hr_expense.group_hr_expense_user'):
+ raise UserError(_("Only HR Officers can approve expenses"))
self.write({'state': 'approve', 'responsible_id': self.env.user.id})
@api.multi
diff --git a/addons/hr_timesheet_attendance/models/hr_timesheet_sheet.py b/addons/hr_timesheet_attendance/models/hr_timesheet_sheet.py
index 49adf3fed7f..d0c980f9f5f 100644
--- a/addons/hr_timesheet_attendance/models/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_attendance/models/hr_timesheet_sheet.py
@@ -165,7 +165,7 @@ class hr_timesheet_sheet_sheet_day(models.Model):
ON r.user_id = u.id
LEFT JOIN res_partner p
ON u.partner_id = p.id
- WHERE check_out IS NOT NULL
+ WHERE a.check_out IS NOT NULL
group by (a.check_in AT TIME ZONE 'UTC' AT TIME ZONE coalesce(p.tz, 'UTC'))::date, s.id, timezone
)) AS foo
GROUP BY name, sheet_id, timezone
diff --git a/addons/mail/controllers/bus.py b/addons/mail/controllers/bus.py
index 517ded468cd..62a5225cfe5 100644
--- a/addons/mail/controllers/bus.py
+++ b/addons/mail/controllers/bus.py
@@ -36,18 +36,16 @@ class MailChatController(BusController):
# --------------------------
@route('/mail/chat_post', type="json", auth="none")
def mail_chat_post(self, uuid, message_content, **kwargs):
- request_uid = self._default_request_uid()
# find the author from the user session, which can be None
author_id = False # message_post accept 'False' author_id, but not 'None'
if request.session.uid:
author_id = request.env['res.users'].sudo().browse(request.session.uid).partner_id.id
# post a message without adding followers to the channel. email_from=False avoid to get author from email data
- mail_channel = request.env["mail.channel"].sudo(request_uid).search([('uuid', '=', uuid)], limit=1)
- message = mail_channel.sudo(request_uid).with_context(mail_create_nosubscribe=True).message_post(author_id=author_id, email_from=False, body=message_content, message_type='comment', subtype='mail.mt_comment', content_subtype='plaintext', **kwargs)
+ mail_channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
+ message = mail_channel.sudo().with_context(mail_create_nosubscribe=True).message_post(author_id=author_id, email_from=False, body=message_content, message_type='comment', subtype='mail.mt_comment', content_subtype='plaintext')
return message and message.id or False
@route(['/mail/chat_history'], type="json", auth="none")
def mail_chat_history(self, uuid, last_id=False, limit=20):
- request_uid = self._default_request_uid()
- channel = request.env["mail.channel"].sudo(request_uid).search([('uuid', '=', uuid)], limit=1)
- return channel.sudo(request_uid).channel_fetch_message(last_id, limit)
+ channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1)
+ return channel.sudo().channel_fetch_message(last_id, limit)
diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py
index 39fe471bcc4..d615e1070fa 100644
--- a/addons/mail/models/mail_activity.py
+++ b/addons/mail/models/mail_activity.py
@@ -3,7 +3,7 @@
from datetime import date, datetime, timedelta
-from odoo import api, fields, models
+from odoo import api, exceptions, fields, models, _
class MailActivityType(models.Model):
@@ -102,21 +102,66 @@ class MailActivity(models.Model):
self.summary = self.activity_type_id.summary
self.date_deadline = (datetime.now() + timedelta(days=self.activity_type_id.days))
+ @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;
+ """
+ self.check_access_rights(operation, raise_exception=True) # will raise an AccessError
+
+ 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'
+ activity_to_documents = dict()
+ for activity in self.sudo():
+ 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))
+
@api.model
def create(self, values):
- activity = super(MailActivity, self).create(values)
- self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[activity.user_id.partner_id.id])
- return activity
+ # 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')
+ self.env[activity_user.res_model].browse(activity_user.res_id).message_subscribe(partner_ids=[activity_user.user_id.partner_id.id])
+ return activity_user
@api.multi
def write(self, values):
- res = super(MailActivity, self).write(values)
+ self._check_access('write')
+ res = super(MailActivity, self.sudo()).write(values)
+
if values.get('user_id'):
for activity in self:
self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[activity.user_id.partner_id.id])
return res
@api.multi
+ def unlink(self):
+ self._check_access('unlink')
+ return super(MailActivity, self.sudo()).unlink()
+
+ @api.multi
def action_done(self):
message = self.env['mail.message']
for activity in self:
diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index ac2183d767a..611da587de9 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -96,6 +96,7 @@ class Message(models.Model):
tracking_value_ids = fields.One2many(
'mail.tracking.value', 'mail_message_id',
string='Tracking values',
+ groups="base.group_no_one",
help='Tracked values are stored in a separate model. This field allow to reconstruct '
'the tracking and to generate statistics on the model.')
# mail gateway
@@ -279,7 +280,7 @@ class Message(models.Model):
# 1. Aggregate partners (author_id and partner_ids), attachments and tracking values
partners = self.env['res.partner'].sudo()
attachments = self.env['ir.attachment']
- trackings = self.env['mail.tracking.value']
+ message_ids = message_tree.keys()
for key, message in message_tree.iteritems():
if message.author_id:
partners |= message.author_id
@@ -291,8 +292,6 @@ class Message(models.Model):
partners |= message.needaction_partner_ids
if message.attachment_ids:
attachments |= message.attachment_ids
- if message.tracking_value_ids:
- trackings |= message.tracking_value_ids
# Read partners as SUPERUSER -> message being browsed as SUPERUSER it is already the case
partners_names = partners.name_get()
partner_tree = dict((partner[0], partner) for partner in partners_names)
@@ -307,13 +306,18 @@ class Message(models.Model):
}) for attachment in attachments_data)
# 3. Tracking values
- tracking_tree = dict((tracking.id, {
- 'id': tracking.id,
- 'changed_field': tracking.field_desc,
- 'old_value': tracking.get_old_display_value()[0],
- 'new_value': tracking.get_new_display_value()[0],
- 'field_type': tracking.field_type,
- }) for tracking in trackings)
+ tracking_values = self.env['mail.tracking.value'].sudo().search([('mail_message_id', 'in', message_ids)])
+ message_to_tracking = dict()
+ tracking_tree = dict.fromkeys(tracking_values.ids, False)
+ for tracking in tracking_values:
+ message_to_tracking.setdefault(tracking.mail_message_id.id, list()).append(tracking.id)
+ tracking_tree[tracking.id] = {
+ 'id': tracking.id,
+ 'changed_field': tracking.field_desc,
+ 'old_value': tracking.get_old_display_value()[0],
+ 'new_value': tracking.get_new_display_value()[0],
+ 'field_type': tracking.field_type,
+ }
# 4. Update message dictionaries
for message_dict in messages:
@@ -340,9 +344,9 @@ class Message(models.Model):
if attachment.id in attachments_tree:
attachment_ids.append(attachments_tree[attachment.id])
tracking_value_ids = []
- for tracking_value in message.tracking_value_ids:
- if tracking_value.id in tracking_tree:
- tracking_value_ids.append(tracking_tree[tracking_value.id])
+ for tracking_value_id in message_to_tracking.get(message_id, list()):
+ if tracking_value_id in tracking_tree:
+ tracking_value_ids.append(tracking_tree[tracking_value_id])
message_dict.update({
'author_id': author,
@@ -721,7 +725,12 @@ class Message(models.Model):
if 'record_name' not in values and 'default_record_name' not in self.env.context:
values['record_name'] = self._get_record_name(values)
+ # delegate creation of tracking after the create as sudo to avoid access rights issues
+ tracking_values_cmd = values.pop('tracking_value_ids', False)
message = super(Message, self).create(values)
+ if tracking_values_cmd:
+ message.sudo().write({'tracking_value_ids': tracking_values_cmd})
+
message._invalidate_documents()
if not self.env.context.get('message_create_from_mail_mail'):
diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py
index 85b9dbb74e8..6d8538288a4 100644
--- a/addons/mail/models/res_partner.py
+++ b/addons/mail/models/res_partner.py
@@ -61,7 +61,7 @@ class Partner(models.Model):
record_name = message.record_name
tracking = []
- for tracking_value in message.tracking_value_ids:
+ for tracking_value in self.env['mail.tracking.value'].sudo().search([('mail_message_id', '=', message.id)]):
tracking.append((tracking_value.field_desc,
tracking_value.get_old_display_value()[0],
tracking_value.get_new_display_value()[0]))
diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv
index 0bd1697ca87..5040f812d73 100644
--- a/addons/mail/security/ir.model.access.csv
+++ b/addons/mail/security/ir.model.access.csv
@@ -23,9 +23,9 @@ access_mail_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,1,1,1
access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1
access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,0
access_mail_message_subtype_user,mail.message.subtype.user,model_mail_message_subtype,,1,1,1,1
-access_mail_tracking_value_all,mail.tracking.value.all,model_mail_tracking_value,,1,0,0,0
-access_mail_tracking_value_portal,mail.tracking.value.portal,model_mail_tracking_value,base.group_portal,1,1,1,1
-access_mail_tracking_value_user,mail.tracking.value.user,model_mail_tracking_value,base.group_user,1,1,1,1
+access_mail_tracking_value_all,mail.tracking.value.all,model_mail_tracking_value,,0,0,0,0
+access_mail_tracking_value_portal,mail.tracking.value.portal,model_mail_tracking_value,base.group_portal,0,0,0,0
+access_mail_tracking_value_user,mail.tracking.value.user,model_mail_tracking_value,base.group_user,0,0,0,0
access_mail_tracking_value_system,mail.tracking.value.system,model_mail_tracking_value,base.group_system,1,1,1,1
access_mail_thread_all,mail.thread.all,model_mail_thread,,1,1,1,1
access_publisher_warranty_contract_all,publisher.warranty.contract.all,model_publisher_warranty_contract,,1,1,1,1
@@ -35,7 +35,7 @@ access_mail_shortcode,mail.shortcode,model_mail_shortcode,base.group_user,1,1,1,
access_mail_shortcode_portal,mail.shortcode.portal,model_mail_shortcode,base.group_portal,1,0,0,0
access_mail_test_user,mail.test.all,model_mail_test,base.group_user,1,1,1,1
access_mail_test_portal,mail.test.all,model_mail_test,base.group_portal,1,1,0,0
-access_mail_activity_all,mail.activity.all,model_mail_activity,,1,0,0,0
+access_mail_activity_all,mail.activity.all,model_mail_activity,,0,0,0,0
access_mail_activity_user,mail.activity.user,model_mail_activity,base.group_user,1,1,1,1
-access_mail_activity_type_all,mail.activity.type.all,model_mail_activity_type,,1,0,0,0
-access_mail_activity_type_user,mail.activity.type.user,model_mail_activity_type,base.group_user,1,1,1,1 \ No newline at end of file
+access_mail_activity_type_all,mail.activity.type.all,model_mail_activity_type,,0,0,0,0
+access_mail_activity_type_user,mail.activity.type.user,model_mail_activity_type,base.group_user,1,1,1,1
diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml
index d5a5b5422c9..b9b13d9de3b 100644
--- a/addons/mail/security/mail_security.xml
+++ b/addons/mail/security/mail_security.xml
@@ -40,5 +40,16 @@
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/>
</record>
+ <record id="mail_activity_rule_user" model="ir.rule">
+ <field name="name">mail.activity: user: own only</field>
+ <field name="model_id" ref="model_mail_activity"/>
+ <field name="domain_force">[('user_id', '=', user.id)]</field>
+ <field name="groups" eval="[(4, ref('base.group_user'))]"/>
+ <field name="perm_create" eval="False"/>
+ <field name="perm_read" eval="False"/>
+ <field name="perm_write" eval="True"/>
+ <field name="perm_unlink" eval="True"/>
+ </record>
+
</data>
</odoo>
diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py
index 4226f54dc34..7b67bfcbb40 100644
--- a/addons/website_slides/controllers/main.py
+++ b/addons/website_slides/controllers/main.py
@@ -293,9 +293,11 @@ class WebsiteSlides(http.Controller):
@http.route(['/slides/add_slide'], type='json', auth='user', methods=['POST'], website=True)
def create_slide(self, *args, **post):
- file_size = len(post['datas']) * 3 / 4; # base64
- if (file_size / 1024.0 / 1024.0) > 25:
- return {'error': _('File is too big. File size cannot exceed 25MB')}
+ # check the size only when we upload a file.
+ if post.get('datas'):
+ file_size = len(post['datas']) * 3 / 4 # base64
+ if (file_size / 1024.0 / 1024.0) > 25:
+ return {'error': _('File is too big. File size cannot exceed 25MB')}
values = dict((fname, post[fname]) for fname in [
'name', 'url', 'tag_ids', 'slide_type', 'channel_id',