Allow client to manage model access
review346001
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Allow client to manage model access
|
||||
* Add time format validation
|
||||
* Remove ModelSQL.default_sequence
|
||||
|
||||
|
||||
+49
-25
@@ -49,6 +49,9 @@ class Model(ModelSQL, ModelView):
|
||||
'invalid_module': 'Module Name must be a python identifier!',
|
||||
})
|
||||
self._order.insert(0, ('model', 'ASC'))
|
||||
self._rpc.update({
|
||||
'list_models': False,
|
||||
})
|
||||
|
||||
def check_module(self, ids):
|
||||
'''
|
||||
@@ -59,6 +62,17 @@ class Model(ModelSQL, ModelView):
|
||||
return False
|
||||
return True
|
||||
|
||||
def list_models(self):
|
||||
'Return a list of all models names'
|
||||
with Transaction().set_user(0):
|
||||
model_ids = self.search([], order=[
|
||||
('module', 'ASC'), # Optimization assumption
|
||||
('model', 'ASC'),
|
||||
('id', 'ASC'),
|
||||
])
|
||||
models = self.browse(model_ids)
|
||||
return [m.model for m in models]
|
||||
|
||||
def create(self, vals):
|
||||
pool = Pool()
|
||||
property_obj = pool.get('ir.property')
|
||||
@@ -264,6 +278,9 @@ class ModelAccess(ModelSQL, ModelView):
|
||||
'create': 'You can not create this kind of document! (%s)',
|
||||
'delete': 'You can not delete this document! (%s)',
|
||||
})
|
||||
self._rpc.update({
|
||||
'get_access': False,
|
||||
})
|
||||
|
||||
def check_xml_record(self, ids, values):
|
||||
return True
|
||||
@@ -280,38 +297,45 @@ class ModelAccess(ModelSQL, ModelView):
|
||||
def default_perm_delete(self):
|
||||
return False
|
||||
|
||||
def get_access(self, models):
|
||||
'Return access for models'
|
||||
pool = Pool()
|
||||
ir_model_obj = pool.get('ir.model')
|
||||
user_group_obj = pool.get('res.user-res.group')
|
||||
cursor = Transaction().cursor
|
||||
default = {'read': True, 'write': True, 'create': True, 'delete': True}
|
||||
access = dict((m, default) for m in models)
|
||||
cursor.execute(('SELECT '
|
||||
'm.model, '
|
||||
'MAX(CASE WHEN a.perm_read THEN 1 ELSE 0 END), '
|
||||
'MAX(CASE WHEN a.perm_write THEN 1 ELSE 0 END), '
|
||||
'MAX(CASE WHEN a.perm_create THEN 1 ELSE 0 END), '
|
||||
'MAX(CASE WHEN a.perm_delete THEN 1 ELSE 0 END) '
|
||||
'FROM "%s" AS a '
|
||||
'JOIN "%s" AS m '
|
||||
'ON (a.model = m.id) '
|
||||
'LEFT JOIN "%s" AS gu '
|
||||
'ON (gu."group" = a."group") '
|
||||
'WHERE m.model IN (' + ','.join(('%%s',) * len(models)) + ') '
|
||||
'AND (gu."user" = %%s OR a."group" IS NULL) '
|
||||
'GROUP BY m.model')
|
||||
% (self._table, ir_model_obj._table, user_group_obj._table),
|
||||
list(models) + [Transaction().user])
|
||||
access.update(dict(
|
||||
(m, {'read': r, 'write': w, 'create': c, 'delete': d})
|
||||
for m, r, w, c, d in cursor.fetchall()))
|
||||
return access
|
||||
|
||||
@Cache('ir_model_access.check')
|
||||
def check(self, model_name, mode='read', raise_exception=True):
|
||||
'''
|
||||
Check access for model_name
|
||||
|
||||
:param model_name: the model name
|
||||
:param mode: 'read', 'write', 'create' or 'delete'
|
||||
:param raise_exception: raise an exception if the test failed
|
||||
|
||||
:return: a boolean
|
||||
'''
|
||||
'Check access for model_name and mode'
|
||||
assert mode in ['read', 'write', 'create', 'delete'], \
|
||||
'Invalid access mode for security'
|
||||
if Transaction().user == 0:
|
||||
return True
|
||||
|
||||
pool = Pool()
|
||||
ir_model_obj = pool.get('ir.model')
|
||||
user_group_obj = pool.get('res.user-res.group')
|
||||
cursor = Transaction().cursor
|
||||
|
||||
cursor.execute('SELECT MAX(CASE WHEN a.perm_%s THEN 1 ELSE 0 END) '
|
||||
'FROM "%s" AS a '
|
||||
'JOIN "%s" AS m '
|
||||
'ON (a.model = m.id) '
|
||||
'LEFT JOIN "%s" AS gu '
|
||||
'ON (gu."group" = a."group") '
|
||||
'WHERE m.model = %%s AND (gu."user" = %%s OR a."group" IS NULL)'
|
||||
% (mode, self._table, ir_model_obj._table, user_group_obj._table),
|
||||
(model_name, Transaction().user))
|
||||
access, = cursor.fetchone()
|
||||
if not access and access is not None:
|
||||
access = self.get_access([model_name])[model_name][mode]
|
||||
if not access:
|
||||
if raise_exception:
|
||||
self.raise_user_error(mode, model_name)
|
||||
else:
|
||||
|
||||
@@ -419,13 +419,10 @@ class Model(WarningErrorMixin, URLMixin):
|
||||
res = {}
|
||||
pool = Pool()
|
||||
translation_obj = pool.get('ir.translation')
|
||||
model_access_obj = pool.get('ir.model.access')
|
||||
field_access_obj = pool.get('ir.model.field.access')
|
||||
|
||||
for parent in self._inherits:
|
||||
res.update(pool.get(parent).fields_get(fields_names))
|
||||
write_access = model_access_obj.check(self._name, 'write',
|
||||
raise_exception=False)
|
||||
|
||||
#Add translation to cache
|
||||
language = Transaction().language
|
||||
@@ -480,7 +477,7 @@ class Model(WarningErrorMixin, URLMixin):
|
||||
if getattr(self._columns[field], arg, None) is not None:
|
||||
res[field][arg] = copy.copy(getattr(self._columns[field],
|
||||
arg))
|
||||
if not write_access or not fwrite_accesses.get(field, True):
|
||||
if not fwrite_accesses.get(field, True):
|
||||
res[field]['readonly'] = True
|
||||
if res[field].get('states') and \
|
||||
'readonly' in res[field]['states']:
|
||||
|
||||
Reference in New Issue
Block a user