From 60722acf09904ce02d386153b7bf879b14bc5dae Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Aug 02 2023 10:46:40 +0000
Subject: [PATCH 1/3] Extend getUser to get user groups


Related: https://pagure.io/koji/issue/3854

---

diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py
index 48ba7a9..656d346 100644
--- a/cli/koji_cli/commands.py
+++ b/cli/koji_cli/commands.py
@@ -7786,7 +7786,7 @@ def anon_handle_userinfo(goptions, session, args):
     ensure_connection(session, goptions)
 
     with session.multicall() as m:
-        userinfos = [m.getUser(user) for user in args]
+        userinfos = [m.getUser(user, groups=True) for user in args]
     user_infos = []
     for username, userinfo in zip(args, userinfos):
         if userinfo.result is None:
@@ -7821,6 +7821,10 @@ def anon_handle_userinfo(goptions, session, args):
             print("Permissions:")
             for perm in perms.result:
                 print("  %s" % perm)
+        if userinfo['groups']:
+            print("Groups:")
+            for group in sorted(userinfo['groups']):
+                print("  %s" % group)
         print("Status: %s" % koji.USER_STATUS[userinfo['status']])
         print("Usertype: %s" % koji.USERTYPES[userinfo['usertype']])
         print("Number of packages: %d" % pkgs.result)
diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py
index c9ff9ff..5ac3a6f 100644
--- a/kojihub/kojihub.py
+++ b/kojihub/kojihub.py
@@ -4155,7 +4155,7 @@ def get_external_repo_list(tag_info, event=None):
     return repos
 
 
-def get_user(userInfo=None, strict=False, krb_princs=True):
+def get_user(userInfo=None, strict=False, krb_princs=True, groups=False):
     """Return information about a user.
 
     :param userInfo: a str (Kerberos principal or name) or an int (user id)
@@ -4172,6 +4172,8 @@ def get_user(userInfo=None, strict=False, krb_princs=True):
         usertype: user type (int), 0 person, 1 for host, may be null
         krb_principals: the user's Kerberos principals (list)
     """
+    krb5_join = False
+    clauses = []
     if userInfo is None:
         userInfo = context.session.user_id
         if userInfo is None:
@@ -4184,11 +4186,11 @@ def get_user(userInfo=None, strict=False, krb_princs=True):
         data = {'id': userInfo}
     elif isinstance(userInfo, str):
         data = {'info': userInfo}
-        clauses = ['krb_principal = %(info)s OR name = %(info)s']
+        clauses.append('krb_principal = %(info)s OR name = %(info)s')
+        krb5_join = True
     else:
         raise koji.GenericError('Invalid type for userInfo: %s' % type(userInfo))
     if isinstance(data, dict) and not data.get('info'):
-        clauses = []
         uid = data.get('id')
         if uid is not None:
             if isinstance(uid, int):
@@ -4206,18 +4208,23 @@ def get_user(userInfo=None, strict=False, krb_princs=True):
             if isinstance(krb_principal, str):
                 clauses.append('user_krb_principals.krb_principal'
                                ' = %(krb_principal)s')
+                krb5_join = True
             else:
                 raise koji.GenericError('Invalid type for krb_principal: %s' % type(krb_principal))
 
