Filter Many2Many group fields on active = True
When the field is used in a domain adding this filter ensure that comparison with None will succeed when there are only inactive groups in the field. Closes #14369
This commit is contained in:
@@ -68,7 +68,10 @@ class Action(DeactivableMixin, ModelSQL, ModelView):
|
|||||||
'Keywords')
|
'Keywords')
|
||||||
icon = fields.Many2One('ir.ui.icon', 'Icon')
|
icon = fields.Many2One('ir.ui.icon', 'Icon')
|
||||||
groups = fields.Many2Many(
|
groups = fields.Many2Many(
|
||||||
'ir.action-res.group', 'action', 'group', "Groups")
|
'ir.action-res.group', 'action', 'group', "Groups",
|
||||||
|
filter=[
|
||||||
|
('active', '=', True),
|
||||||
|
])
|
||||||
_groups_cache = Cache('ir.action.get_groups', context=False)
|
_groups_cache = Cache('ir.action.get_groups', context=False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ class Export(_ClearCache, ModelSQL, ModelView):
|
|||||||
'res.user', "User", required=True, ondelete='CASCADE')
|
'res.user', "User", required=True, ondelete='CASCADE')
|
||||||
groups = fields.Many2Many(
|
groups = fields.Many2Many(
|
||||||
'ir.export-res.group', 'export', 'group', "Groups",
|
'ir.export-res.group', 'export', 'group', "Groups",
|
||||||
|
filter=[
|
||||||
|
('active', '=', True),
|
||||||
|
],
|
||||||
help="The user groups that can use the export.")
|
help="The user groups that can use the export.")
|
||||||
write_groups = fields.Many2Many(
|
write_groups = fields.Many2Many(
|
||||||
'ir.export-write-res.group', 'export', 'group',
|
'ir.export-write-res.group', 'export', 'group',
|
||||||
|
|||||||
@@ -975,7 +975,10 @@ class ModelButton(
|
|||||||
])
|
])
|
||||||
_reset_cache = Cache('ir.model.button.reset')
|
_reset_cache = Cache('ir.model.button.reset')
|
||||||
groups = fields.Many2Many(
|
groups = fields.Many2Many(
|
||||||
'ir.model.button-res.group', 'button', 'group', "Groups")
|
'ir.model.button-res.group', 'button', 'group', "Groups",
|
||||||
|
filter=[
|
||||||
|
('active', '=', True),
|
||||||
|
])
|
||||||
_groups_cache = Cache('ir.model.button.groups')
|
_groups_cache = Cache('ir.model.button.groups')
|
||||||
_view_attributes_cache = Cache(
|
_view_attributes_cache = Cache(
|
||||||
'ir.model.button.view_attributes', context=False)
|
'ir.model.button.view_attributes', context=False)
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class SequenceType(ModelSQL, ModelView):
|
|||||||
name = fields.Char('Sequence Name', required=True, translate=True)
|
name = fields.Char('Sequence Name', required=True, translate=True)
|
||||||
groups = fields.Many2Many(
|
groups = fields.Many2Many(
|
||||||
'ir.sequence.type-res.group', 'sequence_type', 'group', "Groups",
|
'ir.sequence.type-res.group', 'sequence_type', 'group', "Groups",
|
||||||
|
filter=[
|
||||||
|
('active', '=', True),
|
||||||
|
],
|
||||||
help="Groups allowed to edit the sequences of this type.")
|
help="Groups allowed to edit the sequences of this type.")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,10 @@ class UIMenu(
|
|||||||
('keyword', '=', 'tree_open'),
|
('keyword', '=', 'tree_open'),
|
||||||
])
|
])
|
||||||
groups = fields.Many2Many(
|
groups = fields.Many2Many(
|
||||||
'ir.ui.menu-res.group', 'menu', 'group', "Groups")
|
'ir.ui.menu-res.group', 'menu', 'group', "Groups",
|
||||||
|
filter=[
|
||||||
|
('active', '=', True),
|
||||||
|
])
|
||||||
favorite = fields.Function(fields.Boolean('Favorite'), 'get_favorite')
|
favorite = fields.Function(fields.Boolean('Favorite'), 'get_favorite')
|
||||||
favorites = fields.Many2Many(
|
favorites = fields.Many2Many(
|
||||||
'ir.ui.menu.favorite', 'menu', 'user', "Favorites")
|
'ir.ui.menu.favorite', 'menu', 'user', "Favorites")
|
||||||
|
|||||||
@@ -618,16 +618,22 @@ class User(avatar_mixin(100, 'login'), DeactivableMixin, ModelSQL, ModelView):
|
|||||||
'''
|
'''
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
UserGroup = pool.get('res.user-res.group')
|
UserGroup = pool.get('res.user-res.group')
|
||||||
|
Group = pool.get('res.group')
|
||||||
|
|
||||||
transaction = Transaction()
|
transaction = Transaction()
|
||||||
user = transaction.user
|
user = transaction.user
|
||||||
groups = cls._get_groups_cache.get(user)
|
groups = cls._get_groups_cache.get(user)
|
||||||
if groups is not None:
|
if groups is not None:
|
||||||
return groups
|
return groups
|
||||||
cursor = transaction.connection.cursor()
|
cursor = transaction.connection.cursor()
|
||||||
|
group = Group.__table__()
|
||||||
user_group = UserGroup.user_group_all_table()
|
user_group = UserGroup.user_group_all_table()
|
||||||
cursor.execute(*user_group.select(
|
cursor.execute(*user_group
|
||||||
|
.join(group, 'LEFT', user_group.group == group.id)
|
||||||
|
.select(
|
||||||
user_group.group,
|
user_group.group,
|
||||||
where=user_group.user == user,
|
where=((user_group.user == user)
|
||||||
|
& (group.active == Literal(True))),
|
||||||
order_by=[user_group.group.asc]))
|
order_by=[user_group.group.asc]))
|
||||||
groups = tuple(g for g, in cursor)
|
groups = tuple(g for g, in cursor)
|
||||||
cls._get_groups_cache.set(user, groups)
|
cls._get_groups_cache.set(user, groups)
|
||||||
|
|||||||
@@ -227,6 +227,56 @@ class _ModelAccessTestCase(TestCase):
|
|||||||
|
|
||||||
self._assert_raises(record)
|
self._assert_raises(record)
|
||||||
|
|
||||||
|
@with_transaction(context=_context)
|
||||||
|
def test_no_access_with_inactive_group(self):
|
||||||
|
"Test no access with inactive group"
|
||||||
|
pool = Pool()
|
||||||
|
Group = pool.get('res.group')
|
||||||
|
ModelAccess = pool.get('ir.model.access')
|
||||||
|
TestAccess = pool.get(self.model_name)
|
||||||
|
|
||||||
|
inactive_group, = Group.create([{'name': 'Test', 'active': False}])
|
||||||
|
record, = TestAccess.create([{}])
|
||||||
|
ModelAccess.create([{
|
||||||
|
'model': self.model_name,
|
||||||
|
'group': None,
|
||||||
|
self._perm: False,
|
||||||
|
}])
|
||||||
|
ModelAccess.create([{
|
||||||
|
'model': self.model_name,
|
||||||
|
'group': inactive_group.id,
|
||||||
|
self._perm: True,
|
||||||
|
}])
|
||||||
|
|
||||||
|
self._assert_raises(record)
|
||||||
|
|
||||||
|
@with_transaction(context=_context)
|
||||||
|
def test_no_access_with_member_inactive_group(self):
|
||||||
|
"Test no access when member of an inactive group"
|
||||||
|
pool = Pool()
|
||||||
|
Group = pool.get('res.group')
|
||||||
|
ModelAccess = pool.get('ir.model.access')
|
||||||
|
TestAccess = pool.get(self.model_name)
|
||||||
|
|
||||||
|
inactive_group, = Group.create([{
|
||||||
|
'name': 'Test',
|
||||||
|
'active': False,
|
||||||
|
'users': [('add', [Transaction().user])],
|
||||||
|
}])
|
||||||
|
record, = TestAccess.create([{}])
|
||||||
|
ModelAccess.create([{
|
||||||
|
'model': self.model_name,
|
||||||
|
'group': None,
|
||||||
|
self._perm: False,
|
||||||
|
}])
|
||||||
|
ModelAccess.create([{
|
||||||
|
'model': self.model_name,
|
||||||
|
'group': inactive_group.id,
|
||||||
|
self._perm: True,
|
||||||
|
}])
|
||||||
|
|
||||||
|
self._assert_raises(record)
|
||||||
|
|
||||||
@with_transaction(context=_context)
|
@with_transaction(context=_context)
|
||||||
def test_one_access_with_other_group_no_perm(self):
|
def test_one_access_with_other_group_no_perm(self):
|
||||||
"Test one access with other group no perm"
|
"Test one access with other group no perm"
|
||||||
@@ -656,6 +706,62 @@ class _ModelFieldAccessTestCase(TestCase):
|
|||||||
self._assert_raises1(record)
|
self._assert_raises1(record)
|
||||||
self._assert2(record)
|
self._assert2(record)
|
||||||
|
|
||||||
|
@with_transaction(context=_context)
|
||||||
|
def test_no_access_with_inactive_group(self):
|
||||||
|
"Test no access with inactive group"
|
||||||
|
pool = Pool()
|
||||||
|
Group = pool.get('res.group')
|
||||||
|
FieldAccess = pool.get('ir.model.field.access')
|
||||||
|
TestAccess = pool.get('test.access')
|
||||||
|
|
||||||
|
inactive_group, = Group.create([{'name': 'Test', 'active': False}])
|
||||||
|
record, = TestAccess.create([{}])
|
||||||
|
FieldAccess.create([{
|
||||||
|
'model': 'test.access',
|
||||||
|
'field': 'field1',
|
||||||
|
'group': None,
|
||||||
|
self._perm: False,
|
||||||
|
}])
|
||||||
|
FieldAccess.create([{
|
||||||
|
'model': 'test.access',
|
||||||
|
'field': 'field1',
|
||||||
|
'group': inactive_group.id,
|
||||||
|
self._perm: True,
|
||||||
|
}])
|
||||||
|
|
||||||
|
self._assert_raises1(record)
|
||||||
|
self._assert2(record)
|
||||||
|
|
||||||
|
@with_transaction(context=_context)
|
||||||
|
def test_no_access_with_member_inactive_group(self):
|
||||||
|
"Test no access when member of an inactive group"
|
||||||
|
pool = Pool()
|
||||||
|
Group = pool.get('res.group')
|
||||||
|
FieldAccess = pool.get('ir.model.field.access')
|
||||||
|
TestAccess = pool.get('test.access')
|
||||||
|
|
||||||
|
inactive_group, = Group.create([{
|
||||||
|
'name': 'Test',
|
||||||
|
'active': False,
|
||||||
|
'users': [('add', [Transaction().user])],
|
||||||
|
}])
|
||||||
|
record, = TestAccess.create([{}])
|
||||||
|
FieldAccess.create([{
|
||||||
|
'model': 'test.access',
|
||||||
|
'field': 'field1',
|
||||||
|
'group': None,
|
||||||
|
self._perm: False,
|
||||||
|
}])
|
||||||
|
FieldAccess.create([{
|
||||||
|
'model': 'test.access',
|
||||||
|
'field': 'field1',
|
||||||
|
'group': inactive_group.id,
|
||||||
|
self._perm: True,
|
||||||
|
}])
|
||||||
|
|
||||||
|
self._assert_raises1(record)
|
||||||
|
self._assert2(record)
|
||||||
|
|
||||||
@with_transaction(context=_context)
|
@with_transaction(context=_context)
|
||||||
def test_one_access_with_other_group_no_perm(self):
|
def test_one_access_with_other_group_no_perm(self):
|
||||||
"Test one access with other group no perm"
|
"Test one access with other group no perm"
|
||||||
|
|||||||
Reference in New Issue
Block a user