From e2bb8542d3d57c382898f7d2b0c55776c691b8ba Mon Sep 17 00:00:00 2001 From: Pallab Pain Date: Thu, 3 Aug 2023 17:46:25 +0530 Subject: [PATCH] feat(project): adds command to manage user access in projects --- riocli/project/__init__.py | 2 ++ riocli/project/users/__init__.py | 38 ++++++++++++++++++++++ riocli/project/users/add.py | 50 +++++++++++++++++++++++++++++ riocli/project/users/list.py | 55 ++++++++++++++++++++++++++++++++ riocli/project/users/remove.py | 50 +++++++++++++++++++++++++++++ riocli/project/users/util.py | 26 +++++++++++++++ 6 files changed, 221 insertions(+) create mode 100644 riocli/project/users/__init__.py create mode 100644 riocli/project/users/add.py create mode 100644 riocli/project/users/list.py create mode 100644 riocli/project/users/remove.py create mode 100644 riocli/project/users/util.py diff --git a/riocli/project/__init__.py b/riocli/project/__init__.py index ba71f34e..8c55a290 100644 --- a/riocli/project/__init__.py +++ b/riocli/project/__init__.py @@ -20,6 +20,7 @@ from riocli.project.inspect import inspect_project from riocli.project.list import list_project from riocli.project.select import select_project +from riocli.project.users import users @click.group( @@ -41,3 +42,4 @@ def project() -> None: project.add_command(select_project) project.add_command(inspect_project) project.add_command(features) +project.add_command(users) diff --git a/riocli/project/users/__init__.py b/riocli/project/users/__init__.py new file mode 100644 index 00000000..94498f4d --- /dev/null +++ b/riocli/project/users/__init__.py @@ -0,0 +1,38 @@ +# Copyright 2023 Rapyuta Robotics +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import click +from click_help_colors import HelpColorsGroup + +from riocli.constants import Colors +from riocli.project.users.add import add_user_to_project +from riocli.project.users.list import list_project_users +from riocli.project.users.remove import remove_user_from_project + + +@click.group( + invoke_without_command=False, + cls=HelpColorsGroup, + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, +) +def users(): + """ + User access management on a project + """ + pass + + +users.add_command(list_project_users) +users.add_command(add_user_to_project) +users.add_command(remove_user_from_project) diff --git a/riocli/project/users/add.py b/riocli/project/users/add.py new file mode 100644 index 00000000..08aff4c9 --- /dev/null +++ b/riocli/project/users/add.py @@ -0,0 +1,50 @@ +# Copyright 2023 Rapyuta Robotics +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click +from click_help_colors import HelpColorsCommand +from yaspin.api import Yaspin + +from riocli.config import new_client +from riocli.constants import Colors, Symbols +from riocli.project.users.util import get_user_guid_from_email +from riocli.utils.spinner import with_spinner + + +@click.command( + 'add', + cls=HelpColorsCommand, + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, +) +@click.argument('user-email', type=str) +@click.pass_context +@with_spinner(text="Adding user to project...") +def add_user_to_project(ctx: click.Context, user_email: str, spinner: Yaspin = None) -> None: + """ + Add user to the project + """ + project_guid = ctx.obj.data.get('project_id') + organization_guid = ctx.obj.data.get('organization_id') + + try: + user_guid = get_user_guid_from_email(organization_guid, user_email) + client = new_client(with_project=False) + client.add_user_to_project(project_guid, user_guid) + spinner.text = click.style('User added to the project', fg=Colors.GREEN) + spinner.green.ok(Symbols.SUCCESS) + except Exception as e: + spinner.text = click.style('Failed to add user: {}'.format(e), fg=Colors.RED) + spinner.red.ok(Symbols.ERROR) + raise SystemExit(1) diff --git a/riocli/project/users/list.py b/riocli/project/users/list.py new file mode 100644 index 00000000..2cf40d2a --- /dev/null +++ b/riocli/project/users/list.py @@ -0,0 +1,55 @@ +# Copyright 2023 Rapyuta Robotics +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import typing + +import click +from click_help_colors import HelpColorsCommand +from munch import unmunchify + +from riocli.config import new_v2_client +from riocli.constants import Colors +from riocli.utils import tabulate_data + + +@click.command( + 'list', + cls=HelpColorsCommand, + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, +) +@click.pass_context +def list_project_users(ctx: click.Context) -> None: + """ + List users in the project + """ + try: + client = new_v2_client(with_project=False) + project = client.get_project(ctx.obj.data.get('project_id')) + display_project_users(unmunchify(project.spec.users)) + except Exception as e: + click.secho(str(e), fg=Colors.RED) + raise SystemExit(1) + + +def display_project_users(users: typing.List[typing.Dict]) -> None: + headers = ['ID', 'Name', 'Email', 'Status'] + data = [] + for user in users: + data.append([ + user.get('userGUID'), + '{} {}'.format(user.get('firstName'), user.get('lastName')), + user.get('emailID'), + ]) + + tabulate_data(data, headers) diff --git a/riocli/project/users/remove.py b/riocli/project/users/remove.py new file mode 100644 index 00000000..14fe321b --- /dev/null +++ b/riocli/project/users/remove.py @@ -0,0 +1,50 @@ +# Copyright 2023 Rapyuta Robotics +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click +from click_help_colors import HelpColorsCommand +from yaspin.api import Yaspin + +from riocli.config import new_client +from riocli.constants import Colors, Symbols +from riocli.project.users.util import get_user_guid_from_email +from riocli.utils.spinner import with_spinner + + +@click.command( + 'remove', + cls=HelpColorsCommand, + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, +) +@click.argument('user-email', type=str) +@click.pass_context +@with_spinner(text="Removing user from project...") +def remove_user_from_project(ctx: click.Context, user_email: str, spinner: Yaspin = None) -> None: + """ + Remove user from a project + """ + project_guid = ctx.obj.data.get('project_id') + organization_guid = ctx.obj.data.get('organization_id') + + try: + user_guid = get_user_guid_from_email(organization_guid, user_email) + client = new_client(with_project=False) + client.remove_user_from_project(project_guid, user_guid) + spinner.text = click.style('User removed from the project', fg=Colors.GREEN) + spinner.green.ok(Symbols.SUCCESS) + except Exception as e: + spinner.text = click.style('Failed to remove user: {}'.format(e), fg=Colors.RED) + spinner.red.ok(Symbols.ERROR) + raise SystemExit(1) diff --git a/riocli/project/users/util.py b/riocli/project/users/util.py new file mode 100644 index 00000000..5d0ee944 --- /dev/null +++ b/riocli/project/users/util.py @@ -0,0 +1,26 @@ +# Copyright 2023 Rapyuta Robotics +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import typing + +from riocli.organization.utils import get_organization_details + + +def get_user_guid_from_email(organization_guid: str, user_email: str) -> typing.Any: + organization = get_organization_details(organization_guid) + users = organization.get('users') + for user in users: + if user['emailID'] == user_email: + return user['guid'] + + return None