From b99fb5f51b242b75440d07f62703ea345682a60b Mon Sep 17 00:00:00 2001 From: Pallab Pain Date: Mon, 31 Jul 2023 16:55:09 +0530 Subject: [PATCH] feat(organization): adds command to invite user --- Pipfile | 1 + Pipfile.lock | 18 ++++++++++- riocli/organization/__init__.py | 2 ++ riocli/organization/invite_user.py | 49 ++++++++++++++++++++++++++++++ riocli/organization/utils.py | 5 +++ setup.py | 3 +- 6 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 riocli/organization/invite_user.py diff --git a/Pipfile b/Pipfile index 8c08751b..a288da71 100644 --- a/Pipfile +++ b/Pipfile @@ -32,6 +32,7 @@ yaspin = ">=2.3.0" jsonschema = ">=4.0.0" waiting = ">=1.4.1" semver = ">=3.0.0" +email-validator = "==2.0.0.post2" [requires] python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index 22eb64fd..d03e5ec0 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "18f6b5a7d593287408fb9b9a361ee26ad2de6f222b5a95fc4bb3b0e8c59c0437" + "sha256": "5f1b9a8605fc6d4b5f9538df13d704a98f1ab4425cf44a9c9368d91ae0f782d7" }, "pipfile-spec": 6, "requires": { @@ -191,6 +191,22 @@ "index": "pypi", "version": "==0.0.4" }, + "dnspython": { + "hashes": [ + "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8", + "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984" + ], + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==2.4.2" + }, + "email-validator": { + "hashes": [ + "sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900", + "sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c" + ], + "index": "pypi", + "version": "==2.0.0.post2" + }, "graphlib-backport": { "hashes": [ "sha256:24246967b9e7e6a91550bc770e6169585d35aa32790258579a8a3899a8c18fde", diff --git a/riocli/organization/__init__.py b/riocli/organization/__init__.py index 2c9bf4a8..31247b97 100644 --- a/riocli/organization/__init__.py +++ b/riocli/organization/__init__.py @@ -16,6 +16,7 @@ from riocli.constants import Colors from riocli.organization.inspect import inspect_organization +from riocli.organization.invite_user import invite_user from riocli.organization.list import list_organizations from riocli.organization.select import select_organization from riocli.organization.users import list_users @@ -35,6 +36,7 @@ def organization() -> None: organization.add_command(list_users) +organization.add_command(invite_user) organization.add_command(list_organizations) organization.add_command(select_organization) organization.add_command(inspect_organization) diff --git a/riocli/organization/invite_user.py b/riocli/organization/invite_user.py new file mode 100644 index 00000000..44925982 --- /dev/null +++ b/riocli/organization/invite_user.py @@ -0,0 +1,49 @@ +# 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 email_validator import EmailNotValidError, validate_email + +from riocli.constants import Colors, Symbols +from riocli.organization.utils import invite_user_to_org +from riocli.utils.context import get_root_context + + +@click.command( + 'invite-user', + cls=HelpColorsCommand, + help_headers_color=Colors.YELLOW, + help_options_color=Colors.GREEN, +) +@click.argument('user-email', type=str) +@click.pass_context +def invite_user(ctx: click.Context, user_email: str) -> None: + """ + Invite a new user to the current organization + """ + ctx = get_root_context(ctx) + + try: + validate_email(user_email) + except EmailNotValidError as e: + click.secho('{} {} is not a valid email address'.format(Symbols.ERROR, user_email), fg=Colors.RED) + raise SystemExit(1) from e + + try: + invite_user_to_org(ctx.obj.data['organization_id'], user_email) + click.secho('{} User invited successfully.'.format(Symbols.SUCCESS), fg=Colors.GREEN) + except Exception as e: + click.secho('{} Failed to invite user: {}'.format(Symbols.ERROR, e), fg=Colors.RED) + raise SystemExit(1) from e diff --git a/riocli/organization/utils.py b/riocli/organization/utils.py index 7efa95ba..55afb9cb 100644 --- a/riocli/organization/utils.py +++ b/riocli/organization/utils.py @@ -53,3 +53,8 @@ def _api_call( def get_organization_details(organization_guid: str) -> typing.Dict: return _api_call(HttpMethod.GET, '{}/get'.format(organization_guid)) + + +def invite_user_to_org(organization_guid: str, user_email: str) -> typing.Dict: + payload = {'userEmail': user_email} + return _api_call(HttpMethod.PUT, '{}/adduser'.format(organization_guid), payload=payload) diff --git a/setup.py b/setup.py index 9ba120d0..5e8cccdd 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import re -from setuptools import setup, find_packages +from setuptools import find_packages, setup version = re.search( '^__version__\s*=\s*"(.*)"', open("riocli/bootstrap.py").read(), re.M @@ -59,6 +59,7 @@ "jsonschema==4.0.0", "waiting>=1.4.1", "semver>=3.0.0", + "email-validator==2.0.0.post2", ], setup_requires=["flake8"], )