diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index 667a77e8a13..664f20abbd3 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -1147,67 +1147,48 @@ - + Record rules - ir.rule.group + ir.rule form
- - - - - -
- + Record rules - ir.rule.group + ir.rule tree - - - - - - Rule Definition - ir.rule - form - -
- - - - - - - -
- - - Rules - ir.rule - tree - - - @@ -1215,22 +1196,20 @@ + Record Rules - ir.rule.group + ir.rule form - + - + Property multi-company - - ['|',('company_id','child_of',user.company_id.id),('company_id','=',False)] - diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 670fb420bd2..f6412e85b75 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). # @@ -15,7 +15,7 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## import logging @@ -80,7 +80,7 @@ class ir_model(osv.osv): if context: context.pop('__last_update', None) return super(ir_model,self).write(cr, user, ids, vals, context) - + def create(self, cr, user, vals, context=None): if context and context.get('manual',False): vals['state']='manual' @@ -226,7 +226,7 @@ class ir_model_fields(osv.osv): 'domain': fields.char('Domain', size=256), 'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'), 'view_load': fields.boolean('View Auto-Load'), - 'selectable': fields.boolean('Selectable'), + 'selectable': fields.boolean('Selectable'), } _rec_name='field_description' _defaults = { @@ -278,7 +278,7 @@ class ir_model_fields(osv.osv): self.pool.get(vals['model'])._auto_init(cr, ctx) return res - + ir_model_fields() class ir_model_access(osv.osv): @@ -378,6 +378,7 @@ class ir_model_access(osv.osv): 'create': _('You can not create this kind of document! (%s)'), 'unlink': _('You can not delete this document! (%s)'), } + raise except_orm(_('AccessError'), msgs[mode] % model_name ) return r diff --git a/bin/addons/base/ir/ir_rule.py b/bin/addons/base/ir/ir_rule.py index c4165d1bc93..ae13bb5ccda 100644 --- a/bin/addons/base/ir/ir_rule.py +++ b/bin/addons/base/ir/ir_rule.py @@ -23,132 +23,94 @@ from osv import fields,osv import time import tools - -class ir_rule_group(osv.osv): - _name = 'ir.rule.group' - - _columns = { - 'name': fields.char('Name', size=128, select=1), - 'model_id': fields.many2one('ir.model', 'Object',select=1, required=True), - 'global': fields.boolean('Global', select=1, help="Make the rule global, otherwise it needs to be put on a group"), - 'rules': fields.one2many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True"), - 'groups': fields.many2many('res.groups', 'group_rule_group_rel', 'rule_group_id', 'group_id', 'Groups'), - 'users': fields.many2many('res.users', 'user_rule_group_rel', 'rule_group_id', 'user_id', 'Users'), - } - - _order = 'model_id, global DESC' - - _defaults={ - 'global': lambda *a: True, - } - -ir_rule_group() - - class ir_rule(osv.osv): _name = 'ir.rule' - _rec_name = 'field_id' - - def _operand(self,cr,uid,context): - - def get(object, level=3, recur=None, root_tech='', root=''): - res = [] - if not recur: - recur = [] - fields = self.pool.get(object).fields_get(cr,uid) - key = fields.keys() - key.sort() - for k in key: - - if fields[k]['type'] in ('many2one'): - res.append((root_tech+'.'+k+'.id', - root+'/'+fields[k]['string'])) - - elif fields[k]['type'] in ('many2many', 'one2many'): - res.append(('\',\'.join(map(lambda x: str(x.id), '+root_tech+'.'+k+'))', - root+'/'+fields[k]['string'])) - - else: - res.append((root_tech+'.'+k, - root+'/'+fields[k]['string'])) - - if (fields[k]['type'] in recur) and (level>0): - res.extend(get(fields[k]['relation'], level-1, - recur, root_tech+'.'+k, root+'/'+fields[k]['string'])) - - return res - - res = [("False", "False"), ("True", "True"), ("user.id", "User")] - res += get('res.users', level=1, - recur=['many2one'], root_tech='user', root='User') - return res def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}): res = {} for rule in self.browse(cr, uid, ids, context): eval_user_data = {'user': self.pool.get('res.users').browse(cr, 1, uid), 'time':time} - - if rule.domain_force: - res[rule.id] = eval(rule.domain_force, eval_user_data) - else: - if rule.operand and rule.operand.startswith('user.') and rule.operand.count('.') > 1: - #Need to check user.field.field1.field2(if field is False,it will break the chain) - op = rule.operand[5:] - rule.operand = rule.operand[:5+len(op[:op.find('.')])] +' and '+ rule.operand + ' or False' - if rule.operator in ('in', 'child_of'): - dom = eval("[('%s', '%s', [%s])]" % (rule.field_id.name, rule.operator, - eval(rule.operand,eval_user_data)), eval_user_data) - else: - dom = eval("[('%s', '%s', %s)]" % (rule.field_id.name, rule.operator, - rule.operand), eval_user_data) - res[rule.id] = dom + res[rule.id] = eval(rule.domain_force, eval_user_data) return res + def _get_value(self, cr, uid, ids, field_name, arg, context={}): + res = {} + for rule in self.browse(cr, uid, ids, context): + if not rule.groups: + res[rule.id] = True + else: + res[rule.id] = False + return res + + def _check_model_obj(self, cr, uid, ids, context={}): + model_obj = self.pool.get('ir.model') + for rule in self.browse(cr, uid, ids, context): + model = model_obj.browse(cr, uid, rule.model_id.id, context).model + obj = self.pool.get(model) + if isinstance(obj, osv.osv_memory): + return False + return True + _columns = { - 'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1), - 'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator'), - 'operand':fields.selection(_operand,'Operand', size=64), - 'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"), - 'domain_force': fields.char('Force Domain', size=250), + 'name': fields.char('Name', size=128, select=1), + 'model_id': fields.many2one('ir.model', 'Object',select=1, required=True), + 'global': fields.function(_get_value, method=True, string='Global', type='boolean', store=True, help="Make the rule global, otherwise it needs to be put on a group"), + 'groups': fields.many2many('res.groups', 'rule_group_rel', 'rule_group_id', 'group_id', 'Groups'), + 'domain_force': fields.char('Domain', size=250), 'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250), - 'perm_read': fields.boolean('Read Access'), - 'perm_write': fields.boolean('Write Access'), - 'perm_create': fields.boolean('Create Access'), - 'perm_unlink': fields.boolean('Delete Access') + 'perm_read': fields.boolean('Apply For Read'), + 'perm_write': fields.boolean('Apply For Write'), + 'perm_create': fields.boolean('Apply For Create'), + 'perm_unlink': fields.boolean('Apply For Delete') } + + _order = 'model_id DESC' + _defaults = { - 'perm_read': lambda *a: True, - 'perm_write': lambda *a: True, - 'perm_create': lambda *a: True, - 'perm_unlink': lambda *a: True, + 'perm_read': True, + 'perm_write': True, + 'perm_create': True, + 'perm_unlink': True, + 'global': True, } _sql_constraints = [ ('no_access_rights', 'CHECK (perm_read!=False or perm_write!=False or perm_create!=False or perm_unlink!=False)', 'Rule must have atleast one checked access right'), ] + _constraints = [ + (_check_model_obj, 'Rules are not supported for osv_memory objects !', ['model_id']) + ] - def onchange_all(self, cr, uid, ids, field_id, operator, operand): - if not (field_id or operator or operand): - return {} + def domain_create(self, cr, uid, rule_ids): + dom = ['&'] * (len(rule_ids)-1) + for rule in self.browse(cr, uid, rule_ids): + dom += rule.domain + return dom def domain_get(self, cr, uid, model_name, mode='read', context={}): + group_rule = {} + global_rules = [] + if uid == 1: return [], [], ['"'+self.pool.get(model_name)._table+'"'] - cr.execute("""SELECT r.id FROM ir_rule r - JOIN (ir_rule_group g - JOIN ir_model m ON (g.model_id = m.id)) - ON (g.id = r.rule_group) + JOIN ir_model m ON (r.model_id = m.id) WHERE m.model = %s AND r.perm_""" + mode + """ - AND (g.id IN (SELECT rule_group_id FROM group_rule_group_rel g_rel + AND (r.id IN (SELECT rule_group_id FROM rule_group_rel g_rel JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid) - WHERE u_rel.uid = %s) OR g.global)""", (model_name, uid)) + WHERE u_rel.uid = %s) OR r.global)""", (model_name, uid)) ids = map(lambda x: x[0], cr.fetchall()) - dom = [] for rule in self.browse(cr, uid, ids): - dom += rule.domain + for group in rule.groups: + group_rule.setdefault(group.id, []).append(rule.id) + if not rule.groups: + global_rules.append(rule.id) + dom = self.domain_create(cr, uid, global_rules) + dom += ['|'] * (len(group_rule)-1) + for value in group_rule.values(): + dom += self.domain_create(cr, uid, value) d1,d2,tables = self.pool.get(model_name)._where_calc(cr, uid, dom, active_test=False) return d1, d2, tables domain_get = tools.cache()(domain_get) diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index ff61b9ec6fa..fe67848de6a 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -34,7 +34,7 @@ class groups(osv.osv): _columns = { 'name': fields.char('Group Name', size=64, required=True), 'model_access': fields.one2many('ir.model.access', 'group_id', 'Access Controls'), - 'rule_groups': fields.many2many('ir.rule.group', 'group_rule_group_rel', + 'rule_groups': fields.many2many('ir.rule', 'rule_group_rel', 'group_id', 'rule_group_id', 'Rules', domain="[('global', '<>', True)]"), 'menu_access': fields.many2many('ir.ui.menu', 'ir_ui_menu_group_rel', 'gid', 'menu_id', 'Access Menu'), 'comment' : fields.text('Comment',size=250), @@ -47,7 +47,7 @@ class groups(osv.osv): group_name = self.read(cr, uid, [id], ['name'])[0]['name'] default.update({'name': group_name +' (copy)'}) return super(groups, self).copy(cr, uid, id, default, context) - + def write(self, cr, uid, ids, vals, context=None): if 'name' in vals: if vals['name'].startswith('-'): @@ -185,7 +185,6 @@ class users(osv.osv): 'menu_id': fields.many2one('ir.actions.actions', 'Menu Action'), 'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'), 'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'), - 'rules_id': fields.many2many('ir.rule.group', 'user_rule_group_rel', 'user_id', 'rule_group_id', 'Rules'), 'company_id': fields.many2one('res.company', 'Company', required=True, help="The company this user is currently working for."), 'company_ids':fields.many2many('res.company','res_company_users_rel','user_id','cid','Companies'), diff --git a/bin/addons/base/security/base_security.xml b/bin/addons/base/security/base_security.xml index ca1f33aa23e..1059cf4da37 100644 --- a/bin/addons/base/security/base_security.xml +++ b/bin/addons/base/security/base_security.xml @@ -72,37 +72,24 @@ - + res.partner.address company - - - - [('company_id','child_of',[user.company_id.id])] - + res.partner company - - - - [('company_id','child_of',[user.company_id.id])] - - + Multi_company_default company - - - - [('company_id','child_of',[user.company_id.id])] diff --git a/bin/addons/base/security/ir.model.access.csv b/bin/addons/base/security/ir.model.access.csv index bc291af8b33..cf0f73a5cc9 100644 --- a/bin/addons/base/security/ir.model.access.csv +++ b/bin/addons/base/security/ir.model.access.csv @@ -23,9 +23,7 @@ "access_ir_report_custom_group_system","ir_report_custom group_system","model_ir_report_custom",,1,0,0,0 "access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0 "access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0 -"access_ir_rule_group_group_user","ir_rule_group group_user","model_ir_rule_group",,1,0,0,0 "access_ir_rule_group_erp_manager","ir_rule group_erp_manager","model_ir_rule","group_erp_manager",1,1,1,1 -"access_ir_rule_group_group_erp_manager","ir_rule_group group_erp_manager","model_ir_rule_group","group_erp_manager",1,1,1,1 "access_ir_sequence_group_user","ir_sequence group_user","model_ir_sequence",,1,1,1,1 "access_ir_sequence_type_group_user","ir_sequence_type group_user","model_ir_sequence_type",,1,0,0,0 "access_ir_translation_group_system","ir_translation group_system","model_ir_translation",,1,1,1,1 diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 35ff1667418..71faa9898a5 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -656,6 +656,11 @@ class function(_column): self._symbol_f = float._symbol_f self._symbol_set = float._symbol_set + if type == 'boolean': + self._symbol_c = boolean._symbol_c + self._symbol_f = boolean._symbol_f + self._symbol_set = boolean._symbol_set + def digits_change(self, cr): if self.digits_compute: t = self.digits_compute(cr) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index e57f9ce3d87..d407ac4d4af 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1725,6 +1725,7 @@ class orm_memory(orm_template): def read(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'): if not context: context = {} + self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context) if not fields_to_read: fields_to_read = self._columns.keys() result = [] @@ -1754,6 +1755,7 @@ class orm_memory(orm_template): def write(self, cr, user, ids, vals, context=None): if not ids: return True + self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context) vals2 = {} upd_todo = [] for field in vals: @@ -1772,6 +1774,7 @@ class orm_memory(orm_template): return id_new def create(self, cr, user, vals, context=None): + self.pool.get('ir.model.access').check(cr, user, self._name, 'create', context=context) self.vaccum(cr, user) self.next_id += 1 id_new = self.next_id @@ -1923,6 +1926,7 @@ class orm_memory(orm_template): return res or [] def unlink(self, cr, uid, ids, context=None): + self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink', context=context) for id in ids: if id in self.datas: del self.datas[id] @@ -3225,7 +3229,7 @@ class orm(orm_template): """ if not context: context = {} - self.pool.get('ir.model.access').check(cr, user, self._name, 'create') + self.pool.get('ir.model.access').check(cr, user, self._name, 'create', context=context) default = [] @@ -3281,7 +3285,7 @@ class orm(orm_template): del vals[self._inherits[table]] record_id = tocreate[table].pop('id', None) - + if record_id is None or not record_id: record_id = self.pool.get(table).create(cr, user, tocreate[table], context=context) else: