From bbaa945575bc08163aff66272efa2d0b63f73416 Mon Sep 17 00:00:00 2001 From: Aubort Jean-Baptiste Date: Fri, 18 Jul 2008 17:53:12 +0200 Subject: [PATCH] Advanced view for security management & removed parent_id on ir.model bzr revid: jean-baptiste.aubort@camptocamp.com-20080718155312-8z9elapi9w5xldm4 --- bin/addons/base/base_security.xml | 528 ++++++++++++++++++++---------- bin/addons/base/ir/ir.xml | 55 +--- bin/addons/base/ir/ir_model.py | 218 ++++++++---- 3 files changed, 516 insertions(+), 285 deletions(-) diff --git a/bin/addons/base/base_security.xml b/bin/addons/base/base_security.xml index 67652c98463..339427582ec 100644 --- a/bin/addons/base/base_security.xml +++ b/bin/addons/base/base_security.xml @@ -48,181 +48,361 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - ir.model.form1 - ir.model - form - -
- - - - - -
- - - ir.model.tree1 + + Objects Security Tree ir.model tree - - - - - - - - - Objects + + Objects Security ir.model form form,tree - + + {'advanced':True} - - - tree - - - - - - - form - - - - - + diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 741a56ca8f0..b21e0aa42b4 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -36,10 +36,21 @@ import time import tools import pooler +from pprint import pprint #FIXME: Dev + def _get_fields_type(self, cr, uid, context=None): cr.execute('select distinct ttype,ttype from ir_model_fields') return cr.fetchall() + +class ir_model_type(osv.osv): + _name = 'ir.model.type' + _columns = { + 'name': fields.char('Name', size=64, required=True), + #'model_id': fields.many2one('ir.model', 'Models'), + } +ir_model_type() + class ir_model(osv.osv): _name = 'ir.model' _description = "Objects" @@ -49,7 +60,8 @@ class ir_model(osv.osv): 'model': fields.char('Object Name', size=64, required=True, search=1), 'info': fields.text('Information'), 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True), - 'parent_id': fields.many2one('ir.model', 'Parent id'), + #'type_id': fields.one2many('ir.model.type', 'model_id', 'Type'), + #'type_id': fields.many2many('ir.model.type', 'ir_model_type_rel', 'model_id', 'type_id', 'Types'), 'state': fields.selection([('manual','Custom Object'),('base','Base Field')],'Manualy Created',readonly=1), } _defaults = { @@ -57,6 +69,11 @@ class ir_model(osv.osv): 'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base', } + #FIXME: We'll be back soon + #_constraints = [ + # (_check_model_name, 'The model name must start with x_ and not contain any special character !', ['model']), + #] + def _check_model_name(self, cr, uid, ids): for model in self.browse(cr, uid, ids): if model.state=='manual': @@ -65,27 +82,6 @@ class ir_model(osv.osv): if not re.match('^[a-z_A-Z0-9]+$',model.model): return False return True - - # FIXME: What it was for ? - #_constraints = [ - # (_check_model_name, 'The model name must start with x_ and not contain any special character !', ['model']), - #] - - def unlink(self, cr, user, ids, context=None): - for model in self.browse(cr, user, ids, context): - if model.state <> 'manual': - raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(field.name,)) - res = super(ir_model, self).unlink(cr, user, ids, context) - pooler.restart_pool(cr.dbname) - return res - - def create(self, cr, user, vals, context=None): - if context and context.get('manual',False): - vals['state']='manual' - res = super(ir_model,self).create(cr, user, vals, context) - if vals.get('state','base')=='manual': - pooler.restart_pool(cr.dbname) - return res def instanciate(self, cr, user, model, context={}): class x_custom_model(osv.osv): @@ -97,16 +93,129 @@ class ir_model(osv.osv): x_custom_model._rec_name = 'x_name' else: x_custom_model._rec_name = x_custom_model._columns.keys()[0] -ir_model() + + def unlink(self, cr, user, ids, context=None): + #TODO Advanced + for model in self.browse(cr, user, ids, context): + if model.state <> 'manual': + raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(field.name,)) + res = super(ir_model, self).unlink(cr, user, ids, context) + pooler.restart_pool(cr.dbname) + return res -class ir_model_tree(osv.osv): - _name = 'ir.model.tree' - _description = "Objects Tree" - _columns = { - 'model_id': fields.many2one('ir.model', 'Model id', required=True), - 'parent_id': fields.many2one('ir.model', 'Parent id', required=True), - } -ir_model_tree() + def create(self, cr, user, vals, context=None): + #TODO Advanced + if context and context.get('manual',False): + vals['state']='manual' + res = super(ir_model,self).create(cr, user, vals, context) + if vals.get('state','base')=='manual': + pooler.restart_pool(cr.dbname) + return res + + def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): + result = super(osv.osv, self).read(cr, user, ids, fields, context, load) + if 'advanced' in context: + for res in result: + rules = self.pool.get('ir.model.access').search(cr, user, [('model_id', '=', res['id'])]) + rules_br = self.pool.get('ir.model.access').browse(cr, user, rules) + for rule in rules_br: + perm_list = [] + if rule.perm_read: + perm_list.append('r') + if rule.perm_write: + perm_list.append('w') + if rule.perm_create: + perm_list.append('c') + if rule.perm_unlink: + perm_list.append('u') + perms = ",".join(perm_list) + res['group_%i'%rule.group_id.id] = perms + return result + + def write(self, cr, user, ids, vals, context=None): + if 'advanced' in context: + perms_rel = ['create','read','unlink','write'] + perms_all = ['c','r','u','w'] + perms = [] + vals_new = vals.copy() + + for val in vals: + if val[:6]=='group_': + #Values + group_id = int(val[6:]) + model_id = ids[0] + if isinstance(vals[val], basestring): + perms = list(set(vals[val].split(","))) + + #Syntax check + for perm in perms: + if perm not in perms_all: + model_name = self.pool.get('ir.model').browse(cr, user, [model_id])[0].model + group_name = self.pool.get('res.groups').browse(cr, user, [group_id])[0].name + raise osv.except_osv('Error !', 'There is an invalid rule in "%s" for "Group %s". Valid rules are:\r\tc=create\r\tr=read\r\tu=unlink\r\tw=write\rYou must separate them by a coma, example: r,w'%(model_name, group_name)) + + #Assign rights + req = {} + for i,perm in enumerate(perms_all): + #if perm in perms: + # req['perm_%s'%perms_rel[i]] = True + #else: + # req['perm_%s'%perms_rel[i]] = False + req['perm_%s'%perms_rel[i]] = perm in perms and 'True' or 'False' + + #Apply rule + sql = '' + rules = self.pool.get('ir.model.access').search(cr, user, [('model_id', '=', model_id),('group_id', '=', group_id)]) + if rules: + for k in req: + sql += '%s=%s,'%(k,req[k]) + cr.execute("update ir_model_access set %s where id=%i"%(sql[:-1], rules[0])) + else: + model_name = self.pool.get('ir.model').browse(cr, user, [model_id])[0].name + group_name = self.pool.get('res.groups').browse(cr, user, [group_id])[0].name + rule_name = '%s %s'%(model_name,group_name) + cr.execute('insert into ir_model_access \ + (name, model_id, group_id, perm_create, perm_read, perm_unlink, perm_write) \ + values (%s, %i, %i, %s, %s, %s, %s)', + (rule_name, model_id, group_id,req['perm_create'], req['perm_read'], req['perm_unlink'], req['perm_write'],)) + vals_new.pop(val) + return super(osv.osv, self).write(cr, user, ids, vals_new, context) + + def fields_get(self, cr, user, fields=None, context=None, read_access=True): + result = super(osv.osv, self).fields_get(cr, user, fields, context) + if 'advanced' in context: + groups = self.pool.get('res.groups').search(cr, user, []) + groups_br = self.pool.get('res.groups').browse(cr, user, groups) + for group in groups_br: + result['group_%i'%group.id] = {'string': 'Group %s'%group.name,'type': 'char','size': 7} + return result + + def on_change_write(self, cr, user, ids, vals, context=None): + print 'prout' + + def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}, toolbar=False): + result = super(osv.osv, self).fields_view_get(cr, uid, view_id,view_type,context) + if view_type=='tree' and 'advanced' in context: + groups = self.pool.get('res.groups').search(cr, uid, []) + groups_br = self.pool.get('res.groups').browse(cr, uid, groups) + + #state = '' + #TODO: qqch du genre si un object n'a pas de secu + #for field in journal.view_id.columns_id: + # if field.field=='state': + # state = ' colors="red:state==\'draft\'"' + + cols = ['model'] + xml = '''''' + for group in groups_br: + #xml += '''''' % (group.id, group.name) #TODO: on_change + xml += '''''' % (group.id, group.name) + xml += '''''' + + result['arch'] = xml + result['fields'] = self.fields_get(cr, uid, cols, context) + return result +ir_model() class ir_model_fields(osv.osv): _name = 'ir.model.fields' @@ -159,7 +268,6 @@ class ir_model_fields(osv.osv): vals['model']=model_data['model'] if context and context.get('manual',False): vals['state']='manual' - print vals['name'] res = super(ir_model_fields,self).create(cr, user, vals, context) if vals.get('state','base')=='manual': if not vals['name'].startswith('x_'): @@ -186,7 +294,7 @@ class ir_model_access(osv.osv): res = False grouparr = group.split('.') if grouparr: - cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module='%s' and name='%s')" % (grouparr[0], grouparr[1])) + cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module='%s' and name='%s')", (grouparr[0], grouparr[1],)) r = cr.fetchall() if not r: res = False @@ -196,44 +304,22 @@ class ir_model_access(osv.osv): res = False return res - def check_tree(self, cr, uid, model_name, mode): - cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' - 'from ir_model_access a join ir_model m on (m.id=a.model_id) ' - 'join res_groups_users_rel gu on (gu.gid = a.group_id) ' - 'where m.model = %s and gu.uid = %s', (model_name, uid,)) - res = cr.fetchall()[0][0] - if res==None: - cr.execute('select model from ir_model where id=(select parent_id from ir_model where model=%s)', (model_name,)) - parent_name = cr.fetchall() - if len(parent_name)>0: - res = self.check_tree(cr, uid, parent_name[0][0], mode) # Recursiv until there is no parent - print '\tcheck %s = %s' % (parent_name[0][0], str(res)) - return res - - def check(self, cr, uid, model_name, mode='read',raise_exception=True): + def check(self, cr, uid, model_name, mode='read',raise_exception=True): assert mode in ['read','write','create','unlink'], 'Invalid access mode for security' - - # We first check if a specific rule exists - cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' - 'FROM ir_model_access a ' - 'JOIN ir_model m ON (a.model_id=m.id) ' - 'JOIN res_groups_users_rel gu ON (gu.gid = a.group_id) ' - 'WHERE m.model = %s AND gu.uid = %s', (model_name, uid,)) - r = cr.fetchall() - - print '%s in %s = %s by %i'%(mode, model_name, str(r[0][0]), uid) # FIXME: REMOVE PLEASE - # Users root and admin have all access (Todo: exclude xml-rpc requests) if uid==1 or uid==2: return True - # Recursivly check parent if present - if r[0][0] == None: - res = self.check_tree(cr, uid, model_name, mode) - else: - res = r[0][0] + # We check if a specific rule exists + cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' + 'from ir_model_access a join ir_model m on (m.id=a.model_id) ' + 'join res_groups_users_rel gu on (gu.gid = a.group_id) ' + 'where m.model = %s and gu.uid = %s', (model_name, uid,)) + r = cr.fetchall() - if not res: + print '%s in %s = %s by %i'%(mode, model_name, str(r[0][0]), uid) # FIXME: REMOVE PLEASE + + if not r[0][0]: if raise_exception: msgs = { 'read': _('You can not read this document! (%s)'), @@ -242,7 +328,7 @@ class ir_model_access(osv.osv): 'unlink': _('You can not delete this document! (%s)'), } raise except_orm(_('AccessError'), msgs[mode] % model_name ) - return res + return r[0][0] check = tools.cache()(check)