[IMP] osv_memory: disabled regular ir_model_access access rights and switched to per-user access only. also did some cleanup

bzr revid: odo@openerp.com-20100624155602-noiat5i91uyeyy5t
This commit is contained in:
Olivier Dony 2010-06-24 17:56:02 +02:00
parent ef40f49056
commit 09297baccf
5 changed files with 83 additions and 41 deletions

View File

@ -33,8 +33,6 @@ import pooler
import netsvc
from osv import fields
import addons
import zipfile
import release
@ -303,7 +301,7 @@ def load_information_from_description_file(module):
:param module: The name of the module (sale, purchase, ...)
"""
for filename in ['__openerp__.py', '__terp__.py']:
description_file = addons.get_module_resource(module, filename)
description_file = get_module_resource(module, filename)
if os.path.isfile(description_file):
return eval(tools.file_open(description_file).read())
@ -823,7 +821,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
while True:
loop_guardrail += 1
if loop_guardrail > 100:
raise ProgrammingError()
raise ValueError('Possible recursive module tree detected, aborting.')
cr.execute("SELECT name from ir_module_module WHERE state IN %s" ,(tuple(STATES_TO_LOAD),))
module_list = [name for (name,) in cr.fetchall() if name not in graph]
@ -840,9 +838,19 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
has_updates = has_updates or r
if has_updates:
cr.execute("""select model,name from ir_model where id NOT IN (select model_id from ir_model_access)""")
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
for (model, name) in cr.fetchall():
logger.notifyChannel('init', netsvc.LOG_WARNING, 'object %s (%s) has no access rules!' % (model, name))
model_obj = pool.get(model)
if not isinstance(model_obj, osv.osv.osv_memory):
logger.notifyChannel('init', netsvc.LOG_WARNING, 'object %s (%s) has no access rules!' % (model, name))
# Temporary warning while we remove access rights on osv_memory objects, as they have
# been replaced by owner-only access rights
cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""")
for (model, name) in cr.fetchall():
model_obj = pool.get(model)
if isinstance(model_obj, osv.osv.osv_memory):
logger.notifyChannel('init', netsvc.LOG_WARNING, 'In-memory object %s (%s) should not have explicit access rules!' % (model, name))
cr.execute("SELECT model from ir_model")
for (model,) in cr.fetchall():

View File

@ -814,6 +814,7 @@
<page string="Object">
<field name="name" select="1"/>
<field name="model" select="1"/>
<field name="osv_memory" select="1"/>
<separator colspan="4" string="Fields"/>
<field colspan="4" context="{'manual':True}" name="field_id" nolabel="1">
<tree string="Fields Description">

View File

@ -44,6 +44,25 @@ class ir_model(osv.osv):
_name = 'ir.model'
_description = "Objects"
_rec_name = 'name'
def _is_osv_memory(self, cr, uid, ids, field_name, arg, context=None):
models = self.browse(cr, uid, ids, context=context)
res = dict.fromkeys(ids)
for model in models:
res[model.id] = isinstance(self.pool.get(model.model), osv.osv_memory)
return res
def _search_osv_memory(self, cr, uid, model, name, domain, context=None):
if not domain:
return []
field, operator, value = domain[0]
if operator not in ['=', '!=']:
raise osv.except_osv('Invalid search criterions','The osv_memory field can only be compared with = and != operator.')
value = bool(value) if operator == '=' else not bool(value)
all_model_ids = self.search(cr, uid, [], context=context)
is_osv_mem = self._is_osv_memory(cr, uid, all_model_ids, 'osv_memory', arg=None, context=context)
return [('id', 'in', [id for id in is_osv_mem if bool(is_osv_mem[id]) == value])]
_columns = {
'name': fields.char('Object Name', size=64, translate=True, required=True),
'model': fields.char('Object', size=64, required=True, select=1),
@ -51,6 +70,9 @@ class ir_model(osv.osv):
'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
'state': fields.selection([('manual','Custom Object'),('base','Base Object')],'Manually Created',readonly=True),
'access_ids': fields.one2many('ir.model.access', 'model_id', 'Access'),
'osv_memory': fields.function(_is_osv_memory, method=True, string='In-memory model', type='boolean',
fnct_search=_search_osv_memory,
help="Indicates whether this object model lives in memory only, i.e. is not persisted (osv.osv_memory)")
}
_defaults = {
'model': lambda *a: 'x_',
@ -81,7 +103,7 @@ class ir_model(osv.osv):
def unlink(self, cr, user, ids, context=None):
for model in self.browse(cr, user, ids, context):
if model.state <> 'manual':
if model.state != 'manual':
raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(model.name,))
res = super(ir_model, self).unlink(cr, user, ids, context)
pooler.restart_pool(cr.dbname)
@ -300,7 +322,7 @@ 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', 'Object', required=True),
'model_id': fields.many2one('ir.model', 'Object', required=True, domain=[('osv_memory','=', False)]),
'group_id': fields.many2one('res.groups', 'Group', ondelete='cascade'),
'perm_read': fields.boolean('Read Access'),
'perm_write': fields.boolean('Write Access'),

View File

@ -76,6 +76,9 @@ class expression(object):
self.__main_table = None # 'root' table. set by parse()
self.__DUMMY_LEAF = (1, '=', 1) # a dummy leaf that must not be parsed or sql generated
@property
def exp(self):
return self.__exp[:]
def parse(self, cr, uid, table, context):
""" transform the leafs of the expression """

View File

