Include context information in access error

We include the date/time when the access error may be due to history and
user's groups when it depends on it.

Closes #12670
This commit is contained in:
Cédric Krier
2024-01-29 13:18:30 +01:00
parent ed0b38db47
commit 4e75c63e51
5 changed files with 59 additions and 9 deletions
+1
View File
@@ -1,3 +1,4 @@
* Include context information in access error
* Remove trytond-worker max tasks per child option for Python <= 3.10
* Do not copy readonly relational fields
* Support list of single value in sortable_values tools
+6
View File
@@ -224,6 +224,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="text">You are not allowed to delete records "%(ids)s" of "%(model)s" because of at lease one of those rules:
%(rules)s</field>
</record>
<record model="ir.message" id="msg_context_datetime">
<field name="text">At date/time: %(datetime)s</field>
</record>
<record model="ir.message" id="msg_context_groups">
<field name="text">Within groups: %(groups)s</field>
</record>
<record model="ir.message" id="msg_dict_schema_invalid_domain">
<field name="text">Invalid domain in schema "%(schema)s".</field>
</record>
+19 -4
View File
@@ -630,11 +630,18 @@ class ModelAccess(DeactivableMixin, ModelSQL, ModelView):
or (raise_exception and not transaction.check_access)):
return True
User = pool.get('res.user')
Group = pool.get('res.group')
access = cls.get_access([model_name])[model_name][mode]
if not access and access is not None:
if raise_exception:
raise AccessError(gettext(
'ir.msg_access_rule_error', **Model.__names__()))
groups = Group.browse(User.get_groups())
raise AccessError(
gettext('ir.msg_access_rule_error', **Model.__names__()),
gettext(
'ir.msg_context_groups',
groups=', '.join(g.rec_name for g in groups)))
else:
return False
return True
@@ -821,6 +828,9 @@ class ModelFieldAccess(DeactivableMixin, ModelSQL, ModelView):
return dict((x, True) for x in fields)
return True
User = pool.get('res.user')
Group = pool.get('res.group')
accesses = dict((f, a[mode])
for f, a in cls.get_access([model_name])[model_name].items())
if access:
@@ -828,9 +838,14 @@ class ModelFieldAccess(DeactivableMixin, ModelSQL, ModelView):
for field in fields:
if not accesses.get(field, True):
if raise_exception:
groups = Group.browse(User.get_groups())
raise AccessError(
gettext('ir.msg_access_rule_field_error',
**Model.__names__(field)))
gettext(
'ir.msg_access_rule_field_error',
**Model.__names__(field)),
gettext(
'ir.msg_context_groups',
groups=', '.join(g.rec_name for g in groups)))
else:
return False
return True
+18 -1
View File
@@ -1549,8 +1549,14 @@ class ModelSQL(ModelStorage):
@classmethod
def __check_domain_rule(cls, ids, mode):
pool = Pool()
Lang = pool.get('ir.lang')
Rule = pool.get('ir.rule')
Model = pool.get('ir.model')
try:
User = pool.get('res.user')
Group = pool.get('res.group')
except KeyError:
User = Group = None
table = cls.__table__()
transaction = Transaction()
in_max = transaction.database.IN_MAX
@@ -1628,7 +1634,18 @@ class ModelSQL(ModelStorage):
else:
msg = gettext(
f'ir.msg_{mode}_error', ids=ids, model=model)
raise AccessError(msg)
ctx_msg = []
lang = Lang.get()
if cls._history and transaction.context.get('_datetime'):
ctx_msg.append(gettext('ir.msg_context_datetime',
datetime=lang.strftime(
transaction.context['_datetime'])))
if domain and User and Group:
groups = Group.browse(User.get_groups())
ctx_msg.append(gettext('ir.msg_context_groups',
groups=', '.join(g.rec_name for g in groups)))
raise AccessError(msg, '\n'.join(ctx_msg))
@classmethod
def __search_query(cls, domain, count, query, order):
+15 -4
View File
@@ -251,6 +251,7 @@ class Wizard(URLMixin, PoolBase):
ModelAccess = pool.get('ir.model.access')
ActionWizard = pool.get('ir.action.wizard')
User = pool.get('res.user')
Group = pool.get('res.group')
context = Transaction().context
if Transaction().user == 0:
@@ -265,18 +266,28 @@ class Wizard(URLMixin, PoolBase):
models = ActionWizard.get_models(
cls.__name__, action_id=context.get('action_id'))
if model and models and model not in models:
raise AccessError(gettext(
groups = Group.browse(User.get_groups())
raise AccessError(
gettext(
'ir.msg_access_wizard_model_error',
wizard=cls.__name__,
model=model))
model=model),
gettext(
'ir.msg_context_groups',
groups=', '.join(g.rec_name for g in groups)))
groups = set(User.get_groups())
wizard_groups = ActionWizard.get_groups(cls.__name__,
action_id=context.get('action_id'))
if wizard_groups:
if not groups & wizard_groups:
raise AccessError(gettext(
groups = Group.browse(User.get_groups())
raise AccessError(
gettext(
'ir.msg_access_wizard_error',
name=cls.__name__))
name=cls.__name__),
gettext(
'ir.msg_context_groups',
groups=', '.join(g.rec_name for g in groups)))
elif model and model != 'ir.ui.menu':
if (not callable(getattr(Model, 'table_query', None))
or Model.write.__func__ != ModelSQL.write.__func__):