Skip to content

Commit

Permalink
added invite command + minor changes in user command
Browse files Browse the repository at this point in the history
  • Loading branch information
agustinhydrolix committed Feb 23, 2024
1 parent 92cd03a commit d9a5ec0
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 62 deletions.
33 changes: 20 additions & 13 deletions src/hdx_cli/cli_interface/common/undecorated_click_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,25 +436,17 @@ def basic_delete(profile,
return True


def basic_list(profile, resource_path):
hostname = profile.hostname
scheme = profile.scheme
timeout = profile.timeout
list_url = f'{scheme}://{hostname}{resource_path}'
auth_info: AuthInfo = profile.auth
headers = {'Authorization': f'{auth_info.token_type} {auth_info.token}',
'Accept': 'application/json'}
resources = rest_ops.list(list_url,
headers=headers,
timeout=timeout)
def basic_list(profile, resource_path, filter_field: Optional[str] = 'name'):
resources = get_resource_list(profile, resource_path)

for resource in resources:
if isinstance(resource, str):
logger.info(resource)
else:
if (settings := resource.get('settings')) and settings.get('is_default'):
logger.info(f"{resource['name']} (default)")
logger.info(f"{resource[filter_field]} (default)")
else:
logger.info(f"{resource['name']}")
logger.info(f"{resource[filter_field]}")


def _get_resource_information(profile,
Expand Down Expand Up @@ -503,3 +495,18 @@ def basic_activity(profile, resource_path, resource_name, indent):
resource_name,
'activity',
indent)


def get_resource_list(profile, resource_path, **kwargs):
hostname = profile.hostname
scheme = profile.scheme
timeout = profile.timeout
list_url = f'{scheme}://{hostname}{resource_path}'
auth_info: AuthInfo = profile.auth
headers = {'Authorization': f'{auth_info.token_type} {auth_info.token}',
'Accept': 'application/json'}
resources = rest_ops.list(list_url,
headers=headers,
timeout=timeout,
params=kwargs)
return resources
162 changes: 114 additions & 48 deletions src/hdx_cli/cli_interface/user/commands.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from typing import Dict, Tuple
from functools import partial
import re
import json
import click

from ...library_api.common.exceptions import LogicException, HttpException
from ...library_api.userdata.token import AuthInfo
from ...library_api.common import rest_operations as rest_ops
from ...library_api.common.exceptions import LogicException, HttpException, ResourceNotFoundException
from ...library_api.utility.decorators import (report_error_and_exit,
dynamic_confirmation_prompt)
from ...library_api.common.context import ProfileUserContext
from ...library_api.common.logging import get_logger
from ..common.undecorated_click_commands import basic_delete, basic_show, basic_create_from_dict_body
from ..common.undecorated_click_commands import (basic_delete,
basic_show,
basic_create_from_dict_body,
get_resource_list)

logger = get_logger()

Expand All @@ -31,18 +32,25 @@ def user(ctx: click.Context,
@click.command(help='List users.', name='list')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def list_(ctx: click.Context):
def list_users(ctx: click.Context):
resource_path = ctx.parent.obj.get('resource_path')
profile = ctx.parent.obj.get('usercontext')
_basic_list(profile, resource_path)
resources = get_resource_list(profile, resource_path)

_log_formatted_table_header({'email': 45, "status": 30})

@click.command(help='Show user. If not resource_name is provided, it will show the default if there is one.')
for resource in resources:
roles_name = resource.get("roles")
logger.info(f'{resource["email"].ljust(45)}{(", ".join(roles_name)).ljust(50)}')


@click.command(help='Show resource. If not resource_name is provided, it will show the default if there is one.')
@click.option('-i', '--indent', is_flag=True, default=False,
help='Number of spaces for indentation in the output.')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def show(ctx: click.Context, indent: bool):
def show(ctx: click.Context,
indent: bool):
profile = ctx.parent.obj.get('usercontext')
resource_path = ctx.parent.obj.get('resource_path')
if not (resource_name := getattr(profile, 'useremail')):
Expand All @@ -52,41 +60,20 @@ def show(ctx: click.Context, indent: bool):
indent=indent, filter_field='email'))


@click.command(help='Send invitation to a new user.')
@click.argument('email', metavar='USER_EMAIL')
@click.option('-r', '--role', 'roles', multiple=True, default=None, required=True,
help='Specify the role for the new user (can be used multiple times).')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def invite(ctx: click.Context,
email,
roles):
resource_path = '/config/v1/invite/'
profile = ctx.parent.obj.get('usercontext')

org_id = profile.org_id
body = {
'email': email,
'org': org_id,
'roles': roles
}
basic_create_from_dict_body(profile, resource_path, body)
logger.info(f'Invitation sent to {email}')


_confirmation_prompt = partial(dynamic_confirmation_prompt,
prompt="Please type 'delete this resource' to delete: ",
confirmation_message='delete this resource',
fail_message='Incorrect prompt input: resource was not deleted')


