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:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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__):
|
||||
|
||||
Reference in New Issue
Block a user