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
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 ' ) ,
2006-12-26 12:40:58 +00:00
' perm_unlink ' : fields . boolean ( ' Delete Permission ' ) ,
2006-12-07 13:41:40 +00:00
}
def check ( self , cr , uid , model_name , mode = ' read ' ) :
2006-12-26 12:40:58 +00:00
assert mode in [ ' read ' , ' write ' , ' create ' , ' unlink ' ] , ' Invalid access mode for security '
2006-12-26 12:28:50 +00:00
2006-12-07 13:41:40 +00:00
# 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 , ) )
2006-12-26 12:28:50 +00:00
2006-12-07 13:41:40 +00:00
# if no rule is found, grant the access
if not cr . rowcount :
return True
2006-12-26 12:28:50 +00:00
# if group None, ok for this user
ids = filter ( lambda x : x [ 1 ] , cr . fetchall ( ) )
for i in ids :
if not i :
return True
2006-12-07 13:41:40 +00:00
# compute the list of groups which have the right we are looking for
2006-12-26 12:28:50 +00:00
ids = map ( lambda x : str ( x [ 0 ] ) , ids )
2006-12-07 13:41:40 +00:00
if not ids :
raise osv . except_osv ( ' Access denied ! ' , ' You can not %s this resource ! ' % mode )
ids_str = ' , ' . join ( ids )
2006-12-26 12:28:50 +00:00
2006-12-07 13:41:40 +00:00
# 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 :
2007-02-07 15:44:53 +00:00
if model == ' ir.ui.menu ' and not xml_id :
2006-12-07 13:41:40 +00:00
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 ) :
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 ) ] ] )
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 ( )