[IMP+ADD]:improved ir.rule code, added constraint on ir.rule for osv_memory objects

bzr revid: rvo@tinyerp.co.in-20100429120158-rt4p9t1o6kkj78fh
This commit is contained in:
Rvo (Open ERP) 2010-04-29 17:31:58 +05:30
parent 39388d4b22
commit c9720d28f5
8 changed files with 110 additions and 175 deletions

View File

@ -1147,67 +1147,48 @@
<!-- Rules -->
<record id="view_rule_group_form" model="ir.ui.view">
<record id="view_rule_form" model="ir.ui.view">
<field name="name">Record rules</field>
<field name="model">ir.rule.group</field>
<field name="model">ir.rule</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Record rules">
<field name="model_id" select="1"/>
<field name="global" select="1"/>
<field colspan="4" name="name"/>
<group col="6" colspan="4" expand="1">
<field colspan="6" name="rules" nolabel="1"/>
<label align="0.0" colspan="6" string="The rule is satisfied if all test are True (AND)"/>
<label align="0.0" colspan="6" string="Multiple rules on same objects are joined using operator OR"/>
<label align="0.0" angle="2" colspan="4" string="Rules will be applied on following scenario : "/>
<label align="0.0" angle="2" colspan="4" string="GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )"/>
<separator colspan="4"/>
<group col="6" colspan="4">
<field colspan="4" name="name"/>
<field name="model_id" select="1"/>
</group>
<separator colspan="4" string="Access Rights"/>
<group col="8" colspan="4" expand="1">
<field name="perm_read"/>
<field name="perm_write"/>
<field name="perm_create"/>
<field name="perm_unlink"/>
</group>
<separator colspan="4" string="Domain Setup"/>
<group colspan="4" expand="1">
<field name="domain_force" colspan="4"/>
</group>
<separator colspan="4" string="Groups"/>
<group colspan="4" expand="1">
<field name="global" select="1"/>
<field name="groups" select="1" nolabel="1" colspan="4"/>
</group>
</form>
</field>
</record>
<record id="view_rule_group_tree" model="ir.ui.view">
<record id="view_rule_tree" model="ir.ui.view">
<field name="name">Record rules</field>
<field name="model">ir.rule.group</field>
<field name="model">ir.rule</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Record rules">
<field name="model_id"/>
<field name="name"/>
<field name="global"/>
</tree>
</field>
</record>
<record id="view_rule_form" model="ir.ui.view">
<field name="name">Rule Definition</field>
<field name="model">ir.rule</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Test">
<separator colspan="4" string="Simple domain setup"/>
<group col="6" colspan="4">
<field name="field_id"/>
<field name="operator"/>
<field name="operand"/>
</group>
<separator colspan="4" string="Manual domain setup"/>
<field name="domain_force"/>
<label colspan="4" string="If you don't force the domain, it will use the simple domain setup"/>
<newline/>
<field name="perm_read"/>
<field name="perm_write"/>
<field name="perm_create"/>
<field name="perm_unlink"/>
</form>
</field>
</record>
<record id="view_rule_tree" model="ir.ui.view">
<field name="name">Rules</field>
<field name="model">ir.rule</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Test">
<field name="domain"/>
<field name="perm_read"/>
<field name="perm_write"/>
<field name="perm_create"/>
@ -1215,22 +1196,20 @@
</tree>
</field>
</record>
<record id="action_rule" model="ir.actions.act_window">
<field name="name">Record Rules</field>
<field name="res_model">ir.rule.group</field>
<field name="res_model">ir.rule</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_rule_group_tree"/>
<field name="view_id" ref="view_rule_tree"/>
</record>
<menuitem action="action_rule" id="menu_action_rule" parent="base.menu_security"/>
<record id="property_rule_group" model="ir.rule.group">
<record id="property_rule" model="ir.rule">
<field name="name">Property multi-company</field>
<field model="ir.model" name="model_id" ref="model_ir_property"/>
<field eval="True" name="global"/>
</record>
<record id="property_rule" model="ir.rule">
<field name="domain_force">['|',('company_id','child_of',user.company_id.id),('company_id','=',False)]</field>
<field name="rule_group" ref="property_rule_group"/>
</record>
<!--server action view-->

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@ -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 <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
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

View File

@ -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)

View File

@ -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'),

View File

@ -72,37 +72,24 @@
</record>
<record model="ir.rule.group" id="res_partner_address_rule_group">
<record model="ir.rule" id="res_partner_address_rule">
<field name="name">res.partner.address company</field>
<field name="model_id" ref="model_res_partner_address"/>
<field name="global" eval="True"/>
</record>
<record model="ir.rule" id="res_partner_address_comp_rule">
<field name="field_id" search="[('model','=','res.partner.address'),('name','=','company_id')]" model="ir.model.fields"/>
<field name="rule_group" ref="res_partner_address_rule_group"/>
<field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field>
</record>
<record model="ir.rule.group" id="res_partner_rule_group">
<record model="ir.rule" id="res_partner_rule">
<field name="name">res.partner company</field>
<field name="model_id" ref="model_res_partner"/>
<field name="global" eval="True"/>
</record>
<record model="ir.rule" id="res_partner_comp_rule">
<field name="field_id" search="[('model','=','res.partner'),('name','=','company_id')]" model="ir.model.fields"/>
<field name="rule_group" ref="res_partner_rule_group"/>
<field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field>
</record>
<record model="ir.rule.group" id="multi_company_default_rule_group">
<record model="ir.rule" id="multi_company_default_rule">
<field name="name">Multi_company_default company</field>
<field name="model_id" ref="model_multi_company_default"/>
<field name="global" eval="True"/>
</record>
<record model="ir.rule" id="multi_company_default_comp_rule">
<field name="field_id" search="[('model','=','multi_company.default'),('name','=','company_id')]" model="ir.model.fields"/>
<field name="rule_group" ref="multi_company_default_rule_group"/>
<field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field>
</record>

View File

@ -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

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
23 access_ir_report_custom_group_system ir_report_custom group_system model_ir_report_custom 1 0 0 0
24 access_ir_report_custom_fields_group_system ir_report_custom_fields group_system model_ir_report_custom_fields 1 0 0 0
25 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
26 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
27 access_ir_sequence_group_user ir_sequence group_user model_ir_sequence 1 1 1 1
28 access_ir_sequence_type_group_user ir_sequence_type group_user model_ir_sequence_type 1 0 0 0
29 access_ir_translation_group_system ir_translation group_system model_ir_translation 1 1 1 1

View File

@ -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)

View File

@ -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: