Skip to content

Commit 93d2ef1

Browse files
authored
Feature/add user roles view (#329)
* trust user guide * adding trust user guides * user guides * adding user guides * user guides * user guides * adding tora.kozic cmd and --include-roles option * PR feedback * PR feedback * user orgs cmds * cmds to view orgs * pass checks * users and orgs integration tests * style * new command docs * naming * wording * PR feedback
1 parent 7258218 commit 93d2ef1

File tree

5 files changed

+419
-24
lines changed

5 files changed

+419
-24
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
The intended audience of this file is for py42 consumers -- as such, changes that don't affect
99
how a consumer would use the library (e.g. adding unit tests, updating documentation, etc) are not captured here.
1010

11+
## Unreleased
12+
13+
### Added
14+
15+
- New option `--include-roles` on `code42 users list` that includes the roles for all users.
16+
17+
- New command `code42 users show <username>` that prints all the details of that user.
18+
19+
- New commands to view orgs
20+
- `code42 users orgs list`
21+
- `code42 users orgs show <org-uid>`
22+
1123
## 1.10.0 - 2021-10-05
1224

1325
### Added

docs/userguides/users.md

+24-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ To change the information for one or more users, provide the user UID and update
1515

1616
Apply [Code42's user roles](https://support.code42.com/Administrator/Cloud/Monitoring_and_managing/Roles_resources/Roles_reference#Standard_roles) to user accounts to provide administrators with the desired set of permissions. Each role has associated permissions, limitations, and recommended use cases.
1717

18+
#### View User Roles
19+
View a user's current roles and other details with the `show` command:
20+
```bash
21+
code42 users show "[email protected]"
22+
```
23+
Alternatively, pass the `--include-roles` flag to the `list ` command. The following command will print a list of all active users and their current roles:
24+
```bash
25+
code42 users list --active --include-roles
26+
```
27+
28+
#### Update User Roles
29+
1830
Use the following command to add a role to a user:
1931
```bash
2032
code42 users add-role --username "[email protected]" --role-name "Desktop User"
@@ -40,7 +52,18 @@ Similarly, use the `reactivate` and `bulk reactivate` commands to reactivate a u
4052

4153
Use [Organizations](https://support.code42.com/Administrator/Cloud/Code42_console_reference/Organizations_reference) to group users together in the Code42 environment.
4254

43-
Use the following example command to move a user into an organization associated with the `org_id` 1234567890:
55+
You'll need an organization's unique identifier number (UID) to move a user into it. You can use the `list` command to view a list of all current user organizations, including UIDs:
56+
```bash
57+
code42 users orgs list
58+
```
59+
60+
Use the `show` command to view all the details of a user organization.
61+
As an example, to print the details of an organization associated with the UID `123456789` in JSON format:
62+
```bash
63+
code42 users show 123456789 -f JSON
64+
```
65+
66+
Once you've identified your organizations UID number, use the `move` command to move a user into that organization. In the following example a user is moved into the organization associated with the UID `1234567890`:
4467
```bash
4568
code42 users move --username [email protected] --org-id 1234567890
4669
```

src/code42cli/cmds/users.py

+116-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import click
22
from pandas import DataFrame
33
from pandas import json_normalize
4+
from py42.exceptions import Py42NotFoundError
45

56
from code42cli.bulk import generate_template_cmd_factory
67
from code42cli.bulk import run_bulk_process
@@ -17,12 +18,7 @@
1718
from code42cli.worker import create_worker_stats
1819

1920

20-
@click.group(cls=OrderedGroup)
21-
@sdk_options(hidden=True)
22-
def users(state):
23-
"""Manage users within your Code42 environment."""
24-
pass
25-
21+
username_arg = click.argument("username")
2622

2723
org_uid_option = click.option(
2824
"--org-uid",
@@ -42,9 +38,15 @@ def users(state):
4238
)
4339
org_id_option = click.option(
4440
"--org-id",
45-
help="The identifier for the organization to which the user will be moved.",
41+
help="The unique identifier (UID) for the organization to which the user will be moved.",
4642
required=True,
4743
)
44+
include_legal_hold_option = click.option(
45+
"--include-legal-hold-membership",
46+
default=False,
47+
is_flag=True,
48+
help="Include legal hold membership in output.",
49+
)
4850

4951

5052
def role_name_option(help):
@@ -55,21 +57,33 @@ def username_option(help, required=False):
5557
return click.option("--username", help=help, required=required)
5658

5759

60+
@click.group(cls=OrderedGroup)
61+
@sdk_options(hidden=True)
62+
def users(state):
63+
"""Manage users within your Code42 environment."""
64+
pass
65+
66+
5867
@users.command(name="list")
5968
@org_uid_option
6069
@role_name_option("Limit results to only users having the specified role.")
6170
@active_option
6271
@inactive_option
72+
@include_legal_hold_option
6373
@click.option(
64-
"--include-legal-hold-membership",
65-
default=False,
66-
is_flag=True,
67-
help="Include legal hold membership in output.",
74+
"--include-roles", default=False, is_flag=True, help="Include user roles."
6875
)
6976
@format_option
7077
@sdk_options()
7178
def list_users(
72-
state, org_uid, role_name, active, inactive, include_legal_hold_membership, format
79+
state,
80+
org_uid,
81+
role_name,
82+
active,
83+
inactive,
84+
include_legal_hold_membership,
85+
include_roles,
86+
format,
7387
):
7488
"""List users in your Code42 environment."""
7589
if inactive:
@@ -80,7 +94,11 @@ def list_users(
8094
if format == OutputFormat.TABLE
8195
else None
8296
)
83-
df = _get_users_dataframe(state.sdk, columns, org_uid, role_id, active)
97+
if include_roles and columns:
98+
columns.append("roles")
99+
df = _get_users_dataframe(
100+
state.sdk, columns, org_uid, role_id, active, include_roles
101+
)
84102
if include_legal_hold_membership:
85103
df = _add_legal_hold_membership_to_user_dataframe(state.sdk, df)
86104
if df.empty:
@@ -90,6 +108,29 @@ def list_users(
90108
formatter.echo_formatted_dataframe(df)
91109

92110

111+
@users.command("show")
112+
@username_arg
113+
@include_legal_hold_option
114+
@format_option
115+
@sdk_options()
116+
def show_user(state, username, include_legal_hold_membership, format):
117+
"""Show user details."""
118+
columns = (
119+
["userUid", "status", "username", "orgUid", "roles"]
120+
if format == OutputFormat.TABLE
121+
else None
122+
)
123+
response = state.sdk.users.get_by_username(username, incRoles=True)
124+
df = DataFrame.from_records(response["users"], columns=columns)
125+
if include_legal_hold_membership and not df.empty:
126+
df = _add_legal_hold_membership_to_user_dataframe(state.sdk, df)
127+
if df.empty:
128+
click.echo("No results found.")
129+
else:
130+
formatter = DataFrameOutputFormatter(format)
131+
formatter.echo_formatted_dataframe(df)
132+
133+
93134
@users.command()
94135
@username_option("Username of the target user.")
95136
@role_name_option("Name of role to add.")
@@ -146,7 +187,7 @@ def update_user(
146187

147188

148189
@users.command()
149-
@click.argument("username")
190+
@username_arg
150191
@sdk_options()
151192
def deactivate(state, username):
152193
"""Deactivate a user."""
@@ -155,7 +196,7 @@ def deactivate(state, username):
155196

156197

157198
@users.command()
158-
@click.argument("username")
199+
@username_arg
159200
@sdk_options()
160201
def reactivate(state, username):
161202
"""Reactivate a user."""
@@ -183,10 +224,64 @@ def reactivate(state, username):
183224
@sdk_options()
184225
def change_organization(state, username, org_id):
185226
"""Change the organization of the user with the given username
186-
to the org with the given org ID."""
227+
to the org with the given org UID."""
187228
_change_organization(state.sdk, username, org_id)
188229

189230

231+
@users.group(cls=OrderedGroup)
232+
@sdk_options(hidden=True)
233+
def orgs(state):
234+
"""Tools for viewing user orgs."""
235+
pass
236+
237+
238+
def _get_orgs_header():
239+
return {
240+
"orgId": "ID",
241+
"orgUid": "UID",
242+
"orgName": "Name",
243+
"status": "Status",
244+
"parentOrgId": "Parent ID",
245+
"parentOrgUid": "Parent UID",
246+
"type": "Type",
247+
"classification": "Classification",
248+
"creationDate": "Creation Date",
249+
"settings": "Settings",
250+
}
251+
252+
253+
@orgs.command(name="list")
254+
@format_option
255+
@sdk_options()
256+
def list_orgs(
257+
state, format,
258+
):
259+
"""List all orgs."""
260+
pages = state.sdk.orgs.get_all()
261+
formatter = OutputFormatter(format, _get_orgs_header())
262+
orgs = [org for page in pages for org in page["orgs"]]
263+
if orgs:
264+
formatter.echo_formatted_list(orgs)
265+
else:
266+
click.echo("No orgs found.")
267+
268+
269+
@orgs.command(name="show")
270+
@click.argument("org-uid")
271+
@format_option
272+
@sdk_options()
273+
def show_org(
274+
state, org_uid, format,
275+
):
276+
"""Show org details."""
277+
formatter = OutputFormatter(format)
278+
try:
279+
response = state.sdk.orgs.get_by_uid(org_uid)
280+
formatter.echo_formatted_list([response.data])
281+
except Py42NotFoundError:
282+
raise Code42CLIError(f"Invalid org UID {org_uid}.")
283+
284+
190285
@users.group(cls=OrderedGroup)
191286
@sdk_options(hidden=True)
192287
def bulk(state):
@@ -400,8 +495,10 @@ def _get_role_id(sdk, role_name):
400495
raise Code42CLIError(f"Role with name '{role_name}' not found.")
401496

402497

403-
def _get_users_dataframe(sdk, columns, org_uid, role_id, active):
404-
users_generator = sdk.users.get_all(active=active, org_uid=org_uid, role_id=role_id)
498+
def _get_users_dataframe(sdk, columns, org_uid, role_id, active, include_roles):
499+
users_generator = sdk.users.get_all(
500+
active=active, org_uid=org_uid, role_id=role_id, incRoles=include_roles
501+
)
405502
users_list = []
406503
for page in users_generator:
407504
users_list.extend(page["users"])
@@ -413,6 +510,7 @@ def _add_legal_hold_membership_to_user_dataframe(sdk, df):
413510
columns = ["legalHold.legalHoldUid", "legalHold.name", "user.userUid"]
414511

415512
custodians = list(_get_all_active_hold_memberships(sdk))
513+
416514
if len(custodians) == 0:
417515
return df
418516

0 commit comments

Comments
 (0)