Add model field access

This commit is contained in:
Cédric Krier
2011-01-22 23:56:13 +01:00
parent 9fe833f916
commit 2b4098f1d2
11 changed files with 1076 additions and 27 deletions
+1
View File
@@ -1,3 +1,4 @@
* Add model field access
* Add loading attribute on fields
* Remove priority attribute on fields
* Model doesn't convert anymore ids for inherited methods
+141 -24
View File
@@ -235,38 +235,36 @@ class ModelAccess(ModelSQL, ModelView):
@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
'''
assert mode in ['read', 'write', 'create', 'delete'], \
'Invalid access mode for security'
model_obj = self.pool.get(model_name)
if hasattr(model_obj, 'table_query') \
and model_obj.table_query():
return False
if Transaction().user == 0:
return True
ir_model_obj = self.pool.get('ir.model')
user_group_obj = self.pool.get('res.user-res.group')
cursor = Transaction().cursor
cursor.execute('SELECT MAX(CASE WHEN a.perm_'+mode+' THEN 1 else 0 END) '
'FROM ir_model_access a '
'JOIN "' + ir_model_obj._table + '" m '
'ON (a.model = m.id) '
'JOIN "' + user_group_obj._table + '" gu '
'ON (gu.gid = a."group") '
'WHERE m.model = %s AND gu.uid = %s',
(model_name, Transaction().user,))
row = cursor.fetchall()
if row[0][0] is None:
cursor.execute('SELECT ' \
'MAX(CASE WHEN perm_' + mode + ' THEN 1 else 0 END) ' \
'FROM ir_model_access a ' \
'JOIN ir_model m ' \
'ON (a.model = m.id) ' \
'WHERE a."group" IS NULL AND m.model = %s', (model_name,))
row = cursor.fetchall()
if row[0][0] is None:
return True
if not row[0][0]:
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.gid = a."group") '
'WHERE m.model = %%s AND (gu.uid = %%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:
if raise_exception:
self.raise_user_error(mode, model_name)
else:
@@ -309,6 +307,125 @@ class ModelAccess(ModelSQL, ModelView):
ModelAccess()
class ModelFieldAccess(ModelSQL, ModelView):
"Model Field Access"
_name = 'ir.model.field.access'
_description = __doc__
_rec_name = 'field'
field = fields.Many2One('ir.model.field', 'Field', required=True,
ondelete='CASCADE')
group = fields.Many2One('res.group', 'Group', ondelete='CASCADE')
perm_read = fields.Boolean('Read Access')
perm_write = fields.Boolean('Write Access')
description = fields.Text('Description')
def __init__(self):
super(ModelFieldAccess, self).__init__()
self._sql_constraints += [
('field_group_uniq', 'UNIQUE("field", "group")',
'Only one record by field and group is allowed!'),
]
self._error_messages.update({
'read': 'You can not read the field! (%s.%s)',
'write': 'You can not write on the field! (%s.%s)',
})
def check_xml_record(self, ids, values):
return True
def default_perm_read(self):
return False
def default_perm_write(self):
return False
@Cache('ir_model_field_access.check')
def check(self, model_name, fields, mode='read', raise_exception=True,
access=False):
'''
Check access for fields on model_name.
:param model_name: the model name
:param fields: a list of fields
:param mode: 'read' or 'write'
:param raise_exception: raise an exception if the test failed
:param access: return a dictionary with access right instead of boolean
:return: a boolean
'''
assert mode in ('read', 'write'), 'Invalid access mode'
if Transaction().user == 0:
if access:
return dict((x, True) for x in fields)
return True
ir_model_obj = self.pool.get('ir.model')
ir_model_field_obj = self.pool.get('ir.model.field')
user_group_obj = self.pool.get('res.user-res.group')
cursor = Transaction().cursor
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.gid = a."group") '
'WHERE m.model = %%s AND (gu.uid = %%s OR a."group" IS NULL) '
'GROUP BY f.name'
% (mode, self._table, ir_model_field_obj._table,
ir_model_obj._table, user_group_obj._table),
(model_name, Transaction().user))
accesses = dict(cursor.fetchall())
if access:
return accesses
for field in fields:
if not accesses.get(field, True):
if raise_exception:
self.raise_user_error(mode, (model_name, field))
else:
return False
return True
def write(self, ids, vals):
res = super(ModelFieldAccess, self).write(ids, vals)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
pass
return res
def create(self, vals):
res = super(ModelFieldAccess, self).create(vals)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
pass
return res
def delete(self, ids):
res = super(ModelFieldAccess, self).delete(ids)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
pass
return res
ModelFieldAccess()
class ModelData(ModelSQL, ModelView):
"Model data"
_name = 'ir.model.data'
+57
View File
@@ -190,6 +190,63 @@ this repository contains the full copyright notices and license terms. -->
<menuitem parent="ir.menu_models"
action="act_model_access_form" id="menu_model_access_form"/>
<record model="ir.ui.view" id="model_field_access_view_tree">
<field name="model">ir.model.field.access</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<![CDATA[
<tree string="Field Access">
<field name="perm_read" select="2"/>
<field name="perm_write" select="2"/>
<field name="field" select="1"/>
<field name="group" select="1"/>
</tree>
]]>
</field>
</record>
<record model="ir.ui.view" id="model_field_access_view_form">
<field name="model">ir.model.field.access</field>
<field name="type">form</field>
<field name="arch" type="xml">
<![CDATA[
<form string="Field Access">
<label name="field"/>
<field name="field"/>
<label name="group"/>
<field name="group"/>
<newline/>
<label name="perm_read"/>
<field name="perm_read"/>
<label name="perm_write"/>
<field name="perm_write"/>
<separator name="description" colspan="4"/>
<field name="description" colspan="4"/>
</form>
]]>
</field>
</record>
<record model="ir.action.act_window" id="act_model_field_access_form">
<field name="name">Fields Access</field>
<field name="res_model">ir.model.field.access</field>
<field name="view_type">form</field>
</record>
<record model="ir.action.act_window.view"
id="act_model_field_access_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="model_field_access_view_tree"/>
<field name="act_window" ref="act_model_field_access_form"/>
</record>
<record model="ir.action.act_window.view"
id="act_model_field_access_form_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="model_field_access_view_form"/>
<field name="act_window" ref="act_model_field_access_form"/>
</record>
<menuitem parent="menu_model_access_form"
action="act_model_field_access_form" id="menu_model_field_access_form"/>
<record model="ir.action.report" id="report_model_graph">
<field name="name">Graph</field>
<field name="model">ir.model</field>
+15 -2
View File
@@ -90,13 +90,26 @@ class BrowseRecord(object):
% (name, self._model._name))
if col.loading == 'eager':
field_access_obj = self._model.pool.get('ir.model.field.access')
fread_accesses = {}
for inherit_name in self._model._inherits:
inherit_obj = self._model.pool.get(inherit_name)
fread_accesses.update(field_access_obj.check(inherit_name,
inherit_obj._columns.keys(), 'read', access=True))
fread_accesses.update(field_access_obj.check(self._model._name,
self._model._columns.keys(), 'read', access=True))
to_remove = set(x for x, y in fread_accesses.iteritems()
if not y and x != name)
ffields = dict((fname, field) for fname, (_, _, field)
in self._model._inherit_fields.iteritems()
if field.loading == 'eager'
and fname not in self._model._columns)
and fname not in self._model._columns
and fname not in to_remove)
ffields.update(dict((fname, field) for fname, field
in self._model._columns.iteritems()
if field.loading == 'eager'))
if field.loading == 'eager'
and fname not in to_remove))
else:
ffields = {name: col}
+5 -1
View File
@@ -619,6 +619,8 @@ class Model(object):
res = {}
translation_obj = self.pool.get('ir.translation')
model_access_obj = self.pool.get('ir.model.access')
field_access_obj = self.pool.get('ir.model.field.access')
for parent in self._inherits:
res.update(self.pool.get(parent).fields_get(fields_names))
write_access = model_access_obj.check(self._name, 'write',
@@ -648,6 +650,8 @@ class Model(object):
encoder = PYSONEncoder()
fwrite_accesses = field_access_obj.check(self._name, fields_names or
self._columns.keys(), 'write', access=True)
for field in (x for x in self._columns.keys()
if ((not fields_names) or x in fields_names)):
res[field] = {'type': self._columns[field]._type}
@@ -671,7 +675,7 @@ class Model(object):
if getattr(self._columns[field], arg, None) != None:
res[field][arg] = copy.copy(getattr(self._columns[field],
arg))
if not write_access:
if not write_access or not fwrite_accesses.get(field, True):
res[field]['readonly'] = True
if res[field].get('states') and \
'readonly' in res[field]['states']:
+10
View File
@@ -82,7 +82,11 @@ class ModelStorage(Model):
:return: the id of the created record
'''
model_access_obj = self.pool.get('ir.model.access')
model_field_access_obj = self.pool.get('ir.model.field.access')
model_access_obj.check(self._name, 'create')
model_field_access_obj.check(self._name,
[x for x in values if x in self._columns], 'write')
self.__clean_xxx2many_cache()
return False
@@ -113,8 +117,11 @@ class ModelStorage(Model):
and fields value as value. The list will not be in the same order.
'''
model_access_obj = self.pool.get('ir.model.access')
model_field_access_obj = self.pool.get('ir.model.field.access')
model_access_obj.check(self._name, 'read')
model_field_access_obj.check(self._name,
fields_names or self._columns.keys(), 'read')
if isinstance(ids, (int, long)):
return {}
return []
@@ -129,8 +136,11 @@ class ModelStorage(Model):
:return: True if succeed
'''
model_access_obj = self.pool.get('ir.model.access')
model_field_access_obj = self.pool.get('ir.model.field.access')
model_access_obj.check(self._name, 'write')
model_field_access_obj.check(self._name,
[x for x in values if x in self._columns], 'write')
if not self.check_xml_record(ids, values):
self.raise_user_error('write_xml_record',
error_description='xml_record_desc')
+36
View File
@@ -256,9 +256,45 @@ class ModelView(Model):
return value
def _view_look_dom_arch(self, tree, type):
field_access_obj = self.pool.get('ir.model.field.access')
fields_width = {}
tree_root = tree.getroottree().getroot()
# Find field without read access
fread_accesses = field_access_obj.check(self._name,
self._columns.keys(), 'read', access=True)
fields_to_remove = list(x for x, y in fread_accesses.iteritems()
if not y)
for name, field in self._columns.iteritems():
for field_to_remove in fields_to_remove:
if field_to_remove in field.depends:
fields_to_remove.append(name)
# Find field inherited without read access
for inherit_name in self._inherits:
inherit_obj = self.pool.get(inherit_name)
fread_accesses = field_access_obj.check(inherit_obj._name,
inherit_obj._columns.keys(), 'read', access=True)
fields_to_remove += list(x for x, y in fread_accesses.iteritems()
if not y and x not in self._columns.keys())
for name, field in inherit_obj._columns.iteritems():
for field_to_remove in fields_to_remove:
if field_to_remove in field.depends:
fields_to_remove.append(name)
# Remove field without read access
for field in fields_to_remove:
for element in tree.xpath(
'//field[@name="%s"] | //label[@name="%s"]'
% (field, field)):
if type == 'form':
element.tag = 'label'
element.attrib.clear()
elif type == 'tree':
parent = element.getparent()
parent.remove(element)
if type == 'tree':
viewtreewidth_obj = self.pool.get('ir.ui.view_tree_width')
viewtreewidth_ids = viewtreewidth_obj.search([
+1
View File
@@ -7,3 +7,4 @@ from mptt import *
from import_data import *
from export_data import *
from trigger import *
from access import *
+14
View File
@@ -0,0 +1,14 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, fields
class TestAccess(ModelSQL):
'Test Access'
_name = 'test.access'
_description = __doc__
field1 = fields.Char('Field 1')
field2 = fields.Char('Field 2')
TestAccess()
+794
View File
@@ -0,0 +1,794 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
install_module
from trytond.transaction import Transaction
class ModelAccessTestCase(unittest.TestCase):
'''
Test Model Access
'''
def setUp(self):
install_module('test')
self.model_access = POOL.get('ir.model.access')
self.test_access = POOL.get('test.access')
self.model = POOL.get('ir.model')
self.group = POOL.get('res.group')
def test0010perm_read(self):
'''
Test Read Access
'''
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
model_id, = self.model.search([('model', '=', 'test.access')])
test_id = self.test_access.create({})
# Without model access
self.test_access.read(test_id)
# With model access
# One access allowed for any group
model_access_wo_group_id = self.model_access.create({
'model': model_id,
'group': False,
'perm_read': True,
})
self.test_access.read(test_id)
# One access disallowed for any group
self.model_access.write(model_access_wo_group_id, {
'perm_read': False,
})
self.failUnlessRaises(Exception, self.test_access.read,
test_id)
# Two access rules with one group allowed
group_id = self.group.search([('users', '=', USER)])[0]
model_access_w_group_id = self.model_access.create({
'model': model_id,
'group': group_id,
'perm_read': True,
})
self.test_access.read(test_id)
# Two access rules with both allowed
self.model_access.write(model_access_wo_group_id, {
'perm_read': True,
})
self.test_access.read(test_id)
# Two access rules with any group allowed
self.model_access.write(model_access_w_group_id, {
'perm_read': False,
})
self.test_access.read(test_id)
# Two access rules with both disallowed
self.model_access.write(model_access_wo_group_id, {
'perm_read': False,
})
self.failUnlessRaises(Exception, self.test_access.read,
test_id)
# One access disallowed for one group
self.model_access.delete(model_access_wo_group_id)
self.failUnlessRaises(Exception, self.test_access.read,
test_id)
# One access allowed for one group
self.model_access.write(model_access_w_group_id, {
'perm_read': True,
})
self.test_access.read(test_id)
# One access allowed for one other group
group_id = self.group.create({'name': 'Test'})
self.model_access.write(model_access_w_group_id, {
'group': group_id,
})
self.test_access.read(test_id)
# One access disallowed for one other group
self.model_access.write(model_access_w_group_id, {
'perm_read': False,
})
self.test_access.read(test_id)
transaction.cursor.rollback()
def test0020perm_write(self):
'''
Test Write Access
'''
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
model_id, = self.model.search([('model', '=', 'test.access')])
test_id = self.test_access.create({})
# Without model access
self.test_access.write(test_id, {})
# With model access
# One access allowed for any group
model_access_wo_group_id = self.model_access.create({
'model': model_id,
'group': False,
'perm_write': True,
})
self.test_access.write(test_id, {})
# One access disallowed for any group
self.model_access.write(model_access_wo_group_id, {
'perm_write': False,
})
self.failUnlessRaises(Exception, self.test_access.write,
test_id, {})
# Two access rules with one group allowed
group_id = self.group.search([('users', '=', USER)])[0]
model_access_w_group_id = self.model_access.create({
'model': model_id,
'group': group_id,
'perm_write': True,
})
self.test_access.write(test_id, {})
# Two access rules with both allowed
self.model_access.write(model_access_wo_group_id, {
'perm_write': True,
})
self.test_access.write(test_id, {})
# Two access rules with any group allowed
self.model_access.write(model_access_w_group_id, {
'perm_write': False,
})
self.test_access.write(test_id, {})
# Two access rules with both disallowed
self.model_access.write(model_access_wo_group_id, {
'perm_write': False,
})
self.failUnlessRaises(Exception, self.test_access.write,
test_id, {})
# One access disallowed for one group
self.model_access.delete(model_access_wo_group_id)
self.failUnlessRaises(Exception, self.test_access.write,
test_id, {})
# One access allowed for one group
self.model_access.write(model_access_w_group_id, {
'perm_write': True,
})
self.test_access.write(test_id, {})
# One access allowed for one other group
group_id = self.group.create({'name': 'Test'})
self.model_access.write(model_access_w_group_id, {
'group': group_id,
})
self.test_access.write(test_id, {})
# One access disallowed for one other group
self.model_access.write(model_access_w_group_id, {
'perm_write': False,
})
self.test_access.write(test_id, {})
transaction.cursor.rollback()
def test0030perm_create(self):
'''
Test Create Access
'''
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
model_id, = self.model.search([('model', '=', 'test.access')])
# Without model access
test_id = self.test_access.create({})
# With model access
# One access allowed for any group
model_access_wo_group_id = self.model_access.create({
'model': model_id,
'group': False,
'perm_create': True,
})
self.test_access.create({})
# One access disallowed for any group
self.model_access.write(model_access_wo_group_id, {
'perm_create': False,
})
self.failUnlessRaises(Exception, self.test_access.create, {})
# Two access rules with one group allowed
group_id = self.group.search([('users', '=', USER)])[0]
model_access_w_group_id = self.model_access.create({
'model': model_id,
'group': group_id,
'perm_create': True,
})
self.test_access.create({})
# Two access rules with both allowed
self.model_access.write(model_access_wo_group_id, {
'perm_create': True,
})
self.test_access.create({})
# Two access rules with any group allowed
self.model_access.write(model_access_w_group_id, {
'perm_create': False,
})
self.test_access.create({})
# Two access rules with both disallowed
self.model_access.write(model_access_wo_group_id, {
'perm_create': False,
})
self.failUnlessRaises(Exception, self.test_access.create, {})
# One access disallowed for one group
self.model_access.delete(model_access_wo_group_id)
self.failUnlessRaises(Exception, self.test_access.create, {})
# One access allowed for one group
self.model_access.write(model_access_w_group_id, {
'perm_create': True,
})
self.test_access.create({})
# One access allowed for one other group
group_id = self.group.create({'name': 'Test'})
self.model_access.write(model_access_w_group_id, {
'group': group_id,
})
self.test_access.create({})
# One access disallowed for one other group
self.model_access.write(model_access_w_group_id, {
'perm_create': False,
})
self.test_access.create({})
transaction.cursor.rollback()
def test0040perm_delete(self):
'''
Test Delete Access
'''
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
model_id, = self.model.search([('model', '=', 'test.access')])
test_ids = [self.test_access.create({}) for x in range(11)]
# Without model access
test_id = self.test_access.delete(test_ids.pop())
# With model access
# One access allowed for any group
model_access_wo_group_id = self.model_access.create({
'model': model_id,
'group': False,
'perm_delete': True,
})
self.test_access.delete(test_ids.pop())
# One access disallowed for any group
self.model_access.write(model_access_wo_group_id, {
'perm_delete': False,
})
self.failUnlessRaises(Exception, self.test_access.delete,
test_ids.pop())
# Two access rules with one group allowed
group_id = self.group.search([('users', '=', USER)])[0]
model_access_w_group_id = self.model_access.create({
'model': model_id,
'group': group_id,
'perm_delete': True,
})
self.test_access.delete(test_ids.pop())
# Two access rules with both allowed
self.model_access.write(model_access_wo_group_id, {
'perm_delete': True,
})
self.test_access.delete(test_ids.pop())
# Two access rules with any group allowed
self.model_access.write(model_access_w_group_id, {
'perm_delete': False,
})
self.test_access.delete(test_ids.pop())
# Two access rules with both disallowed
self.model_access.write(model_access_wo_group_id, {
'perm_delete': False,
})
self.failUnlessRaises(Exception, self.test_access.delete,
test_ids.pop())
# One access disallowed for one group
self.model_access.delete(model_access_wo_group_id)
self.failUnlessRaises(Exception, self.test_access.delete,
test_ids.pop())
# One access allowed for one group
self.model_access.write(model_access_w_group_id, {
'perm_delete': True,
})
self.test_access.delete(test_ids.pop())
# One access allowed for one other group
group_id = self.group.create({'name': 'Test'})
self.model_access.write(model_access_w_group_id, {
'group': group_id,
})
self.test_access.delete(test_ids.pop())
# One access disallowed for one other group
self.model_access.write(model_access_w_group_id, {
'perm_delete': False,
})
self.test_access.delete(test_ids.pop())
transaction.cursor.rollback()
class ModelFieldAccessTestCase(unittest.TestCase):
'''
Test Model Field Access
'''
def setUp(self):
install_module('test')
self.field_access = POOL.get('ir.model.field.access')
self.test_access = POOL.get('test.access')
self.field = POOL.get('ir.model.field')
self.group = POOL.get('res.group')
def test0010perm_read(self):
'''
Test Read Access
'''
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
field1_id, = self.field.search([
('model.model', '=', 'test.access'),
('name', '=', 'field1'),
])
field2_id, = self.field.search([
('model.model', '=', 'test.access'),
('name', '=', 'field2'),
])
test_id = self.test_access.create({
'field1': 'ham',
'field2': 'spam',
})
# Without field access
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# With field access
# One access allowed for any group
field_access_wo_group_id = self.field_access.create({
'field': field1_id,
'group': False,
'perm_read': True,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# One access disallowed for any group
self.field_access.write(field_access_wo_group_id, {
'perm_read': False,
})
self.failUnlessRaises(Exception, self.test_access.read, test_id,
['field1'])
self.test_access.read(test_id, ['field2'])
self.failUnlessRaises(Exception, self.test_access.read, test_id)
test_access = self.test_access.browse(test_id)
self.failUnlessRaises(Exception, getattr, test_access, 'field1')
test_access.field2
transaction.cursor.cache.clear()
# Two access rules with one group allowed
group_id = self.group.search([('users', '=', USER)])[0]
field_access_w_group_id = self.field_access.create({
'field': field1_id,
'group': group_id,
'perm_read': True,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# Two access rules with both allowed
self.field_access.write(field_access_wo_group_id, {
'perm_read': True,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# Two access rules with any group allowed
self.field_access.write(field_access_w_group_id, {
'perm_read': False,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# Two access rules with both disallowed
self.field_access.write(field_access_wo_group_id, {
'perm_read': False,
})
self.failUnlessRaises(Exception, self.test_access.read, test_id,
['field1'])
self.test_access.read(test_id, ['field2'])
self.failUnlessRaises(Exception, self.test_access.read, test_id)
test_access = self.test_access.browse(test_id)
self.failUnlessRaises(Exception, getattr, test_access, 'field1')
test_access.field2
transaction.cursor.cache.clear()
# One access disallowed for one group
self.field_access.delete(field_access_wo_group_id)
self.failUnlessRaises(Exception, self.test_access.read, test_id,
['field1'])
self.test_access.read(test_id, ['field2'])
self.failUnlessRaises(Exception, self.test_access.read, test_id)
test_access = self.test_access.browse(test_id)
self.failUnlessRaises(Exception, getattr, test_access, 'field1')
test_access.field2
transaction.cursor.cache.clear()
# One access allowed for one group
self.field_access.write(field_access_w_group_id, {
'perm_read': True,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# One access allowed for one other group
group_id = self.group.create({'name': 'Test'})
self.field_access.write(field_access_w_group_id, {
'group': group_id,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# One access disallowed for one other group
self.field_access.write(field_access_w_group_id, {
'perm_read': False,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# Two access rules on both fields allowed
self.field_access.delete(field_access_w_group_id)
field_access1 = self.field_access.create({
'field': field1_id,
'group': False,
'perm_read': True,
})
field_access2 = self.field_access.create({
'field': field2_id,
'group': False,
'perm_read': True,
})
self.test_access.read(test_id, ['field1'])
self.test_access.read(test_id, ['field2'])
self.test_access.read(test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
test_access.field2
transaction.cursor.cache.clear()
# Two access rules on both fields one allowed and one disallowed
self.field_access.write(field_access2, {
'perm_read': False,
})
self.test_access.read(test_id, ['field1'])
self.failUnlessRaises(Exception, self.test_access.read, test_id,
['field2'])
self.failUnlessRaises(Exception, self.test_access.read, test_id)
test_access = self.test_access.browse(test_id)
test_access.field1
self.failUnlessRaises(Exception, getattr, test_access, 'field2')
transaction.cursor.cache.clear()
# Two access rules on both fields disallowed
self.field_access.write(field_access1, {
'perm_read': False,
})
self.failUnlessRaises(Exception, self.test_access.read, test_id,
['field1'])
self.failUnlessRaises(Exception, self.test_access.read, test_id,
['field2'])
self.failUnlessRaises(Exception, self.test_access.read, test_id)
test_access = self.test_access.browse(test_id)
self.failUnlessRaises(Exception, getattr, test_access, 'field1')
self.failUnlessRaises(Exception, getattr, test_access, 'field2')
transaction.cursor.cache.clear()
transaction.cursor.rollback()
def test0010perm_write(self):
'''
Test Write Access
'''
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
field1_id, = self.field.search([
('model.model', '=', 'test.access'),
('name', '=', 'field1'),
])
field2_id, = self.field.search([
('model.model', '=', 'test.access'),
('name', '=', 'field2'),
])
test_id = self.test_access.create({
'field1': 'ham',
'field2': 'spam',
})
# Without field access
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
# With field access
# One access allowed for any group
field_access_wo_group_id = self.field_access.create({
'field': field1_id,
'group': False,
'perm_write': True,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# One access disallowed for any group
self.field_access.write(field_access_wo_group_id, {
'perm_write': False,
})
self.test_access.write(test_id, {})
self.failUnlessRaises(Exception, self.test_access.write, test_id,
{'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.failUnlessRaises(Exception, self.test_access.write, test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules with one group allowed
group_id = self.group.search([('users', '=', USER)])[0]
field_access_w_group_id = self.field_access.create({
'field': field1_id,
'group': group_id,
'perm_write': True,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules with both allowed
self.field_access.write(field_access_wo_group_id, {
'perm_write': True,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules with any group allowed
self.field_access.write(field_access_w_group_id, {
'perm_write': False,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules with both disallowed
self.field_access.write(field_access_wo_group_id, {
'perm_write': False,
})
self.test_access.write(test_id, {})
self.failUnlessRaises(Exception, self.test_access.write, test_id,
{'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.failUnlessRaises(Exception, self.test_access.write, test_id, {
'field1': 'ham',
'field2': 'spam',
})
# One access disallowed for one group
self.field_access.delete(field_access_wo_group_id)
self.test_access.write(test_id, {})
self.failUnlessRaises(Exception, self.test_access.write, test_id,
{'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'ham'})
self.failUnlessRaises(Exception, self.test_access.write, test_id, {
'field1': 'ham',
'field2': 'spam',
})
# One access allowed for one group
self.field_access.write(field_access_w_group_id, {
'perm_write': True,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# One access allowed for one other group
group_id = self.group.create({'name': 'Test'})
self.field_access.write(field_access_w_group_id, {
'group': group_id,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# One access disallowed for one other group
self.field_access.write(field_access_w_group_id, {
'perm_write': False,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules on both fields allowed
self.field_access.delete(field_access_w_group_id)
field_access1 = self.field_access.create({
'field': field1_id,
'group': False,
'perm_write': True,
})
field_access2 = self.field_access.create({
'field': field2_id,
'group': False,
'perm_write': True,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.test_access.write(test_id, {'field2': 'spam'})
self.test_access.write(test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules on both fields one allowed and one disallowed
self.field_access.write(field_access2, {
'perm_write': False,
})
self.test_access.write(test_id, {})
self.test_access.write(test_id, {'field1': 'ham'})
self.failUnlessRaises(Exception, self.test_access.write, test_id,
{'field2': 'spam'})
self.failUnlessRaises(Exception, self.test_access.write, test_id, {
'field1': 'ham',
'field2': 'spam',
})
# Two access rules on both fields disallowed
self.field_access.write(field_access1, {
'perm_write': False,
})
self.test_access.write(test_id, {})
self.failUnlessRaises(Exception, self.test_access.write, test_id,
{'field1': 'ham'})
self.failUnlessRaises(Exception, self.test_access.write, test_id,
{'field2': 'spam'})
self.failUnlessRaises(Exception, self.test_access.write, test_id, {
'field1': 'ham',
'field2': 'spam',
})
transaction.cursor.rollback()
def suite():
suite_ = unittest.TestSuite()
suite_.addTests(unittest.TestLoader(
).loadTestsFromTestCase(ModelAccessTestCase))
suite_.addTests(unittest.TestLoader(
).loadTestsFromTestCase(ModelFieldAccessTestCase))
return suite_
if __name__ == '__main__':
suite = suite()
unittest.TextTestRunner(verbosity=2).run(suite)
+2
View File
@@ -194,6 +194,8 @@ def all_suite():
suite_.addTests(test_protocols_datatype.suite())
import trytond.tests.test_sequence as test_sequence
suite_.addTests(test_sequence.suite())
import trytond.tests.test_access as test_access
suite_.addTests(test_access.suite())
return suite_
def modules_suite():