2006-12-07 13:41:40 +00:00
##############################################################################
#
# 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
2007-06-08 14:34:12 +00:00
from osv . orm import except_orm
2006-12-07 13:41:40 +00:00
import time
import tools
import pooler
2008-03-26 13:15:13 +00:00
def _get_fields_type ( self , cr , uid , context = None ) :
cr . execute ( ' select distinct ttype,ttype from ir_model_fields ' )
return cr . fetchall ( )
2006-12-07 13:41:40 +00:00
class ir_model ( osv . osv ) :
_name = ' ir.model '
_rec_name = ' model '
_columns = {
' name ' : fields . char ( ' Model name ' , size = 64 , translate = True ) ,
2008-04-16 20:00:51 +00:00
' model ' : fields . char ( ' Object name ' , size = 64 , required = True , search = 1 ) ,
2006-12-07 13:41:40 +00:00
' info ' : fields . text ( ' Information ' ) ,
' field_id ' : fields . one2many ( ' ir.model.fields ' , ' model_id ' , ' Fields ' , required = True ) ,
2008-04-16 20:00:51 +00:00
' state ' : fields . selection ( [ ( ' manual ' , ' Custom Field ' ) , ( ' base ' , ' Base Field ' ) ] , ' Manualy Created ' , readonly = 1 ) ,
2006-12-07 13:41:40 +00:00
}
_defaults = {
' name ' : lambda * a : ' No Name ' ,
2008-04-13 06:54:08 +00:00
' model ' : lambda * a : ' x_ ' ,
' state ' : lambda self , cr , uid , ctx = { } : ( ctx and ctx . get ( ' manual ' , False ) ) and ' manual ' or ' base ' ,
2006-12-07 13:41:40 +00:00
}
2008-04-13 06:54:08 +00:00
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 , ) )
return super ( ir_model , self ) . unlink ( cr , user , ids , context )
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 ' :
2008-04-16 20:00:51 +00:00
if not vals [ ' model ' ] . startswith ( ' x_ ' ) :
2008-04-13 06:54:08 +00:00
raise except_orm ( ' Error ' , " Custom models must have an object name that starts with ' x_ ' ! " )
2008-04-16 20:00:51 +00:00
pooler . restart_pool ( cr . dbname )
2008-04-13 06:54:08 +00:00
return res
2006-12-07 13:41:40 +00:00
2008-04-16 20:00:51 +00:00
def instanciate ( self , cr , user , model , context = { } ) :
class x_custom_model ( osv . osv ) :
pass
x_custom_model . _name = model
x_custom_model . _module = False
x_custom_model . _rec_name = ' id '
x_custom_model . createInstance ( self . pool , ' ' , cr )
2008-04-13 06:54:08 +00:00
ir_model ( )
2008-03-26 21:46:53 +00:00
2006-12-07 13:41:40 +00:00
class ir_model_fields ( osv . osv ) :
_name = ' ir.model.fields '
_columns = {
2008-03-26 13:15:13 +00:00
' name ' : fields . char ( ' Name ' , required = True , size = 64 , select = 1 ) ,
2006-12-07 13:41:40 +00:00
' model ' : fields . char ( ' Model Name ' , size = 64 , required = True ) ,
' relation ' : fields . char ( ' Model Relation ' , size = 64 ) ,
2007-12-31 13:31:38 +00:00
' model_id ' : fields . many2one ( ' ir.model ' , ' Model id ' , required = True , select = True , ondelete = ' cascade ' ) ,
2008-03-26 13:15:13 +00:00
' field_description ' : fields . char ( ' Field Label ' , required = True , size = 256 ) ,
2006-12-07 13:41:40 +00:00
' relate ' : fields . boolean ( ' Click and Relate ' ) ,
2008-03-26 13:15:13 +00:00
' ttype ' : fields . selection ( _get_fields_type , ' Field Type ' , size = 64 , required = True ) ,
' selection ' : fields . char ( ' Field Selection ' , size = 128 ) ,
' required ' : fields . boolean ( ' Required ' ) ,
' readonly ' : fields . boolean ( ' Readonly ' ) ,
2008-03-26 21:46:53 +00:00
' select_level ' : fields . selection ( [ ( ' 0 ' , ' Not Searchable ' ) , ( ' 1 ' , ' Always Searchable ' ) , ( ' 2 ' , ' Advanced Search ' ) ] , ' Searchable ' , required = True ) ,
2008-03-26 13:15:13 +00:00
' translate ' : fields . boolean ( ' Translate ' ) ,
' size ' : fields . integer ( ' Size ' ) ,
' state ' : fields . selection ( [ ( ' manual ' , ' Custom Field ' ) , ( ' base ' , ' Base Field ' ) ] , ' Manualy Created ' ) ,
2008-04-16 20:00:51 +00:00
' on_delete ' : fields . selection ( [ ( ' cascade ' , ' Cascade ' ) , ( ' set null ' , ' Set NULL ' ) ] , ' On delete ' , help = ' On delete property for many2one fields ' ) ,
2008-03-26 13:15:13 +00:00
' domain ' : fields . char ( ' Domain ' , size = 256 ) ,
2006-12-07 13:41:40 +00:00
' 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 = {
2007-03-29 07:20:07 +00:00
' relate ' : lambda * a : 0 ,
2006-12-07 13:41:40 +00:00
' view_load ' : lambda * a : 0 ,
2008-03-26 13:15:13 +00:00
' selection ' : lambda * a : " [] " ,
' domain ' : lambda * a : " [] " ,
' name ' : lambda * a : ' x_ ' ,
2008-03-26 21:46:53 +00:00
' state ' : lambda self , cr , uid , ctx = { } : ( ctx and ctx . get ( ' manual ' , False ) ) and ' manual ' or ' base ' ,
2008-04-16 20:00:51 +00:00
' on_delete ' : lambda * a : ' set null ' ,
2008-03-26 21:46:53 +00:00
' select_level ' : lambda * a : ' 0 ' ,
2008-03-26 13:15:13 +00:00
' size ' : lambda * a : 64 ,
2008-04-16 20:00:51 +00:00
' field_description ' : lambda * a : ' ' ,
2006-12-07 13:41:40 +00:00
}
_order = " id "
2008-03-26 13:15:13 +00:00
def unlink ( self , cr , user , ids , context = None ) :
2008-03-26 21:46:53 +00:00
for field in self . browse ( cr , user , ids , context ) :
2008-03-26 13:15:13 +00:00
if field . state < > ' manual ' :
raise except_orm ( ' Error ' , " You can not remove the field ' %s ' ! " % ( field . name , ) )
#
# MAY BE ADD A ALTER TABLE DROP ?
#
return super ( ir_model_fields , self ) . unlink ( cr , user , ids , context )
def create ( self , cr , user , vals , context = None ) :
if ' model_id ' in vals :
model_data = self . pool . get ( ' ir.model ' ) . read ( cr , user , vals [ ' model_id ' ] )
vals [ ' model ' ] = model_data [ ' model ' ]
if context and context . get ( ' manual ' , False ) :
vals [ ' state ' ] = ' manual '
res = super ( ir_model_fields , self ) . create ( cr , user , vals , context )
if vals . get ( ' state ' , ' base ' ) == ' manual ' :
if not vals [ ' name ' ] . startswith ( ' x_ ' ) :
raise except_orm ( ' Error ' , " Custom fields must have a name that starts with ' x_ ' ! " )
self . pool . get ( vals [ ' model ' ] ) . __init__ ( self . pool , cr )
self . pool . get ( vals [ ' model ' ] ) . _auto_init ( cr )
return res
2006-12-07 13:41:40 +00:00
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 ' ) ,
2006-12-26 12:40:58 +00:00
' perm_unlink ' : fields . boolean ( ' Delete Permission ' ) ,
2006-12-07 13:41:40 +00:00
}
2008-03-25 09:41:39 +00:00
def check_groups ( self , cr , uid , group ) :
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 ] ) )
r = cr . fetchall ( )
if not r :
res = False
else :
res = True
else :
res = False
#end if
return res
#end def
2007-06-01 10:57:34 +00:00
def check ( self , cr , uid , model_name , mode = ' read ' , raise_exception = True ) :
2006-12-26 12:40:58 +00:00
assert mode in [ ' read ' , ' write ' , ' create ' , ' unlink ' ] , ' Invalid access mode for security '
2007-09-26 05:17:28 +00:00
if uid == 1 :
2007-02-20 11:52:13 +00:00
return True
2007-09-26 05:17:28 +00:00
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 ( )
2007-05-24 11:23:49 +00:00
if r [ 0 ] [ 0 ] == None :
2007-09-26 05:17:28 +00:00
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) '
' WHERE a.group_id IS NULL AND m.model = %s ' , ( model_name , ) )
2007-05-24 11:23:49 +00:00
r = cr . fetchall ( )
2007-09-26 05:17:28 +00:00
if r [ 0 ] [ 0 ] == None :
return True
2006-12-26 12:28:50 +00:00
2007-05-24 11:23:49 +00:00
if not r [ 0 ] [ 0 ] :
2007-06-01 10:57:34 +00:00
if raise_exception :
2007-09-26 05:17:28 +00:00
if mode == ' read ' :
2008-01-29 15:05:48 +00:00
raise except_orm ( ' AccessError ' ,
' You can not read this document! ( %s ) ' % model_name )
2007-09-26 05:17:28 +00:00
elif mode == ' write ' :
2008-01-29 15:05:48 +00:00
raise except_orm ( ' AccessError ' ,
' You can not write in this document! ( %s ) ' % model_name )
2007-09-26 05:17:28 +00:00
elif mode == ' create ' :
2008-01-29 15:05:48 +00:00
raise except_orm ( ' AccessError ' ,
' You can not create this kind of document! ( %s ) ' % model_name )
2007-09-26 05:17:28 +00:00
elif mode == ' unlink ' :
2008-01-29 15:05:48 +00:00
raise except_orm ( ' AccessError ' ,
' You can not delete this document! ( %s ) ' % model_name )
raise except_orm ( ' AccessError ' ,
' You do not have access to this document! ( %s ) ' % model_name )
2007-06-01 10:57:34 +00:00
else :
return False
2007-05-24 11:23:49 +00:00
return True
2007-09-26 05:17:28 +00:00
2006-12-07 13:41:40 +00:00
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
}
2008-03-26 13:15:13 +00:00
def __init__ ( self , pool , cr ) :
osv . osv . __init__ ( self , pool , cr )
2006-12-07 13:41:40 +00:00
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 ]
2007-10-07 12:09:50 +00:00
_get_id = tools . cache ( ) ( _get_id )
2006-12-07 13:41:40 +00:00
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
2007-10-24 06:14:05 +00:00
model_obj = self . pool . get ( model )
2006-12-07 13:41:40 +00:00
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 :
2007-10-24 06:14:05 +00:00
model_obj . write ( cr , uid , [ res_id ] , values )
self . write ( cr , uid , [ action_id ] , {
' date_update ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
} )
2006-12-07 13:41:40 +00:00
elif res_id :
2007-10-24 06:14:05 +00:00
model_obj . write ( cr , uid , [ res_id ] , values )
2006-12-07 13:41:40 +00:00
if xml_id :
2007-10-24 06:14:05 +00:00
self . create ( cr , uid , {
' name ' : xml_id ,
' model ' : model ,
' module ' : module ,
' res_id ' : res_id ,
' noupdate ' : noupdate ,
} )
if model_obj . _inherits :
for table in model_obj . _inherits :
inherit_id = model_obj . browse ( cr , uid ,
res_id ) [ model_obj . _inherits [ table ] ]
self . create ( cr , uid , {
' name ' : xml_id + ' _ ' + table . replace ( ' . ' , ' _ ' ) ,
' model ' : table ,
' module ' : module ,
' res_id ' : inherit_id ,
' noupdate ' : noupdate ,
} )
2006-12-07 13:41:40 +00:00
else :
if mode == ' init ' or ( mode == ' update ' and xml_id ) :
2007-10-24 06:14:05 +00:00
res_id = model_obj . create ( cr , uid , values )
2006-12-07 13:41:40 +00:00
if xml_id :
2007-10-24 06:14:05 +00:00
self . create ( cr , uid , {
' name ' : xml_id ,
' model ' : model ,
' module ' : module ,
' res_id ' : res_id ,
' noupdate ' : noupdate
} )
if model_obj . _inherits :
for table in model_obj . _inherits :
inherit_id = model_obj . browse ( cr , uid ,
res_id ) [ model_obj . _inherits [ table ] ]
self . create ( cr , uid , {
' name ' : xml_id + ' _ ' + table . replace ( ' . ' , ' _ ' ) ,
' model ' : table ,
' module ' : module ,
' res_id ' : inherit_id ,
' noupdate ' : noupdate ,
} )
2006-12-07 13:41:40 +00:00
if xml_id :
if res_id :
2007-10-24 06:14:05 +00:00
self . loads [ ( module , xml_id ) ] = ( model , res_id )
2007-12-28 09:48:59 +00:00
if model_obj . _inherits :
for table in model_obj . _inherits :
inherit_field = model_obj . _inherits [ table ]
inherit_id = model_obj . read ( cr , uid , res_id ,
[ inherit_field ] ) [ inherit_field ]
self . loads [ ( module , xml_id + ' _ ' + \
table . replace ( ' . ' , ' _ ' ) ) ] = ( table , inherit_id )
2006-12-07 13:41:40 +00:00
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
2007-06-21 12:24:08 +00:00
def ir_set ( self , cr , uid , key , key2 , name , models , value , replace = True , isobject = False , meta = None , xml_id = False ) :
2006-12-07 13:41:40 +00:00
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 )
2007-06-21 12:24:08 +00:00
elif xml_id :
cr . execute ( ' UPDATE ir_values set value= %s WHERE model= %s and key= %s and name= %s ' + where , ( value , model , key , name ) )
2006-12-07 13:41:40 +00:00
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 ) :
2007-02-07 15:44:53 +00:00
logger = netsvc . Logger ( )
logger . notifyChannel ( ' init ' , netsvc . LOG_INFO , ' Deleting %s @ %s ' % ( id , model ) )
2006-12-07 13:41:40 +00:00
try :
self . pool . get ( model ) . unlink ( cr , uid , [ id ] )
if self . unlink_mark [ ( model , id ) ] :
self . unlink ( cr , uid , [ self . unlink_mark [ ( model , id ) ] ] )
2007-06-21 12:24:08 +00:00
cr . execute ( ' DELETE FROM ir_values WHERE value= %s ' , ( model + ' , ' + str ( id ) , ) )
2006-12-07 13:41:40 +00:00
cr . commit ( )
except :
2007-02-07 15:44:53 +00:00
logger . notifyChannel ( ' init ' , netsvc . LOG_ERROR , ' Could not delete id: %d of model %s \t There should be some relation that points to this resource \t You should manually fix this and restart --update=module ' % ( id , model ) )
2006-12-07 13:41:40 +00:00
return True
ir_model_data ( )