From cf0636e0954f975b66bf092a4ecb08cc8500081e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 28 Nov 2012 22:42:51 +0100 Subject: [PATCH] Add ModelFieldAccess.get_access review598002 --- trytond/ir/model.py | 76 +++++++++++++++++++++++------------- trytond/model/model.py | 15 +++---- trytond/tests/test_access.py | 6 +++ 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/trytond/ir/model.py b/trytond/ir/model.py index 74800261c9..893de624da 100644 --- a/trytond/ir/model.py +++ b/trytond/ir/model.py @@ -434,6 +434,53 @@ class ModelFieldAccess(ModelSQL, ModelView): def default_perm_delete(): return True + @classmethod + def get_access(cls, models): + 'Return fields access for models' + pool = Pool() + Model = pool.get('ir.model') + ModelField = pool.get('ir.model.field') + UserGroup = pool.get('res.user-res.group') + cursor = Transaction().cursor + user = Transaction().user + + accesses = {} + for model in models: + maccesses = cls._get_access_cache.get((user, model)) + if maccesses is None: + break + accesses[model] = maccesses + else: + return accesses + + default = {} + accesses = dict((m, default) for m in models) + cursor.execute(('SELECT ' + 'm.model, ' + 'f.name, ' + '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 f ' + 'ON (a.field = f.id) ' + 'JOIN "%s" AS m ' + 'ON (f.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, f.name') + % (cls._table, ModelField._table, + Model._table, UserGroup._table), + list(models) + [Transaction().user]) + for m, f, r, w, c, d in cursor.fetchall(): + accesses[m][f] = {'read': r, 'write': w, 'create': c, 'delete': d} + for model, maccesses in accesses.iteritems(): + cls._get_access_cache.set((user, model), maccesses) + return accesses + @classmethod def check(cls, model_name, fields, mode='read', raise_exception=True, access=False): @@ -447,33 +494,8 @@ class ModelFieldAccess(ModelSQL, ModelView): return dict((x, True) for x in fields) return True - pool = Pool() - Model = pool.get('ir.model') - ModelField = pool.get('ir.model.field') - UserGroup = pool.get('res.user-res.group') - - cursor = Transaction().cursor - key = (model_name, mode, access, Transaction().user) - accesses = cls._get_access_cache.get(key) - - if accesses is None: - cursor.execute('SELECT f.name, ' - 'MAX(CASE WHEN a.perm_%s THEN 1 ELSE 0 END) ' - 'FROM "%s" AS a ' - 'JOIN "%s" AS f ' - 'ON (a.field = f.id) ' - 'JOIN "%s" AS m ' - 'ON (f.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) ' - 'GROUP BY f.name' - % (mode, cls._table, ModelField._table, - Model._table, UserGroup._table), (model_name, - Transaction().user)) - accesses = dict(cursor.fetchall()) - cls._get_access_cache.set(key, accesses) + accesses = dict((f, a[mode]) + for f, a in cls.get_access([model_name])[model_name].iteritems()) if access: return accesses for field in fields: diff --git a/trytond/model/model.py b/trytond/model/model.py index 2859604a60..cff8dabcc7 100644 --- a/trytond/model/model.py +++ b/trytond/model/model.py @@ -451,12 +451,7 @@ class Model(WarningErrorMixin, URLMixin): encoder = PYSONEncoder() - fwrite_accesses = FieldAccess.check(cls.__name__, fields_names or - cls._fields.keys(), 'write', access=True) - fcreate_accesses = FieldAccess.check(cls.__name__, fields_names or - cls._fields.keys(), 'create', access=True) - fdelete_accesses = FieldAccess.check(cls.__name__, fields_names or - cls._fields.keys(), 'delete', access=True) + accesses = FieldAccess.get_access([cls.__name__])[cls.__name__] for field in (x for x in cls._fields.keys() if ((not fields_names) or x in fields_names)): res[field] = { @@ -484,7 +479,7 @@ class Model(WarningErrorMixin, URLMixin): if getattr(cls._fields[field], arg, None) is not None: res[field][arg] = copy.copy(getattr(cls._fields[field], arg)) - if not fwrite_accesses.get(field, True): + if not accesses.get(field, {}).get('read', True): res[field]['readonly'] = True if res[field].get('states') and \ 'readonly' in res[field]['states']: @@ -554,8 +549,10 @@ class Model(WarningErrorMixin, URLMixin): res[field]['relation'] = relation res[field]['domain'] = copy.copy(cls._fields[field].domain) res[field]['context'] = copy.copy(cls._fields[field].context) - res[field]['create'] = fcreate_accesses.get(field, True) - res[field]['delete'] = fdelete_accesses.get(field, True) + res[field]['create'] = accesses.get(field, {}).get('create', + True) + res[field]['delete'] = accesses.get(field, {}).get('delete', + True) if res[field]['type'] == 'one2many' \ and hasattr(cls._fields[field], 'field'): res[field]['relation_field'] = copy.copy( diff --git a/trytond/tests/test_access.py b/trytond/tests/test_access.py index 447e6e3daa..c4906bc80f 100644 --- a/trytond/tests/test_access.py +++ b/trytond/tests/test_access.py @@ -101,6 +101,7 @@ class ModelAccessTestCase(unittest.TestCase): self.test_access.read([test.id]) transaction.cursor.rollback() + self.model_access._get_access_cache.clear() def test0020perm_write(self): ''' @@ -182,6 +183,7 @@ class ModelAccessTestCase(unittest.TestCase): self.test_access.write([test], {}) transaction.cursor.rollback() + self.model_access._get_access_cache.clear() def test0030perm_create(self): ''' @@ -262,6 +264,7 @@ class ModelAccessTestCase(unittest.TestCase): self.test_access.create({}) transaction.cursor.rollback() + self.model_access._get_access_cache.clear() def test0040perm_delete(self): ''' @@ -347,6 +350,7 @@ class ModelAccessTestCase(unittest.TestCase): self.test_access.delete([tests.pop()]) transaction.cursor.rollback() + self.model_access._get_access_cache.clear() class ModelFieldAccessTestCase(unittest.TestCase): @@ -571,6 +575,7 @@ class ModelFieldAccessTestCase(unittest.TestCase): test = self.test_access(test.id) transaction.cursor.rollback() + self.field_access._get_access_cache.clear() def test0010perm_write(self): ''' @@ -778,6 +783,7 @@ class ModelFieldAccessTestCase(unittest.TestCase): }) transaction.cursor.rollback() + self.field_access._get_access_cache.clear() def suite():