details:   https://code.tryton.org/tryton/commit/fed8901dbb27
branch:    default
user:      Adrià Tarroja Caubet <[email protected]>
date:      Tue Sep 22 18:32:04 2026 +0200
description:
        Allow trytond-admin to manage any user

        Closes #13630
diffstat:

 trytond/CHANGELOG              |   1 +
 trytond/trytond/admin.py       |  58 ++++++++++++++++++++++-------------------
 trytond/trytond/commandline.py |  20 ++++++++++----
 3 files changed, 46 insertions(+), 33 deletions(-)

diffs (152 lines):

diff -r 16aae4ad4d69 -r fed8901dbb27 trytond/CHANGELOG
--- a/trytond/CHANGELOG Tue Sep 22 17:49:00 2026 +0200
+++ b/trytond/CHANGELOG Tue Sep 22 18:32:04 2026 +0200
@@ -1,3 +1,4 @@
+* Allow trytond-admin to manage any user
 * Add bulk_create, bulk_delete, bulk_save and bulk_func to ModelStorage
 * Add editable state on field
 * Enforce readonly on field when checking access
diff -r 16aae4ad4d69 -r fed8901dbb27 trytond/trytond/admin.py
--- a/trytond/trytond/admin.py  Tue Sep 22 17:49:00 2026 +0200
+++ b/trytond/trytond/admin.py  Tue Sep 22 18:32:04 2026 +0200
@@ -13,7 +13,7 @@
 from trytond.sendmail import send_test_email
 from trytond.tools import file_open, find_path
 from trytond.tools.email_ import EmailNotValidError, validate_email
-from trytond.transaction import Transaction, TransactionError
+from trytond.transaction import Transaction, TransactionError, inactive_records
 
 __all__ = ['run']
 logger = logging.getLogger(__name__)
@@ -76,14 +76,14 @@
                         })
 
     for db_name in options.database_names:
-        if options.admin_login:
-            admin_login = options.admin_login
+        login = options.login
+        administrator = options.administrator or init[db_name]
         if options.email is not None:
             email = options.email
         elif init[db_name]:
             while True:
                 email = input(
-                    f'email for "{admin_login}" of "{db_name}"'
+                    f'email for "{login}" of "{db_name}"'
                     ' (empty for none): ')
                 if email:
                     try:
@@ -111,17 +111,17 @@
             if not password and not options.reset_password:
                 while True:
                     password = getpass(
-                        f'password for "{admin_login}" of "{db_name}": ')
+                        f'password for "{login}" of "{db_name}": ')
                     password2 = getpass(
-                        f'password confirmation for "{admin_login}": ')
+                        f'password confirmation for "{login}": ')
                     if password != password2:
                         sys.stderr.write(
-                            f'password confirmation for "{admin_login}" '
-                            f'doesn\'t match "{admin_login}" password.\n')
+                            f'password confirmation for "{login}" '
+                            f'doesn\'t match "{login}" password.\n')
                         continue
                     if not password:
                         sys.stderr.write(
-                            f'password for "{admin_login}" is required.\n')
+                            f'password for "{login}" is required.\n')
                         continue
                     break
 
@@ -139,28 +139,32 @@
                         configuration.language = main_lang
 
                     if (init[db_name]
+                            or options.administrator is not None
+                            or options.email is not None
                             or options.password
                             or options.reset_password):
-                        try:
-                            admin, = User.search([
-                                    ('id', '!=', 0),
-                                    ('login', '=', admin_login),
-                                    ('administrator', '=', True),
-                                    ])
-                        except ValueError:
-                            admin = User()
-                            admin.login = admin_login
-                            admin.administrator = True
-                        else:
-                            if not admin.administrator:
-                                admin.administrator = True
+                        with inactive_records():
+                            try:
+                                user, = User.search([
+                                        ('id', '!=', 0),
+                                        ('login', '=', login),
+                                        ])
+                            except ValueError:
+                                user = User(
+                                    login=login,
+                                    administrator=administrator,
+                                    active=True)
+                        if user.active != options.active:
+                            user.active = options.active
+                        if user.administrator != administrator:
+                            user.administrator = administrator
                         if email is not None:
-                            admin.email = email
-                        if not options.reset_password:
-                            admin.password = password
-                        admin.save()
+                            user.email = email
+                        if password:
+                            user.password = password
+                        user.save()
                         if options.reset_password:
-                            User.reset_password([admin])
+                            User.reset_password([user])
                     if options.hostname is not None:
                         configuration.hostname = options.hostname or None
                     if options.export_translations:
diff -r 16aae4ad4d69 -r fed8901dbb27 trytond/trytond/commandline.py
--- a/trytond/trytond/commandline.py    Tue Sep 22 17:49:00 2026 +0200
+++ b/trytond/trytond/commandline.py    Tue Sep 22 18:32:04 2026 +0200
@@ -151,14 +151,22 @@
         action="store_true",
         help="activate missing dependencies of updated modules")
     parser.add_argument(
-        "--admin-login", dest="admin_login", default="admin",
-        help="login of an administrator user (default: admin)")
+        "--login", default="admin",
+        help="login of the user (default: admin)")
+    parser.add_argument(
+        "--administrator",
+        action=getattr(argparse, 'BooleanOptionalAction', 'store_true'),
+        help="set the user as administrator")
+    parser.add_argument(
+        "--active", default=True,
+        action=getattr(argparse, 'BooleanOptionalAction', 'store_true'),
+        help="activate the user")
     parser.add_argument("--email", dest="email", type=validate_email,
-        help="set the admin email")
+        help="set the user email")
     parser.add_argument("-p", "--password", dest="password",
-        action='store_true', help="set the administrator password")
+        action='store_true', help="set the user password")
     parser.add_argument("--reset-password", dest='reset_password',
-        action='store_true', help="reset the administrator password")
+        action='store_true', help="reset the user password")
     parser.add_argument("--test-email", dest='test_email', type=validate_email,
         help="send a test email to the specified address")
     parser.add_argument("-m", "--update-modules-list", action="store_true",
@@ -179,7 +187,7 @@
         help="export module translations to locale folder")
 
     parser.epilog = ('The first time a database is initialized '
-        'or when the password is set, the administrator password is read '
+        'or when the password is set, the user password is read '
         'from file defined by TRYTONPASSFILE environment variable '
         'or interactively asked from the user.\n'
         'The config file can be specified in the TRYTOND_CONFIG '

Reply via email to