IR_RULES :
- new object to define versatile access rules. - provide cache to keep fast access. - associated with user or user group. The orm layer is modified to use them. This modification and pre-defined rules in xml data replace the most part of implicit magic around company_id. bzr revid: bch-73e82904c54c3ad4f5a7454a446af30572ae156d
This commit is contained in:
parent
570538f860
commit
605fde9553
|
@ -59,6 +59,8 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Groups">
|
||||
<field name="name" colspan="4" select="1"/>
|
||||
<field name="rule_ids" />
|
||||
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -116,6 +118,7 @@
|
|||
<newline/>
|
||||
<field name="groups_id"/>
|
||||
<field name="roles_id"/>
|
||||
<field name="rule_ids"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -39,3 +39,4 @@ import ir_values
|
|||
import ir_translation
|
||||
import ir_exports
|
||||
import workflow
|
||||
import ir_rule
|
||||
|
|
|
@ -792,6 +792,48 @@
|
|||
<field name="view_id" ref="ir_access_view_form"/>
|
||||
</record>
|
||||
<menuitem name="Administration/Security/Access Controls" action="ir_access_act" id="menu_ir_access_act"/>
|
||||
==========================================================
|
||||
Rules
|
||||
==========================================================
|
||||
|
||||
<record model="ir.ui.view" id="view_rule_form">
|
||||
<field name="name">Rule</field>
|
||||
<field name="model">ir.rule</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="rule">
|
||||
<field name="name"/>
|
||||
<field name="type" />
|
||||
<field name="model_id" />
|
||||
<field name="field_id" on_change="onchange_rule(model_id,field_id, operator, operand)"/>
|
||||
<field name="operator" on_change="onchange_rule(model_id,field_id, operator, operand)"/>
|
||||
<field name="operand" on_change="onchange_rule(model_id,field_id, operator, operand)"/>
|
||||
<field name="domain" colspan="4"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_rule_tree">
|
||||
<field name="name">Rule</field>
|
||||
<field name="model">ir.rule</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Rules">
|
||||
<field name="name"/>
|
||||
<field name="type"/>
|
||||
<field name="model_id"/>
|
||||
<field name="domain"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_rule">
|
||||
<field name="name">Rule</field>
|
||||
<field name="res_model">ir.rule</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_rule_form"/>
|
||||
</record>
|
||||
<menuitem name="Administration/Security/Rules" action="action_rule" id="menu_action_rule"/>
|
||||
|
||||
|
||||
</data>
|
||||
</terp>
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# 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 time
|
||||
import tools
|
||||
|
||||
class ir_rule(osv.osv):
|
||||
_name = 'ir.rule'
|
||||
|
||||
def _operand(self,cr,uid,context):
|
||||
def get(object, level=3, ending=[], ending_excl=[], recur=[], root_tech='', root=''):
|
||||
res= []
|
||||
fields = self.pool.get(object).fields_get(cr,uid)
|
||||
key = fields.keys()
|
||||
key.sort()
|
||||
for k in key:
|
||||
if (not ending or fields[k]['type'] in ending) and ((not ending_excl) or not (fields[k]['type'] in ending_excl)):
|
||||
res.append((root_tech+'.'+k,root+'/'+fields[k]['string']))
|
||||
|
||||
if fields[k]['type'] in recur:
|
||||
res.append((root_tech+'.'+k+'.id',root+'/'+fields[k]['string']))
|
||||
if (fields[k]['type'] in recur) and (level>0):
|
||||
res.extend(get(fields[k]['relation'], level-1, ending,
|
||||
ending_excl, recur, root_tech+'.'+k, root+'/'+fields[k]['string']))
|
||||
return res
|
||||
res = [("False", "False"),("user.id","User")]+get('res.users', level=1,ending_excl=['one2many','many2one','many2many','reference'],
|
||||
recur=['many2one'],root_tech='user',root='User')
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name',size=128, required=True, select=True),
|
||||
'type': fields.selection( (('add','Additive'),('sub','Subtractive')),'Type',required=True, select=True),
|
||||
'model_id': fields.many2one('ir.model', 'Model',select=True, required=True),
|
||||
'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=',model_id)]",select=True),
|
||||
'operator':fields.selection( (('=','='),('<>','<>'),('<=','<='),('>=','>=')),'Operator'),
|
||||
'operand':fields.selection(_operand,'Operand', size=64),
|
||||
'domain': fields.char('Domain', size=256, required=True)
|
||||
}
|
||||
|
||||
_defaults={
|
||||
'type': lambda *a : 'add'
|
||||
}
|
||||
|
||||
|
||||
def domain_get(self, cr, uid, model_name):
|
||||
# root user above constraint
|
||||
if uid == 1:
|
||||
return '', []
|
||||
|
||||
cr.execute("select r.id from ir_rule r join ir_model m on (r.model_id = m.id ) where m.model = %s and r.id in ( select rule_id from user_rule_rel where users_id = %d union select rule_id from group_rule_rel g join res_groups_users_rel u on (g.group_id = u.gid) where u.uid = %d )", (model_name,uid,uid))
|
||||
ids = map(lambda x:x[0], cr.fetchall())
|
||||
obj = self.pool.get(model_name)
|
||||
add = []
|
||||
add_str = []
|
||||
sub = []
|
||||
sub_str = []
|
||||
for rule in self.browse(cr, uid, ids):
|
||||
dom = eval(rule.domain, {'user': self.pool.get('res.users').browse(cr, uid, uid), 'time':time})
|
||||
d1,d2 = obj._where_calc(dom)
|
||||
if rule.type=='add':
|
||||
add_str += d1
|
||||
add +=d2
|
||||
else:
|
||||
sub_str += d1
|
||||
sub += d2
|
||||
add_str = ' or '.join(add_str)
|
||||
sub_str = ' and '.join(sub_str)
|
||||
|
||||
if not (add or sub):
|
||||
return '', []
|
||||
if add and sub:
|
||||
return '((%s) and (%s))' % (add_str, sub_str), add+sub
|
||||
if add:
|
||||
return '%s' % (add_str,), add
|
||||
if sub:
|
||||
return '%s' % (sub_str,),sub
|
||||
domain_get = tools.cache()(domain_get)
|
||||
|
||||
def onchange_rule(self, cr, uid, context, model_id, field_id, operator, operand):
|
||||
|
||||
if not ( field_id and operator and operand): return {}
|
||||
|
||||
field_names= self.pool.get('ir.model.fields').read(cr,uid,[field_id], ["name"])
|
||||
if not field_names : return {}
|
||||
|
||||
return {'value':{'domain': "[('%s', '%s', %s)]"%(field_names[0]['name'], operator, operand)}}
|
||||
|
||||
def write(self, cr, uid, *args, **argv):
|
||||
res = super(ir_rule, self).write(cr, uid, *args, **argv)
|
||||
# Restart the cache on the company_get method
|
||||
self.domain_get()
|
||||
return res
|
||||
|
||||
|
||||
ir_rule()
|
|
@ -33,7 +33,13 @@ class groups(osv.osv):
|
|||
_name = "res.groups"
|
||||
_columns = {
|
||||
'name': fields.char('Group Name', size=64, required=True),
|
||||
'rule_ids': fields.many2many('ir.rule', 'group_rule_rel', 'group_id', 'rule_id', 'Acces Rules'),
|
||||
}
|
||||
def write(self, cr, uid, *args, **argv):
|
||||
res = super(groups, self).write(cr, uid, *args, **argv)
|
||||
# Restart the cache on the company_get method
|
||||
self.pool.get('ir.rule').domain_get()
|
||||
return res
|
||||
groups()
|
||||
|
||||
|
||||
|
@ -86,6 +92,7 @@ class users(osv.osv):
|
|||
'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'),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'rule_ids': fields.many2many('ir.rule', 'user_rule_rel', 'users_id', 'rule_id', 'Acces Rules'),
|
||||
}
|
||||
_sql_constraints = [
|
||||
('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !')
|
||||
|
@ -101,8 +108,8 @@ class users(osv.osv):
|
|||
|
||||
def write(self, cr, uid, *args, **argv):
|
||||
res = super(users, self).write(cr, uid, *args, **argv)
|
||||
# Restart the cache on the company_get method
|
||||
self.company_get()
|
||||
self.pool.get('ir.rule').domain_get()
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids):
|
||||
|
@ -120,5 +127,7 @@ class users(osv.osv):
|
|||
login = self.read(cr, uid, [id], ['login'])[0]['login']
|
||||
default.update({'login': login+' (copy)'})
|
||||
return super(users, self).copy(cr, uid, id, default, context)
|
||||
|
||||
|
||||
users()
|
||||
|
||||
|
|
|
@ -285,8 +285,11 @@ class many2one(_column):
|
|||
for id in filter(None, res.values()):
|
||||
try:
|
||||
names[id] = dict(obj.name_get(cr, user, [id], context))[id]
|
||||
except except_orm:
|
||||
names[id] = "== Access denied =="
|
||||
except except_orm, e:
|
||||
if e.name == 'AccessError':
|
||||
names[id] = "== Access denied =="
|
||||
else :
|
||||
raise
|
||||
for r in res.keys():
|
||||
if res[r] and res[r] in names:
|
||||
res[r] = (res[r], names[res[r]])
|
||||
|
@ -397,11 +400,12 @@ class many2many(_column):
|
|||
ids_s = ','.join(map(str,ids))
|
||||
limit_str = self._limit is not None and ' limit %d' % self._limit or ''
|
||||
obj = obj.pool.get(self._obj)
|
||||
if 'company_id' in obj._columns:
|
||||
compids = tools.get_user_companies(cr, user)
|
||||
cr.execute('SELECT r.'+self._id2+', r.'+self._id1+' FROM '+self._rel+' AS r, '+obj._table+' AS o WHERE r.'+self._id1+' in ('+ids_s+') AND r.'+self._id2+' = o.id AND (o.company_id IN ('+','.join(map(str,compids))+') OR o.company_id IS NULL)'+limit_str+' OFFSET %d', (offset,))
|
||||
else:
|
||||
cr.execute('select '+self._id2+','+self._id1+' from '+self._rel+' where '+self._id1+' in ('+ids_s+')'+limit_str+' offset %d', (offset,))
|
||||
|
||||
d1, d2 = obj.pool.get('ir.rule').domain_get(cr, user, obj._name)
|
||||
if d1:
|
||||
d1 = ' and '+d1
|
||||
|
||||
cr.execute('SELECT '+self._rel+'.'+self._id2+','+self._rel+'.'+self._id1+' FROM '+self._rel+' , '+obj._table+' where '+self._rel+'.'+self._id1+' in ('+ids_s+') AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id ' +d1+limit_str+' offset %d', d2+[offset])
|
||||
for r in cr.fetchall():
|
||||
res[r[1]].append(r[0])
|
||||
return res
|
||||
|
@ -425,12 +429,13 @@ class many2many(_column):
|
|||
elif act[0]==5:
|
||||
cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%d', (id,))
|
||||
elif act[0]==6:
|
||||
if 'company_id' in obj._columns and not user == 1:
|
||||
compids = tools.get_user_companies(cr, user)
|
||||
cr.execute('delete from '+self._rel+' where '+self._id1+'=%d AND '+self._id2+' IN (SELECT r.'+self._id2+' FROM '+self._rel+' AS r, '+obj._table+' AS o WHERE r.'+self._id1+'=%d AND r.'+self._id2+' = o.id AND (o.company_id IN ('+','.join(map(str,compids))+') OR o.company_id IS NULL))', (id, id, ))
|
||||
else:
|
||||
cr.execute('delete from '+self._rel+' where '+self._id1+'=%d', (id, ))
|
||||
for act_nbr in act[2]:
|
||||
|
||||
d1, d2 = obj.pool.get('ir.rule').domain_get(cr, user, obj._name)
|
||||
if d1:
|
||||
d1 = ' and '+d1
|
||||
cr.execute('delete from '+self._rel+' where '+self._id1+'=%d AND '+self._id2+' IN (SELECT '+self._rel+'.'+self._id2+' FROM '+self._rel+', '+obj._table+' WHERE '+self._rel+'.'+self._id1+'=%d AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2 )
|
||||
|
||||
for act_nbr in act[2]: # XXX add clause ? [bch 20070518]
|
||||
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%d, %d)', (id, act_nbr))
|
||||
|
||||
#
|
||||
|
|
|
@ -174,12 +174,15 @@ class browse_record(object):
|
|||
if data[n]:
|
||||
obj = self._table.pool.get(f._obj)
|
||||
compids=False
|
||||
if 'company_id' in obj._columns and not self._uid == 1:
|
||||
compids = tools.get_user_companies(self._cr, self._uid)
|
||||
if compids:
|
||||
self._cr.execute('SELECT id FROM '+obj._table+' where id = %d AND (company_id in ('+','.join(map(str,compids))+') or company_id is null)', (data[n],))
|
||||
if not self._cr.fetchall():
|
||||
raise except_orm('BrowseError', 'Object %s (id:%d) is linked to the object %s (id:%d) which is not in your company' %(self._table._description, self._id, obj._description, data[n]))
|
||||
#
|
||||
# Removed for performance sake. (Bug may arise) [20070516]
|
||||
#
|
||||
# if 'company_id' in obj._columns :
|
||||
# compids = tools.get_user_companies(self._cr, self._uid)
|
||||
# if compids:
|
||||
# self._cr.execute('SELECT id FROM '+obj._table+' where id = %d AND (company_id in ('+','.join(map(str,compids))+') or company_id is null)', (data[n],))
|
||||
# if not self._cr.fetchall():
|
||||
# raise except_orm('BrowseError', 'Object %s (id:%d) is linked to the object %s (id:%d) which is not in your company' %(self._table._description, self._id, obj._description, data[n]))
|
||||
data[n] = browse_record(self._cr, self._uid, data[n], obj, self._cache, context=self._context, list_class=self._list_class)
|
||||
else:
|
||||
data[n] = browse_null()
|
||||
|
@ -479,7 +482,19 @@ class orm(object):
|
|||
self._sequence = self._table+'_id_seq'
|
||||
for k in self._defaults:
|
||||
assert (k in self._columns) or (k in self._inherit_fields), 'Default function defined in %s but field %s does not exist !' % (self._name, k,)
|
||||
if self._log_access:
|
||||
self._columns.update({
|
||||
'create_uid': fields.many2one('res.users','Creation user',required=True, readonly=True),
|
||||
'create_date': fields.datetime('Creation date',required=True, readonly=True),
|
||||
'write_uid': fields.many2one('res.users','Last modification by', readonly=True),
|
||||
'write_date': fields.datetime('Last modification date', readonly=True),
|
||||
})
|
||||
|
||||
#FIXME : does not work :
|
||||
# self._defaults.update({
|
||||
# 'create_uid': lambda self,cr,uid,context : uid,
|
||||
# 'create_date': lambda *a : time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
# })
|
||||
#
|
||||
# Update objects that uses this one to update their _inherits fields
|
||||
#
|
||||
|
@ -710,25 +725,20 @@ class orm(object):
|
|||
if fields==None:
|
||||
fields = self._columns.keys()
|
||||
|
||||
# if the object has a field named 'company_id', filter out all
|
||||
# records which do not concern the current company (the company
|
||||
# of the current user) or its "childs"
|
||||
company_clause='true'
|
||||
compids=False
|
||||
if 'company_id' in self._columns and not user == 1:
|
||||
compids = tools.get_user_companies(cr, user)
|
||||
if compids:
|
||||
company_clause = '(company_id in ('+','.join(map(str,compids))+') or company_id is null)'
|
||||
# construct a clause for the rules :
|
||||
d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
|
||||
|
||||
# all inherited fields + all non inherited fields for which the attribute whose name is in load is True
|
||||
fields_pre = filter(lambda x: x in self._columns and getattr(self._columns[x],'_classic_write'), fields) + self._inherits.values()
|
||||
|
||||
if len(fields_pre) or compids:
|
||||
cr.execute('select %s from %s where id in (%s) and %s order by %s' % (','.join(fields_pre + ['id']), self._table, ','.join([str(x) for x in ids]), company_clause, self._order))
|
||||
uniq_id = []
|
||||
[uniq_id.append(i) for i in ids if not uniq_id.count(i)]
|
||||
if not cr.rowcount == len(uniq_id) and compids:
|
||||
raise except_orm('ReadError', 'You try to read objects (%s) that is not in your company' % self._description)
|
||||
if len(fields_pre) :
|
||||
if d1:
|
||||
cr.execute('select %s from %s where id in (%s) and %s order by %s' % (','.join(fields_pre + ['id']), self._table, ','.join([str(x) for x in ids]), d1, self._order),d2)
|
||||
if not cr.rowcount == len({}.fromkeys(ids)):
|
||||
raise except_orm('AccessError', 'You try to bypass an access rule (Document type : %s).' % self._description)
|
||||
else:
|
||||
cr.execute('select %s from %s where id in (%s) order by %s' % (','.join(fields_pre + ['id']), self._table, ','.join([str(x) for x in ids]), self._order))
|
||||
|
||||
res = cr.dictfetchall()
|
||||
else:
|
||||
res = map(lambda x: {'id':x}, ids)
|
||||
|
@ -835,19 +845,26 @@ class orm(object):
|
|||
wf_service.trg_delete(uid, self._name, id, cr)
|
||||
str_d = string.join(('%d',)*len(ids),',')
|
||||
|
||||
cr.execute('select * from '+self._table+' where id in ('+str_d+')', ids)
|
||||
res = cr.dictfetchall()
|
||||
#cr.execute('select * from '+self._table+' where id in ('+str_d+')', ids)
|
||||
#res = cr.dictfetchall()
|
||||
#for key in self._inherits:
|
||||
# ids2 = [x[self._inherits[key]] for x in res]
|
||||
# self.pool.get(key).unlink(cr, uid, ids2)
|
||||
cr.execute('delete from inherit where (obj_type=%s and obj_id in ('+str_d+')) or (inst_type=%s and inst_id in ('+str_d+'))', (self._name,)+tuple(ids)+(self._name,)+tuple(ids))
|
||||
cr.execute('delete from '+self._table+' where id in ('+str_d+')', ids)
|
||||
|
||||
d1, d2 = self.pool.get('ir.rule').domain_get(cr, uid, self._name)
|
||||
if d1:
|
||||
d1 = ' and '+d1
|
||||
|
||||
cr.execute('delete from inherit where (obj_type=%s and obj_id in ('+str_d+'))'+d1+' or (inst_type=%s and inst_id in ('+str_d+')'+d1+')', [self._name]+ids+d2+[self._name]+ids+d2)
|
||||
cr.execute('delete from '+self._table+' where id in ('+str_d+')'+d1, ids+d2)
|
||||
return True
|
||||
|
||||
#
|
||||
# TODO: Validate
|
||||
#
|
||||
def write(self, cr, user, ids, vals, context={}):
|
||||
if not ids:
|
||||
return True
|
||||
delta= context.get('read_delta',False)
|
||||
if delta and self._log_access:
|
||||
cr.execute("select (now() - min(write_date)) <= '%s'::interval from %s where id in (%s)"% (delta,self._table,",".join(map(str, ids))) )
|
||||
|
@ -856,10 +873,9 @@ class orm(object):
|
|||
raise except_orm('ConcurrencyException', 'This record was modified in the meanwhile')
|
||||
|
||||
self.pool.get('ir.model.access').check(cr, user, self._name, 'write')
|
||||
|
||||
#for v in self._inherits.values():
|
||||
# assert v not in vals, (v, vals)
|
||||
if not ids:
|
||||
return
|
||||
ids_str = string.join(map(str, ids),',')
|
||||
upd0=[]
|
||||
upd1=[]
|
||||
|
@ -884,7 +900,11 @@ class orm(object):
|
|||
upd1.append(user)
|
||||
|
||||
if len(upd0):
|
||||
cr.execute('update '+self._table+' set '+string.join(upd0,',')+' where id in ('+ids_str+')', upd1)
|
||||
|
||||
d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
|
||||
if d1:
|
||||
d1 = ' and '+d1
|
||||
cr.execute('update '+self._table+' set '+string.join(upd0,',')+' where id in ('+ids_str+')'+d1, upd1+ d2)
|
||||
|
||||
if totranslate:
|
||||
for f in direct:
|
||||
|
@ -1391,11 +1411,11 @@ class orm(object):
|
|||
# if the object has a field named 'company_id', filter out all
|
||||
# records which do not concern the current company (the company
|
||||
# of the current user) or its "childs"
|
||||
if 'company_id' in self._columns and not user == 1:
|
||||
compids = tools.get_user_companies(cr, user)
|
||||
if compids:
|
||||
compids.append(False)
|
||||
args.append(('company_id','in',compids))
|
||||
# if 'company_id' in self._columns and not user == 1:
|
||||
# compids = tools.get_user_companies(cr, user)
|
||||
# if compids:
|
||||
# compids.append(False)
|
||||
# args.append(('company_id','in',compids))
|
||||
|
||||
i = 0
|
||||
tables=[self._table]
|
||||
|
@ -1497,6 +1517,7 @@ class orm(object):
|
|||
|
||||
# compute the where, order by, limit and offset clauses
|
||||
(qu1,qu2) = self._where_calc(args)
|
||||
|
||||
if len(qu1):
|
||||
qu1 = ' where '+string.join(qu1,' and ')
|
||||
else:
|
||||
|
@ -1505,7 +1526,13 @@ class orm(object):
|
|||
|
||||
limit_str = limit and ' limit %d' % limit or ''
|
||||
offset_str = offset and ' offset %d' % offset or ''
|
||||
|
||||
|
||||
|
||||
# construct a clause for the rules :
|
||||
d1, d2 = self.pool.get('ir.rule').domain_get(cr, user, self._name)
|
||||
if d1:
|
||||
qu1 = qu1 and qu1+' and '+d1 or ' where '+d1
|
||||
qu2 += d2
|
||||
# execute the "main" query to fetch the ids we were searching for
|
||||
cr.execute('select %s.id from ' % self._table + ','.join(tables) +qu1+' order by '+order_by+limit_str+offset_str, qu2)
|
||||
res = cr.fetchall()
|
||||
|
|
Loading…
Reference in New Issue