def _delete_entity_type_data(args): if args.force or (not args.force and mcmd.io.ask.confirm( 'Are you sure you want to delete all data in entity type {}?'. format(args.resource))): io.start('Deleting all data from entity {}'.format( highlight(args.resource))) client.delete(api.rest1(args.resource))
def add_theme(args): """ add_theme adds a theme to the stylesheet table :param args: commandline arguments containing bootstrap3_theme and optionally bootstrap4_theme :return: None """ _validate_args(args) valid_types = {'text/css'} api_ = api.add_theme() bs3_name = args.bootstrap3 bs4 = args.bootstrap4 paths = [bs3_name] names = ['bootstrap3-style'] if bs4: paths.append(bs4) names.append('bootstrap4-style') bs4_name = file_utils.get_file_name_from_path(bs4) io.start( 'Adding bootstrap 3 theme {} and bootstrap 4 theme {} to bootstrap themes' .format(highlight(bs3_name), highlight(bs4_name))) else: io.start('Adding bootstrap 3 theme {} to bootstrap themes'.format( highlight(bs3_name))) if not args.from_path: paths = [_get_path_from_quick_folders(theme) for theme in paths] files = _prepare_files_for_upload(paths, names, valid_types) post_files(files, api_)
def set_(args): """ set sets the specified row of the specified table (or setting of specified settings table) to the specified value :param args: command line arguments containing: the settings type, the setting to set, and the value to set it to, if not a setting also the --for (which row to alter) if --from-path or --from-resource is passed the value is assumed to be a file containing the value data to be set :return: None """ value = args.value value_desc = highlight(value) if args.from_path: path = Path(args.value) value = files.read_file(path) value_desc = 'contents of {}'.format(highlight(args.value)) elif args.from_resource: path = files.select_file_from_folders(context().get_resource_folders(), args.value) value = files.read_file(path) value_desc = 'contents of {}'.format(highlight(args.value)) if args.for_: entity = args.type row = args.for_ io.start('Updating {} of {} for id {} to {}'.format( highlight(args.attribute), highlight(args.type), highlight(args.for_), value_desc)) else: entity = _get_settings_entity(args.type) io.start('Updating {} of {} settings to {}'.format( highlight(args.attribute), highlight(args.type), value_desc)) row = _get_first_row_id(entity) url = api.rest1('{}/{}/{}'.format(entity, row, args.attribute)) put(url, json.dumps(value))
def _wait(wait: Wait, state: _ScriptExecutionState): text = '{}: {} {}'.format(bold('Waiting for user'), wait.message.render(state.values), dim('(Press enter to continue)')) io.start(text) io.wait_for_enter() io.succeed()
def _delete_package_contents(args): if args.force or (not args.force and mcmd.io.ask.confirm( 'Are you sure you want to delete the contents of package {}?'. format(args.resource))): io.start('Deleting contents of package {}'.format( highlight(args.resource))) _delete_entity_types_in_package(args.resource) _delete_packages_in_package(args.resource)
def _remove_script(script_name): path = context().get_scripts_folder().joinpath(script_name) _check_script_exists(path) try: io.start('Removing script %s' % highlight(script_name)) path.unlink() except OSError as e: raise McmdError('Error removing script: %s' % str(e))
def add_package(args): io.start('Adding package %s' % highlight(args.id)) data = {'id': args.id, 'label': args.id} if args.parent: data['parent'] = args.parent post(api.rest1('sys_md_Package'), data=data)
def _grant_rls(principal_type: PrincipalType, principal_name: str, entity_type_id: str, entity_id: str, permission: Permission): io.start('Giving %s %s permission to %s on row %s of entity type %s' % (principal_type.value, highlight(principal_name), highlight(permission.value), highlight(entity_id), highlight(entity_type_id))) security.grant_row_permission(principal_type, principal_name, entity_type_id, entity_id, permission)
def _add_role_membership(user: User, role: Role): """ Adds a membership manually because the identities API can't add memberships to non-group roles. """ io.start('Making user {} a member of role {}'.format( highlight(user.username), highlight(role.name))) membership = {'user': user.id, 'role': role.id, 'from': timestamp()} data = {'entities': [membership]} post(api.rest2('sys_sec_RoleMembership'), data=data)
def _grant(principal_type: PrincipalType, principal_name: str, resource_type: ResourceType, entity_type_id: str, permission: Permission): io.start('Giving %s %s permission to %s on %s %s' % (principal_type.value, highlight(principal_name), highlight(permission.value), resource_type.get_label().lower(), highlight(entity_type_id))) security.grant_permission(principal_type, principal_name, resource_type, entity_type_id, permission)
def config_set_host(args): if args.url: url = args.url else: auths = config.get('host', 'auth') urls = [auth['url'] for auth in auths] url = ask.multi_choice('Please select a host:', urls) io.start("Switching to host {}".format(highlight(url))) config.set_host(url)
def _include_group_role(subject: Role, target_role: Role): if not target_role.group: raise McmdError('Role {} is not a group role'.format(target_role.name)) if subject.name == target_role.name: raise McmdError("A role can't include itself") io.start('Including role {} in role {}'.format(highlight(target_role.name), highlight(subject.name))) include = {'role': target_role.name} put(api.role(target_role.group.name, subject.name), data=json.dumps(include))
def disable_rls(args): if not ask.confirm( 'Are you sure you want to disable row level security on %s?' % args.entity): return io.start('Disabling row level security on entity type %s' % highlight(args.entity)) ensure_resource_exists(args.entity, ResourceType.ENTITY_TYPE) security.disable_row_level_security(args.entity)
def history(args): if args.clear: io.start('Clearing history') hist.clear() else: lines = hist.read(args.number, include_fails=True) if len(lines) == 0: log.info('History is empty.') for line in lines: io.start(line[1]) if line[0]: io.succeed() else: io.error(None)
def _delete_entity_type_attribute(args): if args.force or (not args.force and mcmd.io.ask.confirm( 'Are you sure you want to delete attribute {} of entity type {}?'. format(args.attribute, args.resource))): io.start('Deleting attribute {} of entity {}'.format( highlight(args.attribute), highlight(args.resource))) response = client.get(api.rest2('sys_md_Attribute'), params={ 'q': 'entity=={};name=={}'.format( args.resource, args.attribute) }) attribute_id = response.json()['items'][0]['id'] client.delete(api.rest2('sys_md_Attribute/{}'.format(attribute_id)))
def add_role(args): role_name = to_role_name(args.rolename) io.start('Adding role {}'.format(highlight(role_name))) role = {'name': role_name, 'label': role_name} if args.includes: role_names = [to_role_name(name) for name in args.includes] role['includes'] = _get_role_ids(role_names) if args.group: group_name = _to_group_name(args.group) role['group'] = _get_group_id(group_name) data = {'entities': [role]} post(api.rest2('sys_sec_Role'), data=data)
def _add_host(): url = ask.input_("URL", required=True) if config.host_exists(url): raise McmdError("A host with URL {} already exists.".format(url)) username = ask.input_("Username (Default: admin)") password = ask.password( "Password (Leave blank to use command line authentication)") username = '******' if len(username) == 0 else username password = None if len(password) == 0 else password io.start("Adding host {}".format(highlight(url))) config.add_host(url, username, password) io.succeed() return url
def add_logo(args): """ add_logo uploads a logo to add to the left top of the menu :param args: commandline arguments containing path to logo :return: None """ api_ = api.logo() valid_types = {'image/jpeg', 'image/png', 'image/gif'} logo = [args.logo] if not args.from_path: io.start('Adding logo from path {}'.format(highlight(args.logo))) logo = [_get_path_from_quick_folders(args.logo)] else: io.start('Adding logo {}'.format(highlight(args.logo))) files = _prepare_files_for_upload(logo, ['logo'], valid_types) post_files(files, api_)
def add_token(args): io.start('Adding token %s for user %s' % (highlight(args.token), highlight(args.user))) user = get(api.rest2('sys_sec_User'), params={ 'attrs': 'id', 'q': 'username=={}'.format(args.user) }) if user.json()['total'] == 0: raise McmdError('Unknown user %s' % args.user) user_id = user.json()['items'][0]['id'] data = {'User': user_id, 'token': args.token} post(api.rest1('sys_sec_Token'), data=data)
def add_user(args): io.start('Adding user %s' % highlight(args.username)) password = args.set_password if args.set_password else args.username email = args.with_email if args.with_email else args.username + '@molgenis.org' active = not args.is_inactive superuser = args.is_superuser ch_pwd = args.change_password post(api.rest1('sys_sec_User'), data={ 'username': args.username, 'password_': password, 'changePassword': ch_pwd, 'Email': email, 'active': active, 'superuser': superuser })
def _do_import(file_path, package, entity_type_id): io.start('Importing %s' % (highlight(file_path.name))) params = { 'action': _get_import_action(file_path.name), 'metadataAction': 'upsert' } if package: params['packageId'] = package if entity_type_id: params['entityTypeId'] = entity_type_id response = post_file(api.import_(), file_path.resolve(), params) import_run_url = urljoin(config.get('host', 'selected'), response.text) status, message = _poll_for_completion(import_run_url) if status == 'FAILED': raise McmdError(message)
def _import_from_url(args): file_url = args.resource file_name = file_url.split("/")[-1] io.start('Importing from URL %s' % highlight(file_url)) params = { 'action': _get_import_action(file_name), 'metadataAction': 'upsert' } if args.to_package: params['packageId'] = args.to_package params['url'] = file_url response = post(api.import_by_url(), params=params) import_run_url = urljoin(config.get('host', 'selected'), response.text) status, message = _poll_for_completion(import_run_url) if status == 'FAILED': raise McmdError(message)
def _grant(principal_type, principal_name, resource_type, identifier, permission): data = {'radio-' + identifier: permission} if principal_type == PrincipalType.USER: data['username'] = principal_name elif principal_type == PrincipalType.ROLE: principal_name = to_role_name(principal_name) data['rolename'] = principal_name else: raise McmdError('Unknown principal type: %s' % principal_type) io.start('Giving %s %s permission to %s on %s %s' % (principal_type.value, highlight(principal_name), highlight(permission), resource_type.get_label().lower(), highlight(identifier))) url = urljoin( api.permissions(), '{}/{}'.format(resource_type.get_resource_name(), principal_type.value)) post_form(url, data)
def set_(args): """ set sets the specified row of the specified table (or setting of specified settings table) to the specified value :param args: command line arguments containing: the settings type, the setting to set, and the value to set it to, if not a setting also the --for (which row to alter) :return: None """ if args.for_: entity = args.type row = args.for_ io.start('Updating {} of {} for id {} to {}'.format( highlight(args.attribute), highlight(args.type), highlight(args.for_), highlight(args.value))) else: entity = _get_settings_entity(args.type) io.start('Updating {} of {} settings to {}'.format( highlight(args.attribute), highlight(args.type), highlight(args.value))) row = _get_first_row_id(entity) url = api.rest1('{}/{}/{}'.format(entity, row, args.attribute)) put(url, json.dumps(args.value))
def _download_attachment(attachment, issue_num): issue_folder = context().get_issues_folder().joinpath(issue_num) issue_folder.mkdir(parents=True, exist_ok=True) file_path = issue_folder.joinpath(attachment.name) if file_path.exists(): overwrite = mcmd.io.ask.confirm( 'File %s already exists. Re-download?' % file_path.name) if not overwrite: return file_path io.start('Downloading %s from GitHub issue %s' % (highlight(attachment.name), highlight('#' + issue_num))) try: r = requests.get(attachment.url) r.raise_for_status() with file_path.open('wb') as f: f.write(r.content) except (OSError, requests.RequestException, requests.HTTPError) as e: raise McmdError('Error downloading GitHub attachment: %s' % str(e)) io.succeed() return file_path
def enable_theme(args): """ enable_theme enables a bootstrap theme :param args: commandline arguments containing the id of the theme (without .css) :exception McmdError: when applying the theme fails :return None """ theme = args.theme.replace('.css', '').replace('.min', '') io.start('Applying theme {}'.format(highlight(theme))) # Resource can be bootstrap-name.min.css (if molgenis theme), or name.min.css (if uploaded .min.css), or # name.css (if uploaded as .css). if one_resource_exists([ theme + '.min.css', theme + '.css', 'bootstrap-' + theme + '.min.css' ], ResourceType.THEME): # Molgenis themes start with bootstrap- but this is stripped from the name in the theme manager try: post(api.set_theme(), data=theme) except: post(api.set_theme(), data=theme.split('bootstrap-')[1]) else: raise McmdError( 'Applying theme failed. No themes found containing {} in the name'. format(args.theme, 'sys_set_StyleSheet'))
def _add_group_role_membership(user: User, group: Group, role: Role): io.start('Making user {} a member of role {}'.format( highlight(user.username), highlight(role.name))) url = api.member(group.name) post(url, data={'username': user.username, 'roleName': role.name})
def _wait(message): text = '{}: {} {}'.format(bold('Waiting for user'), message, dim('(Press enter to continue)')) io.start(text) io.wait_for_enter() io.succeed()
def _update_group_role_membership(user: User, group: Group, role: Role): io.start('Making user {} a member of role {}'.format( highlight(user.username), highlight(role.name))) url = urljoin(api.member(group.name), user.username) put(url, data=json.dumps({'roleName': role.name}))
def add_group(args): group_name = _to_group_name(args.name) io.start('Adding group %s' % highlight(group_name)) post(api.group(), data={'name': group_name, 'label': args.name})