* improve security on attachment: use the access right of the linked model
* improve cache managment bzr revid: christophe@tinyerp.com-20081016182816-o2h4swwye1urt3kw
This commit is contained in:
parent
05543e0af7
commit
f538cefe02
|
@ -29,8 +29,72 @@
|
|||
##############################################################################
|
||||
|
||||
from osv import fields,osv
|
||||
from osv.orm import except_orm
|
||||
import tools
|
||||
|
||||
class ir_attachment(osv.osv):
|
||||
|
||||
def check(self, cr, uid, ids, mode):
|
||||
if not ids:
|
||||
return
|
||||
ima = self.pool.get('ir.model.access')
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
objs = self.browse(cr, uid, ids) or []
|
||||
for o in objs:
|
||||
if o and o.res_model:
|
||||
ima.check(cr, uid, o.res_model, mode)
|
||||
|
||||
check = tools.cache()(check)
|
||||
|
||||
def search(self, cr, uid, *args, **kwargs):
|
||||
ids = super(ir_attachment, self).search(cr, uid, *args, **kwargs)
|
||||
if not ids:
|
||||
return []
|
||||
models = super(ir_attachment,self).read(cr, uid, ids, ['id', 'res_model'])
|
||||
cache = {}
|
||||
ima = self.pool.get('ir.model.access')
|
||||
for m in models:
|
||||
if m['res_model'] in cache:
|
||||
if not cache[m['res_model']]:
|
||||
ids.remove(m['id'])
|
||||
continue
|
||||
cache[m['res_model']] = ima.check(cr, uid, m['res_model'], 'read', raise_exception=False)
|
||||
return ids
|
||||
|
||||
def read(self, cr, uid, ids, *args, **kwargs):
|
||||
self.check(cr, uid, ids, 'read')
|
||||
return super(ir_attachment, self).read(cr, uid, ids, *args, **kwargs)
|
||||
|
||||
def write(self, cr, uid, ids, *args, **kwargs):
|
||||
self.check(cr, uid, ids, 'write')
|
||||
return super(ir_attachment, self).write(cr, uid, ids, *args, **kwargs)
|
||||
|
||||
def copy(self, cr, uid, id, *args, **kwargs):
|
||||
self.check(cr, uid, [id], 'write')
|
||||
return super(ir_attachment, self).copy(cr, uid, id, *args, **kwargs)
|
||||
|
||||
def unlink(self, cr, uid, ids, *args, **kwargs):
|
||||
self.check(cr, uid, ids, 'unlink')
|
||||
return super(ir_attachment, self).unlink(cr, uid, ids, *args, **kwargs)
|
||||
|
||||
def create(self, cr, uid, values, *args, **kwargs):
|
||||
if 'res_model' in values and values['res_model'] != '':
|
||||
self.pool.get('ir.model.access').check(cr, uid, values['res_model'], 'create')
|
||||
return super(ir_attachment, self).create(cr, uid, values, *args, **kwargs)
|
||||
|
||||
def clear_cache(self):
|
||||
self.check()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
r = super(ir_attachment, self).__init__(*args, **kwargs)
|
||||
self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache')
|
||||
return r
|
||||
|
||||
def __del__(self):
|
||||
self.pool.get('ir.model.access').unregister_cache_clearing_method(self._name, 'clear_cache')
|
||||
return super(ir_attachment, self).__del__()
|
||||
|
||||
_name = 'ir.attachment'
|
||||
_columns = {
|
||||
'name': fields.char('Attachment Name',size=64, required=True),
|
||||
|
|
|
@ -329,27 +329,42 @@ class ir_model_access(osv.osv):
|
|||
|
||||
check = tools.cache()(check)
|
||||
|
||||
__cache_clearing_methods = []
|
||||
|
||||
def register_cache_clearing_method(self, model, method):
|
||||
self.__cache_clearing_methods.append((model, method))
|
||||
|
||||
def unregister_cache_clearing_method(self, model, method):
|
||||
try:
|
||||
i = self.__cache_clearing_methods.index((model, method))
|
||||
del self.__cache_clearing_methods[i]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def call_cache_clearing_methods(self):
|
||||
for model, method in self.__cache_clearing_methods:
|
||||
getattr(self.pool.get(model), method)()
|
||||
|
||||
#
|
||||
# Check rights on actions
|
||||
#
|
||||
def write(self, cr, uid, *args, **argv):
|
||||
self.pool.get('ir.ui.menu').clear_cache()
|
||||
self.call_cache_clearing_methods()
|
||||
res = super(ir_model_access, self).write(cr, uid, *args, **argv)
|
||||
self.check()
|
||||
self.check() # clear the cache of check function
|
||||
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):
|
||||
self.pool.get('ir.ui.menu').clear_cache()
|
||||
self.call_cache_clearing_methods()
|
||||
res = super(ir_model_access, self).unlink(cr, uid, *args, **argv)
|
||||
self.check()
|
||||
return res
|
||||
def read(self, cr, uid, *args, **argv):
|
||||
res = super(ir_model_access, self).read(cr, uid, *args, **argv)
|
||||
self.check()
|
||||
return res
|
||||
|
||||
ir_model_access()
|
||||
|
||||
class ir_model_data(osv.osv):
|
||||
|
|
|
@ -61,7 +61,13 @@ class ir_ui_menu(osv.osv):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._cache = {}
|
||||
return super(ir_ui_menu, self).__init__(*args, **kwargs)
|
||||
r = super(ir_ui_menu, self).__init__(*args, **kwargs)
|
||||
self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache')
|
||||
return r
|
||||
|
||||
def __del__(self):
|
||||
self.pool.get('ir.model.access').unregister_cache_clearing_method(self._name, 'clear_cache')
|
||||
return super(ir_ui_menu, self).__del__()
|
||||
|
||||
def clear_cache(self):
|
||||
# radical but this doesn't frequently happen
|
||||
|
|
|
@ -589,6 +589,13 @@ class currency(float):
|
|||
# return str(display_value)
|
||||
|
||||
|
||||
def is_hashable(h):
|
||||
try:
|
||||
hash(h)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
#
|
||||
# Use it as a decorator of the function you plan to cache
|
||||
# Timeout: 0 = no timeout, otherwise in seconds
|
||||
|
@ -607,6 +614,11 @@ class cache(object):
|
|||
|
||||
# Update named arguments with positional argument values
|
||||
kwargs.update(dict(zip(arg_names, args)))
|
||||
for k in kwargs:
|
||||
if isinstance(kwargs[k], (list, dict, set)):
|
||||
kwargs[k] = tuple(kwargs[k])
|
||||
elif not is_hashable(kwargs[k]):
|
||||
kwargs[k] = repr(kwargs[k])
|
||||
kwargs = kwargs.items()
|
||||
kwargs.sort()
|
||||
|
||||
|
@ -621,7 +633,8 @@ class cache(object):
|
|||
return value
|
||||
|
||||
# Work out new value, cache it and return it
|
||||
# Should copy() this value to avoid futur modf of the cacle ?
|
||||
# FIXME Should copy() this value to avoid futur modifications of the cache ?
|
||||
# FIXME What about exceptions ?
|
||||
result = fn(self2,cr,**dict(kwargs))
|
||||
|
||||
self.cache[key] = (result, time.time())
|
||||
|
|
Loading…
Reference in New Issue