Check button states when testing access

Closes #14591
This commit is contained in:
Cédric Krier committed 2026-02-09 18:13:34 +01:00
1 parent cd51fce0b7
commit 7d040c8cb9
5 files changed
+51 -1

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Check button states when testing access
* Remove the files of Binary fields from the Filestore
* Add delete and delete_many to Filestore
* Deprecate ``grouped_slice`` without size
+3
View File
@@ -282,6 +282,9 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.message" id="msg_access_button_error">
<field name="text">Calling button "%(button)s on "%(model)s" is not allowed.</field>
</record>
<record model="ir.message" id="msg_button_state_record">
<field name="text">You can not call "%(button)s" on "%(record)s" of "%(model)s".</field>
</record>
<record model="ir.message" id="msg_view_invalid_xml">
<field name="text">Invalid XML for view "%(name)s".</field>
+12 -1
View File
@@ -19,6 +19,7 @@ from . import fields
from .fields import on_change_result
from .fields.field import _set_value
from .model import Model
from .modelstorage import _pyson_encoder, _record_eval_pyson
__all__ = ['ModelView']
@@ -764,10 +765,20 @@ class ModelView(Model):
raise AccessButtonError(
gettext('ir.msg_access_button_error',
button=func.__name__,
model=cls.__name__))
**cls.__names__()))
else:
ModelAccess.check(cls.__name__, 'write')
states = cls._buttons.get(func.__name__, {})
for state_name in {'invisible', 'readonly'} & states.keys():
state = _pyson_encoder.encode(states[state_name])
for record in records:
if _record_eval_pyson(record, state, encoded=True):
raise AccessButtonError(
gettext('ir.msg_button_state_record',
button=func.__name__,
**cls.__names__(record=record)))
if (transaction.user != 0) and check_access:
button_rules = Button.get_rules(
cls.__name__, func.__name__)
+16
View File
@@ -68,6 +68,12 @@ class ModelViewButton(ModelView):
super().__setup__()
cls._buttons = {
'test': {},
'test_invisible': {
'invisible': Eval('value', 0) == 42,
},
'test_readonly': {
'readonly': Eval('value', 0) == 42,
},
}
@classmethod
@@ -79,6 +85,16 @@ class ModelViewButton(ModelView):
def test_non_decorated(cls, records):
pass
@classmethod
@ModelView.button
def test_invisible(cls, records):
pass
@classmethod
@ModelView.button
def test_readonly(cls, records):
pass
class ModelViewButtonDepends(ModelView):
__name__ = 'test.modelview.button_depends'
+19
View File
@@ -454,6 +454,25 @@ class ModelView(TestCase):
with self.assertRaises(AccessButtonError):
TestModel.test([test])
@with_transaction(context={'_check_access': True})
def test_button_access_state(self):
"Test Button Access with states"
pool = Pool()
Model = pool.get('test.modelview.button')
record = Model()
Model.test_invisible([record])
Model.test_readonly([record])
record = Model(value=42)
with self.assertRaises(AccessButtonError):
Model.test_invisible([record])
with self.assertRaises(AccessButtonError):
Model.test_readonly([record])
@with_transaction(context={'_check_access': True})
def test_button_no_rule(self):
"Test no Button Rule"