Skip to content

Commit bcf09d2

Browse files
committed
usermanager: Update groups commands for better UX
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
1 parent d4a2850 commit bcf09d2

1 file changed

Lines changed: 100 additions & 11 deletions

File tree

scripts/usermanager.py

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def _apply_group_changes(current, add_groups, remove_groups):
125125

126126

127127
def _resolve_user_id(user_id, api_url, token):
128-
if "@" not in user_id:
128+
if _looks_like_object_id(user_id):
129129
return user_id
130130
status, body = _request_json("GET", f"{api_url}/users", token=token)
131131
if status >= 400:
@@ -135,20 +135,20 @@ def _resolve_user_id(user_id, api_url, token):
135135
payload = json.loads(body) if body else []
136136
except json.JSONDecodeError as exc:
137137
raise SystemExit("Failed to parse users response") from exc
138-
if not isinstance(payload, list):
139-
raise SystemExit("Unexpected users response")
140-
matches = [
141-
user
142-
for user in payload
143-
if isinstance(user, dict) and user.get("email") == user_id
144-
]
138+
items = _parse_paginated_items(payload)
139+
matches = []
140+
for user in items:
141+
if not isinstance(user, dict):
142+
continue
143+
if user.get("email") == user_id or user.get("username") == user_id:
144+
matches.append(user)
145145
if not matches:
146-
raise SystemExit(f"No user found with email: {user_id}")
146+
raise SystemExit(f"No user found with email/username: {user_id}")
147147
if len(matches) > 1:
148-
raise SystemExit(f"Multiple users found with email: {user_id}")
148+
raise SystemExit(f"Multiple users found with email/username: {user_id}")
149149
resolved_id = matches[0].get("id")
150150
if not resolved_id:
151-
raise SystemExit(f"User with email {user_id} has no id")
151+
raise SystemExit(f"User with {user_id} has no id")
152152
return resolved_id
153153

154154

@@ -194,6 +194,47 @@ def _resolve_group_id(group_id, api_url, token):
194194
return resolved_id
195195

196196

197+
def _resolve_group_name(group_name, api_url, token):
198+
if not _looks_like_object_id(group_name):
199+
return group_name
200+
status, body = _request_json(
201+
"GET", f"{api_url}/user-groups/{group_name}", token=token
202+
)
203+
if status >= 400:
204+
_print_response(status, body)
205+
raise SystemExit(1)
206+
try:
207+
payload = json.loads(body) if body else {}
208+
except json.JSONDecodeError as exc:
209+
raise SystemExit("Failed to parse user-group response") from exc
210+
resolved_name = payload.get("name")
211+
if not resolved_name:
212+
raise SystemExit(f"Group {group_name} has no name")
213+
return resolved_name
214+
215+
216+
def _resolve_group_names(group_names, api_url, token):
217+
return _dedupe(
218+
[_resolve_group_name(name, api_url, token) for name in group_names]
219+
)
220+
221+
222+
def _update_user_groups(resolved_id, add_groups, remove_groups, api_url, token):
223+
status, body = _request_json("GET", f"{api_url}/user/{resolved_id}", token=token)
224+
if status >= 400:
225+
_print_response(status, body)
226+
raise SystemExit(1)
227+
try:
228+
payload = json.loads(body) if body else {}
229+
except json.JSONDecodeError as exc:
230+
raise SystemExit("Failed to parse user response") from exc
231+
current_groups = _extract_group_names(payload)
232+
data = {
233+
"groups": _apply_group_changes(current_groups, add_groups, remove_groups),
234+
}
235+
return _request_json("PATCH", f"{api_url}/user/{resolved_id}", data, token=token)
236+
237+
197238
def _request_json(method, url, data=None, token=None, form=False):
198239
headers = {"accept": "application/json"}
199240
body = None
@@ -352,6 +393,28 @@ def main():
352393
delete_user = subparsers.add_parser("delete-user", help="Delete user by id")
353394
delete_user.add_argument("user_id")
354395

396+
assign_group = subparsers.add_parser(
397+
"assign-group", help="Assign group(s) to a user"
398+
)
399+
assign_group.add_argument("user_id")
400+
assign_group.add_argument(
401+
"--group",
402+
action="append",
403+
default=[],
404+
help="Group name or id; can be used multiple times or with commas",
405+
)
406+
407+
deassign_group = subparsers.add_parser(
408+
"deassign-group", help="Remove group(s) from a user"
409+
)
410+
deassign_group.add_argument("user_id")
411+
deassign_group.add_argument(
412+
"--group",
413+
action="append",
414+
default=[],
415+
help="Group name or id; can be used multiple times or with commas",
416+
)
417+
355418
list_groups = subparsers.add_parser("list-groups", help="List user groups")
356419

357420
get_group = subparsers.add_parser("get-group", help="Get user group by id or name")
@@ -416,6 +479,8 @@ def main():
416479
"get-user",
417480
"update-user",
418481
"delete-user",
482+
"assign-group",
483+
"deassign-group",
419484
"list-groups",
420485
"get-group",
421486
"create-group",
@@ -500,6 +565,12 @@ def main():
500565
set_groups = _parse_group_list(args.set_groups)
501566
add_groups = _parse_group_list(args.add_group)
502567
remove_groups = _parse_group_list(args.remove_group)
568+
if set_groups:
569+
set_groups = _resolve_group_names(set_groups, api_url, token)
570+
if add_groups:
571+
add_groups = _resolve_group_names(add_groups, api_url, token)
572+
if remove_groups:
573+
remove_groups = _resolve_group_names(remove_groups, api_url, token)
503574
if set_groups or add_groups or remove_groups:
504575
if set_groups:
505576
current_groups = set_groups
@@ -529,6 +600,24 @@ def main():
529600
status, body = _request_json(
530601
"DELETE", f"{api_url}/user/{resolved_id}", token=token
531602
)
603+
elif args.command == "assign-group":
604+
resolved_id = _resolve_user_id(args.user_id, api_url, token)
605+
add_groups = _parse_group_list(args.group)
606+
if not add_groups:
607+
raise SystemExit("No groups specified. Use --group.")
608+
add_groups = _resolve_group_names(add_groups, api_url, token)
609+
status, body = _update_user_groups(
610+
resolved_id, add_groups, [], api_url, token
611+
)
612+
elif args.command == "deassign-group":
613+
resolved_id = _resolve_user_id(args.user_id, api_url, token)
614+
remove_groups = _parse_group_list(args.group)
615+
if not remove_groups:
616+
raise SystemExit("No groups specified. Use --group.")
617+
remove_groups = _resolve_group_names(remove_groups, api_url, token)
618+
status, body = _update_user_groups(
619+
resolved_id, [], remove_groups, api_url, token
620+
)
532621
elif args.command == "list-groups":
533622
status, body = _request_json("GET", f"{api_url}/user-groups", token=token)
534623
elif args.command == "get-group":

0 commit comments

Comments
 (0)