@click.command(help='Delete user.')
@click.command(help='Delete resource.')
@click.option('--disable-confirmation-prompt', is_flag=True, show_default=True, default=False,
help='Suppress confirmation to delete resource.')
@click.argument('email', metavar='USER_EMAIL')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def delete(ctx: click.Context, email: str,
def delete(ctx: click.Context,
email: str,
disable_confirmation_prompt: bool):
_confirmation_prompt(prompt_active=not disable_confirmation_prompt)
resource_path = ctx.parent.obj.get('resource_path')
Expand Down Expand Up @@ -155,25 +142,104 @@ def remove(ctx: click.Context,
logger.info(f'Removed role(s) from {email}')


def _basic_list(profile, resource_path):
hostname = profile.hostname
scheme = profile.scheme
timeout = profile.timeout
list_url = f'{scheme}://{hostname}{resource_path}'
auth_info: AuthInfo = profile.auth
headers = {'Authorization': f'{auth_info.token_type} {auth_info.token}',
'Accept': 'application/json'}
resources = rest_ops.list(list_url,
headers=headers,
timeout=timeout)
@click.group(help='Invite-related operations')
@click.option('--user', 'user_email', metavar='USER_EMAIL', default=None,
help='Perform operation on the passed user.')
@click.pass_context
def invite(ctx: click.Context,
user_email):
user_profile = ctx.parent.obj['usercontext']
ctx.obj = {'resource_path': '/config/v1/invites/',
'usercontext': user_profile}
ProfileUserContext.update_context(user_profile,
useremail=user_email)


@click.command(help='Send invitation to a new user.')
@click.argument('email', metavar='USER_EMAIL')
@click.option('-r', '--role', 'roles', multiple=True, default=None, required=True,
help='Specify the role for the new user (can be used multiple times).')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def send(ctx: click.Context,
email,
roles):
resource_path = ctx.parent.obj.get('resource_path')
profile = ctx.parent.obj.get('usercontext')

org_id = profile.org_id
body = {
'email': email,
'org': org_id,
'roles': roles
}
basic_create_from_dict_body(profile, resource_path, body)
logger.info(f'Sent invitation to {email}')


@click.command(help='Resend invitation.')
@click.argument('email', metavar='USER_EMAIL')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def resend(ctx: click.Context,
email):
resource_path = ctx.parent.obj.get("resource_path")
profile = ctx.parent.obj.get('usercontext')

invite_id = json.loads(basic_show(profile,
resource_path,
email,
filter_field='email')).get('id')
if not invite_id:
logger.debug('An error occurred while obtaining the invite ID.')
raise ResourceNotFoundException('Cannot find the invitation ID.')

resource_path = f'{resource_path}{invite_id}/resend_invite/'

basic_create_from_dict_body(profile, resource_path, None)
logger.info(f'Resent invitation to {email}')


@click.command(help='List invites.', name='list')
@click.option('-p', '--pending', is_flag=True, default=False,
help='List only pending invitations.')
@click.pass_context
@report_error_and_exit(exctype=Exception)
def list_invites(ctx: click.Context,
pending: bool):
resource_path = ctx.parent.obj.get('resource_path')
profile = ctx.parent.obj.get('usercontext')

resources = get_resource_list(profile,
resource_path,
pending_only=pending)

_log_formatted_table_header({'email': 45, "status": 30})
for resource in resources:
roles_name = resource.get("roles")
logger.info(f'Email: {resource["email"]} | Roles: {(", ".join(roles_name))}')
logger.info(f'{resource["email"].ljust(45)}{resource.get("status").ljust(30)}')


user.add_command(list_)
user.add_command(invite)
def _log_formatted_table_header(headers_and_spacing: Dict[str, int]):
format_strings = []
values = headers_and_spacing.values()

logger.info(f'{"-" * sum(values)}')

for key, spacing in headers_and_spacing.items():
format_strings.append(f"{key:<{spacing}}")

logger.info(f'{"".join(format_strings)}')
logger.info(f'{"-" * sum(values)}')


user.add_command(list_users)
user.add_command(assign)
user.add_command(remove)
user.add_command(delete)
user.add_command(show)
user.add_command(invite)
invite.add_command(list_invites)
invite.add_command(show)
invite.add_command(delete)
invite.add_command(send)
invite.add_command(resend)
4 changes: 3 additions & 1 deletion src/hdx_cli/library_api/common/rest_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ def update_with_put(url, *,
def list(url, *,
headers,
fmt='json',
timeout):
timeout,
params=None):
result = requests.get(url,
headers=headers,
params=params,
timeout=timeout)
if result.status_code != 200:
raise HttpException(result.status_code, result.content)
Expand Down

0 comments on commit d9a5ec0

Please sign in to comment.