From 2d6fd5ea65261bf99254de7ed312a56c95c0b6a0 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 16 Nov 2015 11:55:34 +0100 Subject: [PATCH] [IMP] ir_translation: make access rights depend on translated record A translation of a field value for a given record can only be created/updated/ deleted if the current user has access rights for updating the record. Access rights on translations are restricted to the group "Employee". Those still need create/write/delete access, in order to be able to edit records in the user interface. Other users (portal, etc.) simply have no explicit access rights at all on translations. --- openerp/addons/base/ir/ir_translation.py | 54 +++++++++++++++---- .../addons/base/security/ir.model.access.csv | 2 +- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index 93fa727365e..d9454d40faf 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from collections import defaultdict from difflib import get_close_matches import logging @@ -496,6 +497,40 @@ class ir_translation(osv.osv): fields = self.env['ir.model.fields'].search([('model', '=', model_name)]) return {field.name: field.help for field in fields} + @api.multi + def check(self, mode): + """ Check access rights of operation ``mode`` on ``self`` for the + current user. Raise an AccessError in case conditions are not met. + """ + if self.env.user._is_admin(): + return + + # collect translated field records (model_ids) and other translations + trans_ids = [] + model_ids = defaultdict(list) + model_fields = defaultdict(list) + for trans in self: + if trans.type == 'model': + mname, fname = trans.name.split(',') + model_ids[mname].append(trans.res_id) + model_fields[mname].append(fname) + else: + trans_ids.append(trans.id) + + # check for regular access rights on other translations + if trans_ids: + records = self.browse(trans_ids) + records.check_access_rights(mode) + records.check_access_rule(mode) + + # check for read/write access on translated field records + fmode = 'read' if mode == 'read' else 'write' + for mname, ids in model_ids.iteritems(): + records = self.env[mname].browse(ids) + records.check_access_rights(fmode) + records.check_field_access_rights(fmode, model_fields[mname]) + records.check_access_rule(fmode) + @api.model def create(self, vals): if vals.get('type') == 'model' and vals.get('value'): @@ -503,7 +538,8 @@ class ir_translation(osv.osv): mname, fname = vals['name'].split(',') field = self.env[mname]._fields[fname] vals['value'] = field.check_trans_value(vals['value']) - record = super(ir_translation, self).create(vals) + record = super(ir_translation, self.sudo()).create(vals).with_env(self.env) + record.check('create') self.clear_caches() return record @@ -520,19 +556,17 @@ class ir_translation(osv.osv): vals['value'] = field.check_trans_value(vals['value']) elif vals.get('src') or not vals.get('value', True): vals.setdefault('state', 'to_translate') - result = super(ir_translation, self).write(vals) + self.check('write') + result = super(ir_translation, self.sudo()).write(vals) + self.check('write') self.clear_caches() return result - def unlink(self, cursor, user, ids, context=None): - if context is None: - context = {} - if isinstance(ids, (int, long)): - ids = [ids] - + @api.multi + def unlink(self): + self.check('unlink') self.clear_caches() - result = super(ir_translation, self).unlink(cursor, user, ids, context=context) - return result + return super(ir_translation, self.sudo()).unlink() @api.model def insert_missing(self, field, records): diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index 3f4f49c8fff..21a18587c18 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -28,7 +28,7 @@ "access_ir_sequence_group_system","ir_sequence group_system","model_ir_sequence","group_system",1,1,1,1 "access_ir_sequence_date_range_group_user","ir_sequence_date_range group_user","model_ir_sequence_date_range","group_user",1,0,0,0 "access_ir_sequence_date_range_group_system","ir_sequence_date_range group_system","model_ir_sequence_date_range","group_system",1,1,1,1 -"access_ir_translation_all","ir_translation all","model_ir_translation",,1,1,1,1 +"access_ir_translation_all","ir_translation all","model_ir_translation","group_user",1,1,1,1 "access_ir_translation_group_system","ir_translation group_system","model_ir_translation","group_system",1,1,1,1 "access_ir_ui_menu_group_user","ir_ui_menu group_user","model_ir_ui_menu",base.group_user,1,0,0,0 "access_ir_ui_menu_group_system","ir_ui_menu group_system","model_ir_ui_menu","group_system",1,1,1,1