diff options
Diffstat (limited to 'bin/addons/base/ir/ir_model.py')
| -rw-r--r-- | bin/addons/base/ir/ir_model.py | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py new file mode 100644 index 00000000000..cbd03803795 --- /dev/null +++ b/bin/addons/base/ir/ir_model.py @@ -0,0 +1,273 @@ +############################################################################## +# +# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from osv import fields,osv +import ir +import netsvc + +import time +import tools +import pooler + +class ir_model(osv.osv): + _name = 'ir.model' + _rec_name = 'model' + _columns = { + 'name': fields.char('Model name', size=64, translate=True), + 'model': fields.char('Object name', size=64, required=True), + 'info': fields.text('Information'), + 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True), + } + _defaults = { + 'name': lambda *a: 'No Name', + } +ir_model() + +class ir_model_fields(osv.osv): + _name = 'ir.model.fields' + _columns = { + 'name': fields.char('Name', size=64), + 'model': fields.char('Model Name', size=64, required=True), +# on pourrait egalement changer ca en many2one, mais le prob c'est qu'alors faut +# faire une jointure a chaque fois qu'on recherche vu que le client ne connait que le nom +# de l'objet et pas son id + 'relation': fields.char('Model Relation', size=64), + 'model_id': fields.many2one('ir.model', 'Model id', required=True, select=True), +# in fact, this is the field label + 'field_description': fields.char('Field Description', size=256), + 'ttype': fields.char('Field Type', size=64), + 'relate': fields.boolean('Click and Relate'), + + 'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'), + 'group_name': fields.char('Group Name', size=128), + 'view_load': fields.boolean('View Auto-Load'), + } + _defaults = { + 'relate': lambda *a: 1, + 'view_load': lambda *a: 0, + 'name': lambda *a: 'No Name', + 'field_description': lambda *a: 'No description available', + } + _order = "id" +ir_model_fields() + +class ir_model_access(osv.osv): + _name = 'ir.model.access' + _columns = { + 'name': fields.char('Name', size=64, required=True), + 'model_id': fields.many2one('ir.model', 'Model', required=True), + 'group_id': fields.many2one('res.groups', 'Group'), + 'perm_read': fields.boolean('Read Access'), + 'perm_write': fields.boolean('Write Access'), + 'perm_create': fields.boolean('Create Access'), + } + def check(self, cr, uid, model_name, mode='read'): + assert mode in ['read','write','create'], 'Invalid access mode for security' + + # fetch the list of rules for this "permission type" on this model + cr.execute('select group_id, perm_'+mode+' from ir_model_access a left join ir_model m on (a.model_id=m.id) where m.model=%s', (model_name,)) + + # if no rule is found, grant the access + if not cr.rowcount: + return True + + # compute the list of groups which have the right we are looking for + ids = map(lambda x: str(x[0]), filter(lambda x: x[1], cr.fetchall())) + if not ids: + raise osv.except_osv('Access denied !', 'You can not %s this resource !' % mode) + ids_str = ','.join(ids) + + # check if the user is part of one of those groups + cr.execute('select count(*) from res_groups_users_rel where uid=%d and gid in ('+ids_str+')', (uid,)) + if cr.fetchone()[0]: + return True + raise osv.except_osv('Access denied !', 'You can not %s this resource !' % mode) + check = tools.cache()(check) + + # + # Methods to clean the cache on the Check Method. + # + def write(self, cr, uid, *args, **argv): + res = super(ir_model_access, self).write(cr, uid, *args, **argv) + self.check() + return res + def create(self, cr, uid, *args, **argv): + res = super(ir_model_access, self).create(cr, uid, *args, **argv) + self.check() + return res + def unlink(self, cr, uid, *args, **argv): + res = super(ir_model_access, self).unlink(cr, uid, *args, **argv) + self.check() + return res +ir_model_access() + +class ir_model_data(osv.osv): + _name = 'ir.model.data' + _columns = { + 'name': fields.char('XML Identifier', required=True, size=64), + 'model': fields.char('Model', required=True, size=64), + 'module': fields.char('Module', required=True, size=64), + 'res_id': fields.integer('Resource ID'), + 'noupdate': fields.boolean('Non Updatable'), + 'date_update': fields.datetime('Update Date'), + 'date_init': fields.datetime('Init Date') + } + _defaults = { + 'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'noupdate': lambda *a: False + } + + def __init__(self, pool): + osv.osv.__init__(self, pool) + self.loads = {} + self.doinit = True + self.unlink_mark = {} + + def _get_id(self,cr, uid, module, xml_id): + ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)]) + assert len(ids)==1, '%d reference(s) to %s. You should have only one !' % (len(ids),xml_id) + return ids[0] + + def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True): + if not xml_id: + return False + try: + id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id'] + self.loads[(module,xml_id)] = (model,id) + except: + id = False + return id + + def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False): + warning = True + if xml_id and ('.' in xml_id): + assert len(xml_id.split('.'))==2, '"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id' % (xml_id) + warning = False + module, xml_id = xml_id.split('.') + if (not xml_id) and (not self.doinit): + return False + action_id = False + if xml_id: + cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id)) + results = cr.fetchall() + for action_id2,res_id2 in results: + cr.execute('select id from '+self.pool.get(model)._table+' where id=%d', (res_id2,)) + result3 = cr.fetchone() + if not result3: + cr.execute('delete from ir_model_data where id=%d', (action_id2,)) + else: + res_id,action_id = res_id2,action_id2 + + if action_id and res_id: + self.pool.get(model).write(cr, uid, [res_id], values) + self.write(cr, uid, [action_id], {'date_update': time.strftime('%Y-%m-%d %H:%M:%S')}) + elif res_id: + self.pool.get(model).write(cr, uid, [res_id], values) + if xml_id: + self.create(cr, uid, {'name':xml_id, 'model':model, 'module':module, 'res_id':res_id, 'noupdate':noupdate}) + else: + if mode=='init' or (mode=='update' and xml_id): + res_id = self.pool.get(model).create(cr, uid, values) + if xml_id: + self.create(cr, uid, {'name':xml_id, 'model':model, 'module':module, 'res_id':res_id, 'noupdate':noupdate}) + if xml_id: + if warning: + assert (module,xml_id) not in self.loads, "id '%s' is already defined in module '%s' !" % (xml_id, module) + if res_id: + self.loads[(module,xml_id)] = (model, res_id) + return res_id + + def _unlink(self, cr, uid, model, ids, direct=False): + #self.pool.get(model).unlink(cr, uid, ids) + for id in ids: + self.unlink_mark[(model, id)]=False + cr.execute('delete from ir_model_data where res_id=%d and model=\'%s\'', (id,model)) + return True + + def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None): + obj = self.pool.get('ir.values') + if type(models[0])==type([]) or type(models[0])==type(()): + model,res_id = models[0] + else: + res_id=None + model = models[0] + + if res_id: + where = ' and res_id=%d' % (res_id,) + else: + where = ' and (res_id is null)' + + if key2: + where += ' and key2=\'%s\'' % (key2,) + else: + where += ' and (key2 is null)' + + cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name)) + res = cr.fetchone() + if not res: + res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta) + return True + + def _process_end(self, cr, uid, modules): + if not modules: + return True + module_str = ["'%s'" % m for m in modules] + cr.execute('select id,name,model,res_id,module from ir_model_data where module in ('+','.join(module_str)+') and not noupdate') + wkf_todo = [] + for (id, name, model, res_id,module) in cr.fetchall(): + if (module,name) not in self.loads: + self.unlink_mark[(model,res_id)] = id + if model=='workflow.activity': + cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%d)', (res_id,)) + wkf_todo.extend(cr.fetchall()) + cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%d where act_to=%d", (res_id,res_id)) + cr.execute("delete from wkf_transition where act_to=%d", (res_id,)) + + for model,id in wkf_todo: + wf_service = netsvc.LocalService("workflow") + wf_service.trg_write(uid, model, id, cr) + + cr.commit() + for (model,id) in self.unlink_mark.keys(): + if self.pool.get(model): + print 'Deleting %s@%s' % (id, model), + try: + self.pool.get(model).unlink(cr, uid, [id]) + if self.unlink_mark[(model,id)]: + self.unlink(cr, uid, [self.unlink_mark[(model,id)]]) + cr.commit() + print '... ok' + except: + print '... ko' + print '-'*60 + print 'WARNING: Could not delete id', id, 'of model', model + print '\tThere should be some relation that points to this resource' + print '\tYou should manually fix this and restart --update=module' + return True +ir_model_data() + |