@ -1754,6 +1754,10 @@ class orm_memory(orm_template):
self.check_id = 0
cr.execute('delete from wkf_instance where res_type=%s', (self._name,))
def _check_access(self, uid, object_id, mode):
if uid != 1 and self.datas[object_id]['internal.create_uid'] != uid:
raise except_orm(_('AccessError'), '%s access is only allowed on your own records for osv_memory objects' % mode.capitalize())
def vaccum(self, cr, uid):
self.check_id += 1
if self.check_id % self._check_time:
@ -1774,7 +1778,6 @@ class orm_memory(orm_template):
def read(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'):
if not context:
context = {}
self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context)
if not fields_to_read:
fields_to_read = self._columns.keys()
result = []
@ -1785,8 +1788,10 @@ class orm_memory(orm_template):
for id in ids:
r = {'id': id}
for f in fields_to_read:
if id in self.datas:
r[f] = self.datas[id].get(f, False)
record = self.datas.get(id)
if record:
self._check_access(user, id, 'read')
r[f] = record.get(f, False)
if r[f] and isinstance(self._columns[f], fields.binary) and context.get('bin_size', False):
r[f] = len(r[f])
result.append(r)
@ -1804,7 +1809,6 @@ class orm_memory(orm_template):
def write(self, cr, user, ids, vals, context=None):
if not ids:
return True
self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context)
vals2 = {}
upd_todo = []
for field in vals:
@ -1812,18 +1816,18 @@ class orm_memory(orm_template):
vals2[field] = vals[field]
else:
upd_todo.append(field)
for id_new in ids:
self.datas[id_new].update(vals2)
self.datas[id_new]['internal.date_access'] = time.time()
for object_id in ids:
self._check_access(user, object_id, mode='write')
self.datas[object_id].update(vals2)
self.datas[object_id]['internal.date_access'] = time.time()
for field in upd_todo:
self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
self._validate(cr, user, [id_new], context)
self._columns[field].set_memory(cr, self, object_id, field, vals[field], user, context)
self._validate(cr, user, [object_id], context)
wf_service = netsvc.LocalService("workflow")
wf_service.trg_write(user, self._name, id_new, cr)
return id_new
wf_service.trg_write(user, self._name, object_id, cr)
return object_id
def create(self, cr, user, vals, context=None):
self.pool.get('ir.model.access').check(cr, user, self._name, 'create', context=context)
self.vaccum(cr, user)
self.next_id += 1
id_new = self.next_id
@ -1842,6 +1846,7 @@ class orm_memory(orm_template):
upd_todo.append(field)
self.datas[id_new] = vals2
self.datas[id_new]['internal.date_access'] = time.time()
self.datas[id_new]['internal.create_uid'] = user
for field in upd_todo:
self._columns[field].set_memory(cr, self, id_new, field, vals[field], user, context)
@ -1936,13 +1941,19 @@ class orm_memory(orm_template):
import expression
e = expression.expression(args)
e.parse(cr, user, self, context)
res=e.__dict__['_expression__exp']
res = e.exp
return res or []
def search(self, cr, user, args, offset=0, limit=None, order=None,
context=None, count=False):
if not context:
context = {}
# implicit filter on current user
if not args:
args = []
args.insert(0, ('internal.create_uid', '=', user))
result = self._where_calc(cr, user, args, context=context)
if result==[]:
return self.datas.keys()
@ -1954,25 +1965,20 @@ class orm_memory(orm_template):
if result:
for id, data in self.datas.items():
counter=counter+1
data['id'] = id
if limit and (counter >int(limit)):
data['id'] = id
if limit and (counter > int(limit)):
break
f = True
for arg in result:
if arg[1] =='=':
val =eval('data[arg[0]]'+'==' +' arg[2]', locals())
elif arg[1] in ['<','>','in','not in','<=','>=','<>']:
val =eval('data[arg[0]]'+arg[1] +' arg[2]', locals())
elif arg[1] in ['ilike']:
if str(data[arg[0]]).find(str(arg[2]))!=-1:
val= True
else:
val=False
if arg[1] == '=':
val = eval('data[arg[0]]'+'==' +' arg[2]', locals())
elif arg[1] in ['<','>','in','not in','<=','>=','<>']:
val = eval('data[arg[0]]'+arg[1] +' arg[2]', locals())
elif arg[1] in ['ilike']:
val = (str(data[arg[0]]).find(str(arg[2]))!=-1)
f = f and val
if f and val:
f = True
else:
f = False
if f:
res.append(id)
if count:
@ -1980,20 +1986,22 @@ class orm_memory(orm_template):
return res or []
def unlink(self, cr, uid, ids, context=None):
self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink', context=context)
for id in ids:
if id in self.datas:
del self.datas[id]
self._check_access(uid, id, 'unlink')
self.datas.pop(id, None)
if len(ids):
cr.execute('delete from wkf_instance where res_type=%s and res_id IN %s', (self._name, tuple(ids)))
return True
def perm_read(self, cr, user, ids, context=None, details=True):
result = []
credentials = self.pool.get('res.users').name_get(cr, user, [user])[0]
create_date = time.strftime('%Y-%m-%d %H:%M:%S')
for id in ids:
self._check_access(user, id, 'read')
result.append({
'create_uid': (user, 'Root'),
'create_date': time.strftime('%Y-%m-%d %H:%M:%S'),
'create_uid': credentials,
'create_date': create_date,
'write_uid': False,
'write_date': False,
'id': id