details: https://code.tryton.org/tryton/commit/b427806d9a6c
branch: 8.0
user: Cédric Krier <[email protected]>
date: Thu Sep 10 16:07:26 2026 +0200
description:
Forbid to set role to admin user
The links between admin user and groups are managed by XML record.
But the sync task may delete such link if a role is assigned to admin
because
the task is run as root which skip the XML check.
Closes #15086
(grafted from 0512f49869883b95b74387a292753e9e43375f35)
diffstat:
modules/user_role/res.py | 22 +++++++++++++++++++---
1 files changed, 19 insertions(+), 3 deletions(-)
diffs (59 lines):
diff -r 3f50225338e9 -r b427806d9a6c modules/user_role/res.py
--- a/modules/user_role/res.py Thu Sep 03 17:23:33 2026 +0200
+++ b/modules/user_role/res.py Thu Sep 10 16:07:26 2026 +0200
@@ -4,7 +4,7 @@
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool, PoolMeta
-from trytond.pyson import Bool, Eval, If
+from trytond.pyson import Bool, Eval, Id, If
class Role(ModelSQL, ModelView):
@@ -49,7 +49,11 @@
class User(metaclass=PoolMeta):
__name__ = 'res.user'
- roles = fields.One2Many('res.user.role', 'user', "Roles")
+ roles = fields.One2Many(
+ 'res.user.role', 'user', "Roles",
+ states={
+ 'invisible': Eval('id', -1) == Id('res', 'user_admin'),
+ })
@classmethod
def __setup__(cls):
@@ -69,12 +73,19 @@
@classmethod
def sync_roles(cls, users=None, date=None, clear=False):
+ pool = Pool()
+ ModelData = pool.get('ir.model.data')
+
+ admin_id = ModelData.get_id('res', 'user_admin')
+
if date is None:
date = dt.datetime.now()
if users is None:
users = cls.search([])
to_write = []
for user in users:
+ if user.id == admin_id:
+ continue
if not user.roles and not clear:
continue
new = {g.id for r in user.roles for g in r.role.groups
@@ -93,7 +104,12 @@
class UserRole(ModelSQL, ModelView):
__name__ = 'res.user.role'
user = fields.Many2One(
- 'res.user', "User", ondelete='CASCADE', required=True)
+ 'res.user', "User", ondelete='CASCADE', required=True,
+ domain=[
+ If(Eval('user', -1) == Id('res', 'user_admin'),
+ ('id', '=', -1),
+ ()),
+ ])
role = fields.Many2One(
'res.role', "Role", ondelete='CASCADE', required=True)
from_date = fields.DateTime(