-    query = QueryProcessor(tables=['users'], columns=fields,
-                           joins=['LEFT JOIN user_krb_principals'
-                                  ' ON users.id = user_krb_principals.user_id'],
+    joins = []
+    if krb5_join:
+        joins.append('LEFT JOIN user_krb_principals ON users.id = user_krb_principals.user_id')
+    query = QueryProcessor(tables=['users'], columns=fields, joins=joins,
                            clauses=clauses, values=data)
     user = query.executeOne()
     if not user and strict:
         raise koji.GenericError("No such user: %r" % userInfo)
-    if user and krb_princs:
-        user['krb_principals'] = list_user_krb_principals(user['id'])
+    if user:
+        if krb_princs:
+            user['krb_principals'] = list_user_krb_principals(user['id'])
+        if groups:
+            user['groups'] = list_user_groups(user['id'])
     return user
 
 
@@ -4306,6 +4313,28 @@ def _edit_user(userInfo, name=None, krb_principal_mappings=None):
             context.session.setKrbPrincipal(user['id'], krb_principal=a)
 
 
+def list_user_groups(user_info=None):
+    if user_info is None:
+        user_info = context.session.user_id
+        if user_info is None:
+            # not logged in
+            raise koji.GenericError("No user provided")
+    data = {'info': user_info}
+    clauses = ['active IS TRUE']
+    joins = ['users g on g.id = user_groups.group_id']
+    if isinstance(user_info, int):
+        clauses.append('user_id = %(info)i')
+    elif isinstance(user_info, str):
+        joins.append('users AS u ON u.id = user_groups.user_id')
+        clauses.append('u.name = %(info)s')
+    else:
+        raise koji.GenericError('Invalid type for user_info: %s' % type(user_info))
+    fields = ['g.id', 'g.name']
+    query = QueryProcessor(tables=['user_groups'],
+                           columns=fields, joins=joins, clauses=clauses, values=data)
+    return query.execute() or []
+
+
 def list_user_krb_principals(user_info=None):
     """Return kerberos principal list of a user.
 
diff --git a/tests/test_cli/test_userinfo.py b/tests/test_cli/test_userinfo.py
index df4ed69..ec524fd 100644
--- a/tests/test_cli/test_userinfo.py
+++ b/tests/test_cli/test_userinfo.py
@@ -20,6 +20,7 @@ class TestUserinfo(utils.CliTestCase):
                           'krb_principals': ['test-principal'],
                           'name': self.user,
                           'status': 0,
+                          'groups': ['group1', 'group2'],
                           'usertype': 0}
         self.user_perms = ['admin', 'tag']
         self.count_list_packages = 2
@@ -65,6 +66,9 @@ krb principals:
 Permissions:
   admin
   tag
+Groups:
+  group1
+  group2
 Status: NORMAL
 Usertype: NORMAL
 Number of packages: 2
diff --git a/tests/test_hub/test_get_user.py b/tests/test_hub/test_get_user.py
index 8365427..51bcf2e 100644
--- a/tests/test_hub/test_get_user.py
+++ b/tests/test_hub/test_get_user.py
@@ -93,8 +93,7 @@ class TestGetUser(DBQueryTestCase):
         columns = ['id', 'name', 'status', 'usertype']
         self.assertEqual(set(query.columns), set(columns))
         self.assertEqual(query.clauses, ['users.id = %(id)i'])
-        self.assertEqual(query.joins, ['LEFT JOIN user_krb_principals ON '
-                                       'users.id = user_krb_principals.user_id'])
+        self.assertEqual(query.joins, [])
         self.assertEqual(query.values, userinfo)
 
 

From 9d03e43a6aafb215779c229ff98572e47f2c6b13 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Aug 02 2023 10:46:40 +0000
Subject: [PATCH 2/3] use auth.get_user_groups


---

diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py
index 656d346..69b262d 100644
--- a/cli/koji_cli/commands.py
+++ b/cli/koji_cli/commands.py
@@ -7787,6 +7787,14 @@ def anon_handle_userinfo(goptions, session, args):
 
     with session.multicall() as m:
         userinfos = [m.getUser(user, groups=True) for user in args]
+    try:
+        # hub < 1.34 doesn't support groups option, it also raises an exception on access,
+        # so later it would fail the result iteration cycle
+        userinfos[0].result
+    except koji.ParameterError:
+        with session.multicall() as m:
+            userinfos = [m.getUser(user) for user in args]
+
     user_infos = []
     for username, userinfo in zip(args, userinfos):
         if userinfo.result is None:
@@ -7821,7 +7829,7 @@ def anon_handle_userinfo(goptions, session, args):
             print("Permissions:")
             for perm in perms.result:
                 print("  %s" % perm)
-        if userinfo['groups']:
+        if userinfo.get('groups'):
             print("Groups:")
             for group in sorted(userinfo['groups']):
                 print("  %s" % group)
diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py
index 5ac3a6f..afe6f11 100644
--- a/kojihub/kojihub.py
+++ b/kojihub/kojihub.py
@@ -4224,7 +4224,7 @@ def get_user(userInfo=None, strict=False, krb_princs=True, groups=False):
         if krb_princs:
             user['krb_principals'] = list_user_krb_principals(user['id'])
         if groups:
-            user['groups'] = list_user_groups(user['id'])
+            user['groups'] = [x['name'] for x in get_user_groups(user['id'])]
     return user
 
 
@@ -4313,28 +4313,6 @@ def _edit_user(userInfo, name=None, krb_principal_mappings=None):
             context.session.setKrbPrincipal(user['id'], krb_principal=a)
 
 
-def list_user_groups(user_info=None):
-    if user_info is None:
-        user_info = context.session.user_id
-        if user_info is None:
-            # not logged in
-            raise koji.GenericError("No user provided")
-    data = {'info': user_info}
-    clauses = ['active IS TRUE']
-    joins = ['users g on g.id = user_groups.group_id']
-    if isinstance(user_info, int):
-        clauses.append('user_id = %(info)i')
-    elif isinstance(user_info, str):
-        joins.append('users AS u ON u.id = user_groups.user_id')
-        clauses.append('u.name = %(info)s')
-    else:
-        raise koji.GenericError('Invalid type for user_info: %s' % type(user_info))
-    fields = ['g.id', 'g.name']
-    query = QueryProcessor(tables=['user_groups'],
-                           columns=fields, joins=joins, clauses=clauses, values=data)
-    return query.execute() or []
-
-
 def list_user_krb_principals(user_info=None):
     """Return kerberos principal list of a user.
 

From 9ed7ccda199b61d21771764985951aab7e6586a6 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Aug 02 2023 10:54:05 +0000
Subject: [PATCH 3/3] fix returned data after rebase


---

diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py
index afe6f11..775cb5d 100644
--- a/kojihub/kojihub.py
+++ b/kojihub/kojihub.py
@@ -4224,7 +4224,7 @@ def get_user(userInfo=None, strict=False, krb_princs=True, groups=False):
         if krb_princs:
             user['krb_principals'] = list_user_krb_principals(user['id'])
         if groups:
-            user['groups'] = [x['name'] for x in get_user_groups(user['id'])]
+            user['groups'] = [x for x in get_user_groups(user['id']).values()]
     return user
 
 

