-
Notifications
You must be signed in to change notification settings - Fork 13
Users command: Functionality to add/remove roles + Users user guide #283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
163aa0b
7fb2f14
cdb75f0
516ca65
03d0b58
52bd426
697c17d
2256f69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.. click:: code42cli.cmds.users:users | ||
:prog: users | ||
:show-nested: |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
from code42cli.click_ext.groups import OrderedGroup | ||
from code42cli.click_ext.options import incompatible_with | ||
from code42cli.errors import Code42CLIError | ||
from code42cli.errors import UserDoesNotExistError | ||
from code42cli.options import format_option | ||
from code42cli.options import sdk_options | ||
from code42cli.output_formats import DataFrameOutputFormatter | ||
|
@@ -60,6 +61,50 @@ def list_users(state, org_uid, role_name, active, inactive, format): | |
formatter.echo_formatted_dataframe(df) | ||
|
||
|
||
@users.command() | ||
@click.argument("username") | ||
@click.argument("role-name") | ||
@sdk_options() | ||
def add_role(state, username, role_name): | ||
"""Add the specified role to the specified username""" | ||
maddie-vargo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_add_user_role(state.sdk, role_name, username) | ||
|
||
|
||
@users.command() | ||
@click.argument("username") | ||
@click.argument("role-name") | ||
@sdk_options() | ||
def remove_role(state, username, role_name): | ||
"""Add the specified role to the specified username""" | ||
_remove_user_role(state.sdk, role_name, username) | ||
|
||
|
||
def _add_user_role(sdk, role_name, username): | ||
user_id = _get_user_id(sdk, username) | ||
try: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand what this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The try/except block isn't doing anything, actually - I will remove it. We don't actually even need the roleID from _get_role_id to proceed. However, I like the error handling Cecilia had built for an invalid role name. It handles cases where an invalid role name was entered and provides the following error message:
Otherwise, the error is:
Py42 doesn't really have a method for determining if a role name is valid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth adding a comment about that, or even extracting the error handling into a separate method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a comment. I had trouble extracting the error handling, since 95% of what that method doing is error handling. Extracting the error handling didn't add clarity or reduce redundancy. |
||
_get_role_id(sdk, role_name) | ||
except Code42CLIError: | ||
raise | ||
sdk.users.add_role(user_id, role_name) | ||
|
||
|
||
def _remove_user_role(sdk, role_name, username): | ||
user_id = _get_user_id(sdk, username) | ||
try: | ||
_get_role_id(sdk, role_name) | ||
except Code42CLIError: | ||
raise | ||
sdk.users.remove_role(user_id, role_name) | ||
|
||
|
||
def _get_user_id(sdk, username): | ||
user = sdk.users.get_by_username(username)["users"] | ||
if not user: | ||
raise UserDoesNotExistError | ||
maddie-vargo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
user_id = user[0]["userId"] | ||
return user_id | ||
|
||
|
||
def _get_role_id(sdk, role_name): | ||
try: | ||
roles_dataframe = DataFrame.from_records( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,9 @@ | |
} | ||
] | ||
} | ||
TEST_USERNAME = TEST_USERS_RESPONSE["users"][0]["username"] | ||
TEST_USER_ID = TEST_USERS_RESPONSE["users"][0]["userId"] | ||
TEST_ROLE_NAME = TEST_ROLE_RETURN_DATA["data"][0]["roleName"] | ||
|
||
|
||
def _create_py42_response(mocker, text): | ||
|
@@ -56,6 +59,11 @@ def get_all_users_success(cli_state): | |
cli_state.sdk.users.get_all.return_value = get_all_users_generator() | ||
|
||
|
||
@pytest.fixture | ||
def get_user_id_success(cli_state): | ||
cli_state.sdk.users.get_by_username.return_value = TEST_USERS_RESPONSE | ||
|
||
|
||
@pytest.fixture | ||
def get_available_roles_success(cli_state, get_available_roles_response): | ||
cli_state.sdk.users.get_available_roles.return_value = get_available_roles_response | ||
|
@@ -153,3 +161,44 @@ def test_list_users_when_given_excluding_active_and_inactive_uses_active_equals_ | |
cli_state.sdk.users.get_all.assert_called_once_with( | ||
active=None, org_uid=None, role_id=None | ||
) | ||
|
||
|
||
def test_add_user_role_adds( | ||
runner, cli_state, get_user_id_success, get_available_roles_success | ||
): | ||
command = ["users", "add-role", "[email protected]", "Customer Cloud Admin"] | ||
runner.invoke(cli, command, obj=cli_state) | ||
cli_state.sdk.users.add_role.assert_called_once_with(TEST_USER_ID, TEST_ROLE_NAME) | ||
|
||
|
||
def test_add_user_role_raises_error_when_role_does_not_exist( | ||
runner, cli_state, get_user_id_success, get_available_roles_success | ||
): | ||
command = ["users", "add-role", "[email protected]", "test"] | ||
result = runner.invoke(cli, command, obj=cli_state) | ||
assert result.exit_code == 1 | ||
assert "Role with name test not found." in result.output | ||
|
||
|
||
def test_remove_user_role_removes( | ||
runner, cli_state, get_user_id_success, get_available_roles_success | ||
): | ||
command = [ | ||
"users", | ||
"remove-role", | ||
"[email protected]", | ||
"Customer Cloud Admin", | ||
] | ||
runner.invoke(cli, command, obj=cli_state) | ||
cli_state.sdk.users.remove_role.assert_called_once_with( | ||
TEST_USER_ID, TEST_ROLE_NAME | ||
) | ||
|
||
|
||
def test_remove_user_role_raises_error_when_role_does_not_exist( | ||
runner, cli_state, get_user_id_success, get_available_roles_success | ||
): | ||
command = ["users", "remove-role", "[email protected]", "test"] | ||
result = runner.invoke(cli, command, obj=cli_state) | ||
assert result.exit_code == 1 | ||
assert "Role with name test not found." in result.output | ||
maddie-vargo marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When commands have multiple arguments, we elect to use required options instead.
This is because then the order does not matter, like I don't have to use
--help
to see if the username goes first or the role name.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, I added them as functions with flexible help text, assuming that they would be re-used in further expansions of the
users
command.