def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Remove %s Resource" % label output_objects.append({ 'object_type': 'header', 'text': 'Remove %s Resource' % label }) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] unique_resource_name = accepted['unique_resource_name'][-1].lower() if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append({ 'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label }) return (output_objects, returnvalues.CLIENT_ERROR) # make sure vgrid settings allow this owner to edit resources (allow_status, allow_msg) = allow_resources_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({'object_type': 'error_text', 'text': allow_msg}) return (output_objects, returnvalues.CLIENT_ERROR) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, ret_variables) = \ init_vgrid_script_add_rem(vgrid_name, client_id, unique_resource_name, 'resource', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) elif msg: # In case of warnings, msg is non-empty while ret_val remains True output_objects.append({'object_type': 'warning', 'text': msg}) if not vgrid_is_owner(vgrid_name, client_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': '''You must be an owner of the %s to remove a resource!''' % label }) return (output_objects, returnvalues.CLIENT_ERROR) # don't remove if not a participant if not vgrid_is_resource(vgrid_name, unique_resource_name, configuration): output_objects.append({ 'object_type': 'error_text', 'text': '%s is not a resource in %s or a parent %s.' % (unique_resource_name, vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) # remove (rm_status, rm_msg) = vgrid_remove_resources(configuration, vgrid_name, [unique_resource_name]) if not rm_status: output_objects.append({'object_type': 'error_text', 'text': rm_msg}) output_objects.append({ 'object_type': 'error_text', 'text': '''%(res_name)s might be listed as a resource of this %(vgrid_label)s because it is a resource of a parent %(vgrid_label)s. Removal must be performed from the most significant %(vgrid_label)s possible. ''' % { 'res_name': unique_resource_name, 'vgrid_label': label } }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': 'Resource %s successfully removed from %s %s!' % (unique_resource_name, vgrid_name, label) }) output_objects.append({ 'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name }) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Remove %s Owner" % label output_objects.append({'object_type': 'header', 'text': 'Remove %s Owner' % label}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] flags = ''.join(accepted['flags']) cert_id = accepted['cert_id'][-1] cert_dir = client_id_dir(cert_id) # inherited vgrid membership inherit_vgrid_member = False if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append( {'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) # always allow owner to remove self if client_id != cert_id: user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append( {'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label}) return (output_objects, returnvalues.CLIENT_ERROR) # make sure vgrid settings allow this owner to edit other owners (allow_status, allow_msg) = allow_owners_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({'object_type': 'error_text', 'text': allow_msg}) return (output_objects, returnvalues.CLIENT_ERROR) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'owner', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) # don't remove if not already an owner if not vgrid_is_owner(vgrid_name, cert_id, configuration): logger.warning('%s is not allowed to remove owner %s from %s' % (client_id, cert_id, vgrid_name)) output_objects.append({'object_type': 'error_text', 'text': '%s is not an owner of %s or a parent %s.' % (cert_id, vgrid_name, label)}) return (output_objects, returnvalues.CLIENT_ERROR) # we need the local owners file to detect inherited ownerships (owners_status, owners_direct) = vgrid_owners(vgrid_name, configuration, False) (all_status, owners) = vgrid_owners(vgrid_name, configuration, True) if not owners_status or not all_status: logger.error('Error loading owners for %s: %s / %s' % (vgrid_name, owners_direct, owners)) output_objects.append( {'object_type': 'error_text', 'text': 'An internal error occurred, error conditions have been logged.'}) output_objects.append({'object_type': 'text', 'text': ''' You can help us fix the problem by notifying the administrators via mail about what you wanted to do when the error happened.'''}) return (output_objects, returnvalues.CLIENT_ERROR) logger.info('%s removing owner %s from %s' % (client_id, cert_id, vgrid_name)) # find out whether to just remove an owner or delete the whole thing. # ask about delete if last or no direct owners. if len(owners_direct) > 1: logger.debug('Removing %s, one of several owners, from %s.' % (cert_id, vgrid_name)) if not (cert_id in owners_direct): # the owner owns an upper vgrid, ownership is inherited # cannot remove, not last (inherited) owner logger.warning('Cannot delete: Inherited ownership.' + '\n Owners: %s,\n Direct owners: %s.' % (owners, owners_direct)) output_objects.append({'object_type': 'error_text', 'text': '''%s is owner of a parent %s. Owner removal has to be performed at the topmost vgrid''' % (cert_id, label)}) return (output_objects, returnvalues.CLIENT_ERROR) else: # Remove any tracker admin rights if configuration.trac_admin_path: public_tracker_dir = \ os.path.abspath(os.path.join( configuration.vgrid_public_base, vgrid_name, '.vgridtracker')) private_tracker_dir = \ os.path.abspath(os.path.join( configuration.vgrid_private_base, vgrid_name, '.vgridtracker')) vgrid_tracker_dir = \ os.path.abspath(os.path.join( configuration.vgrid_files_home, vgrid_name, '.vgridtracker')) for tracker_dir in [public_tracker_dir, private_tracker_dir, vgrid_tracker_dir]: if not rm_tracker_admin(configuration, cert_id, vgrid_name, tracker_dir, output_objects): return (output_objects, returnvalues.SYSTEM_ERROR) user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep # Do not touch vgrid share if still a member of a parent vgrid if vgrid_is_member(vgrid_name, cert_id, configuration): # list is in top-down order parent_vgrids = vgrid_list_parents(vgrid_name, configuration) inherit_vgrid_member = vgrid_name for parent in parent_vgrids: if vgrid_is_member(parent, cert_id, configuration, recursive=False): inherit_vgrid_member = parent break output_objects.append( {'object_type': 'text', 'text': '''NOTE: %s is still a member of parent %s %s. Preserving access to corresponding %s.''' % (cert_id, label, inherit_vgrid_member, label)}) else: (success, msg) = unlink_share(user_dir, vgrid_name) if not success: logger.error('Could not remove share link: %s.' % msg) output_objects.append({'object_type': 'error_text', 'text': 'Could not remove share links: %s.' % msg}) return (output_objects, returnvalues.SYSTEM_ERROR) # unlink shared web folders (success, msg) = unlink_web_folders(user_dir, vgrid_name) if not success: logger.error('Could not remove web links: %s.' % msg) output_objects.append({'object_type': 'error_text', 'text': 'Could not remove web links: %s.' % msg}) return (output_objects, returnvalues.SYSTEM_ERROR) # remove user from saved owners list (rm_status, rm_msg) = vgrid_remove_owners(configuration, vgrid_name, [cert_id]) if not rm_status: output_objects.append({'object_type': 'error_text', 'text': '%s of owners of %s' % (rm_msg, vgrid_name)}) return (output_objects, returnvalues.SYSTEM_ERROR) # Any parent vgrid membership is left untouched here as we only # force a normal refresh in unmap_inheritance unmap_inheritance(configuration, vgrid_name, cert_id) output_objects.append({'object_type': 'text', 'text': '%s successfully removed as owner of %s!' % (cert_id, vgrid_name)}) output_objects.append({'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name}) return (output_objects, returnvalues.OK) else: # no more direct owners - we try to remove this VGrid logger.debug('Leave %s from %s with no more direct owners: delete' % (vgrid_name, cert_id)) if not force(flags): output_objects.append({'object_type': 'text', 'text': ''' No more direct owners of %s - leaving will result in the %s getting deleted. Please use either of the links below to confirm or cancel. ''' % (vgrid_name, label)}) # Reuse csrf token from this request target_op = 'rmvgridowner' js_name = target_op csrf_token = accepted[csrf_field][-1] helper = html_post_helper(js_name, '%s.py' % target_op, {'vgrid_name': vgrid_name, 'cert_id': cert_id, 'flags': 'f', csrf_field: csrf_token}) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({'object_type': 'link', 'destination': "javascript: %s();" % js_name, 'class': 'removelink iconspace', 'text': 'Really leave and delete %s' % vgrid_name}) output_objects.append({'object_type': 'text', 'text': ''}) output_objects.append({'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name}) return (output_objects, returnvalues.OK) # check if any resources participate or sub-vgrids depend on this one (list_status, subs) = vgrid_list_subvgrids(vgrid_name, configuration) if not list_status: logger.error('Error loading sub-vgrid for %s: %s)' % (vgrid_name, subs)) output_objects.append({'object_type': 'error_text', 'text': ''' An internal error occurred, error conditions have been logged.'''}) output_objects.append({'object_type': 'text', 'text': ''' You can help us fix the problem by notifying the administrators via mail about what you wanted to do when the error happened.'''}) return (output_objects, returnvalues.CLIENT_ERROR) if len(subs) > 0: logger.debug('Cannot delete: still has sub-vgrids: %s' % subs) output_objects.append( {'object_type': 'error_text', 'text': '%s has one or more child %ss and cannot be deleted.' % (vgrid_name, label)}) output_objects.append( {'object_type': 'text', 'text': '''To leave (and delete) %s first remove all its children: %s.''' % (vgrid_name, ', '.join(subs))}) return (output_objects, returnvalues.CLIENT_ERROR) # we consider the local members and resources here, not inherited ones (member_status, members_direct) = vgrid_members(vgrid_name, configuration, False) (resource_status, resources_direct) = vgrid_resources(vgrid_name, configuration, False) if not member_status or not resource_status: logger.warning('failed to load %s members or resources: %s %s' % (vgrid_name, members_direct, resources_direct)) output_objects.append( {'object_type': 'error_text', 'text': 'could not load %s members or resources for %s.' % (label, vgrid_name)}) return (output_objects, returnvalues.SYSTEM_ERROR) if len(resources_direct) > 0: logger.debug('Cannot delete: still has direct resources %s.' % resources_direct) output_objects.append( {'object_type': 'error_text', 'text': '%s still has resources and cannot be deleted.' % vgrid_name}) output_objects.append({'object_type': 'text', 'text': ''' To leave (and delete) %s, first remove the participating resources.''' % vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) if len(members_direct) > 0: logger.debug('Cannot delete: still has direct members %s.' % members_direct) output_objects.append( {'object_type': 'error_text', 'text': '%s still has members and cannot be deleted.' % vgrid_name}) output_objects.append({'object_type': 'text', 'text': ''' To leave (and delete) %s, first remove all members.''' % vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) # Deleting write restricted VGrid is not allowed (load_status, saved_settings) = vgrid_settings(vgrid_name, configuration, recursive=True, as_dict=True) if not load_status: output_objects.append( {'object_type': 'error_text', 'text': 'failed to load saved %s settings' % vgrid_name}) return (output_objects, returnvalues.SYSTEM_ERROR) if saved_settings.get('write_shared_files', keyword_members) != \ keyword_members: logger.warning("%s can't delete vgrid %s - write limited!" % (client_id, vgrid_name)) output_objects.append( {'object_type': 'error_text', 'text': """You can't delete write-restricted %ss - first remove any write restrictions for shared files on the admin page and then try again.""" % label}) return (output_objects, returnvalues.CLIENT_ERROR) # When reaching here, OK to remove the VGrid. # if top-level: unlink, remove all files and directories, # in all cases: remove configuration entry for the VGrid # unlink and move new-style vgrid sub dir to parent logger.info('Deleting %s and all related data as requested by %s' % (vgrid_name, cert_id)) if (cert_id in owners_direct): # owner owns this vgrid, direct ownership logger.debug('%s looks like a top-level vgrid.' % vgrid_name) logger.debug('Deleting all related files.') user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep (share_lnk, share_msg) = unlink_share(user_dir, vgrid_name) (web_lnk, web_msg) = unlink_web_folders(user_dir, vgrid_name) (files_act, files_msg) = abandon_vgrid_files(vgrid_name, configuration) else: # owner owns some parent vgrid - ownership is only inherited logger.debug('%s looks like a sub-vgrid, ownership inherited.' % vgrid_name) logger.debug('Only removing entry, leaving files in place.') share_lnk, share_msg = True, '' web_lnk, web_msg = True, '' (files_act, files_msg) = inherit_vgrid_files(vgrid_name, configuration) (removed, entry_msg) = remove_vgrid_entry(vgrid_name, configuration) output_objects.append({'object_type': 'text', 'text': '%s has been removed with last owner.' % vgrid_name}) output_objects.append({'object_type': 'link', 'destination': 'vgridman.py', 'text': 'Back to the overview.'}) if not share_lnk or not web_lnk or not files_act or not removed: err = '\n'.join([share_msg, web_msg, files_msg, entry_msg]) logger.error('Errors while removing %s:\n%s.' % (vgrid_name, err)) output_objects.append({'object_type': 'error_text', 'text': ''' An internal error occurred, error conditions have been logged.'''}) output_objects.append({'object_type': 'text', 'text': ''' You can help us fix the problem by notifying the administrators via mail about what you wanted to do when the error happened.'''}) return (output_objects, returnvalues.CLIENT_ERROR) else: # Remove vgrid from vgrid cache (after deleting all) unmap_vgrid(configuration, vgrid_name) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Add %s Member" % label output_objects.append({'object_type': 'header', 'text': 'Add %s Member(s)' % label}) status = returnvalues.OK (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() cert_id_list = accepted['cert_id'] request_name = unhexlify(accepted['request_name'][-1]) rank_list = accepted['rank'] + ['' for _ in cert_id_list] if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append( {'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append( {'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label}) return (output_objects, returnvalues.CLIENT_ERROR) # make sure vgrid settings allow this owner to edit members (allow_status, allow_msg) = allow_members_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({'object_type': 'error_text', 'text': allow_msg}) return (output_objects, returnvalues.CLIENT_ERROR) cert_id_added = [] for (cert_id, rank_str) in zip(cert_id_list, rank_list): cert_id = cert_id.strip() cert_dir = client_id_dir(cert_id) try: rank = int(rank_str) except ValueError: rank = None # Allow openid alias as subject if openid with alias is enabled if configuration.user_openid_providers and configuration.user_openid_alias: cert_id = expand_openid_alias(cert_id, configuration) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'member', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) status = returnvalues.CLIENT_ERROR continue # don't add if already an owner if vgrid_is_owner(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text': '%s is already an owner of %s or a parent %s.' % (cert_id, vgrid_name, label)}) status = returnvalues.CLIENT_ERROR continue # don't add if already a member unless rank is given if rank is None and vgrid_is_member(vgrid_name, cert_id, configuration): output_objects.append( {'object_type': 'error_text', 'text': '''%s is already a member of %s or a parent %s. Please remove the person first and then try this operation again.''' % (cert_id, vgrid_name, label) }) status = returnvalues.CLIENT_ERROR continue # owner or member of subvgrid? (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration) if not list_status: output_objects.append({'object_type': 'error_text', 'text': 'Error getting list of sub%ss: %s' % (label, subvgrids)}) status = returnvalues.SYSTEM_ERROR continue # TODO: we DO allow ownership of sub vgrids with parent membership so we # should support the (cumbersome) relinking of vgrid shares here. Leave it # to user to do it manually for now with temporary removal of ownership skip_entity = False for subvgrid in subvgrids: if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text': """%(cert_id)s is already an owner of a sub-%(vgrid_label)s ('%(subvgrid)s'). While we DO support members being owners of sub-%(vgrid_label)ss, we do not support adding parent %(vgrid_label)s members at the moment. Please (temporarily) remove the person as owner of all sub-%(vgrid_label)ss first and then try this operation again.""" % {'cert_id': cert_id, 'subvgrid': subvgrid, 'vgrid_label': label}}) status = returnvalues.CLIENT_ERROR skip_entity = True break if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False): output_objects.append( {'object_type': 'error_text', 'text': """%s is already a member of a sub-%s ('%s'). Please remove the person first and then try this operation again.""" % (cert_id, label, subvgrid)}) status = returnvalues.CLIENT_ERROR skip_entity = True break if skip_entity: continue # Check if only rank change was requested and apply if so if rank is not None: (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name, [cert_id], rank=rank) if not add_status: output_objects.append( {'object_type': 'error_text', 'text': add_msg}) status = returnvalues.SYSTEM_ERROR else: output_objects.append({'object_type': 'text', 'text': 'changed %s to member %d' % (cert_id, rank)}) # No further action after rank change as everything else exists continue # Getting here means cert_id is neither owner or member of any parent or # sub-vgrids. # Please note that base_dir must end in slash to avoid access to other # vgrid dirs when own name is a prefix of another name base_dir = os.path.abspath(os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep # make sure all dirs can be created (that a file or directory with the same # name do not exist prior to adding the member) if os.path.exists(user_dir + vgrid_name): output_objects.append( {'object_type': 'error_text', 'text': '''Could not add member, a file or directory in the home directory called %s exists! (%s)''' % (vgrid_name, user_dir + vgrid_name)}) status = returnvalues.CLIENT_ERROR continue # Add (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name, [cert_id]) if not add_status: output_objects.append( {'object_type': 'error_text', 'text': add_msg}) status = returnvalues.SYSTEM_ERROR continue vgrid_name_parts = vgrid_name.split('/') is_subvgrid = len(vgrid_name_parts) > 1 if is_subvgrid: try: # vgrid_name = IMADA/STUD/BACH # vgrid_name_last_fragment = BACH vgrid_name_last_fragment = \ vgrid_name_parts[len(vgrid_name_parts) - 1].strip() # vgrid_name_without_last_fragment = IMADA/STUD/ vgrid_name_without_last_fragment = \ ('/'.join(vgrid_name_parts[0:len(vgrid_name_parts) - 1]) + os.sep).strip() # create dirs if they do not exist dir1 = user_dir + vgrid_name_without_last_fragment if not os.path.isdir(dir1): os.makedirs(dir1) except Exception, exc: # out of range? should not be possible due to is_subvgrid check output_objects.append( {'object_type': 'error_text', 'text': ('Could not create needed dirs on %s server! %s' % (configuration.short_title, exc))}) logger.error('%s when looking for dir %s.' % (exc, dir1)) status = returnvalues.SYSTEM_ERROR continue # create symlink from users home directory to vgrid file directory link_src = os.path.abspath(configuration.vgrid_files_home + os.sep + vgrid_name) + os.sep link_dst = user_dir + vgrid_name # create symlink to vgrid files if not make_symlink(link_src, link_dst, logger): output_objects.append({'object_type': 'error_text', 'text': 'Could not create link to %s files!' % label }) logger.error('Could not create link to %s files! (%s -> %s)' % (label, link_src, link_dst)) status = returnvalues.SYSTEM_ERROR continue cert_id_added.append(cert_id)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) logger.debug("User: %s executing %s" % (client_id, op_name)) if not configuration.site_enable_cloud: output_objects.append({ 'object_type': 'error_text', 'text': 'The cloud service is not enabled on the system' }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'header', 'text': 'Cloud Instance Management' }) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of cload access vgrid permission if not user_dict or not cloud_access_allowed(configuration, user_dict): output_objects.append({ 'object_type': 'error_text', 'text': "You don't have permission to access the cloud facilities on " "this site" }) return (output_objects, returnvalues.CLIENT_ERROR) return_status = returnvalues.OK action = accepted['action'][-1] # NOTE: instance_X may be empty list - fall back to empty string instance_id = ([''] + accepted['instance_id'])[-1] instance_label = ([''] + accepted['instance_label'])[-1] instance_image = ([''] + accepted['instance_image'])[-1] accept_terms = (([''] + accepted['accept_terms'])[-1] in ('yes', 'on')) cloud_id = accepted['service'][-1] service = { k: v for options in configuration.cloud_services for k, v in options.items() if options['service_name'] == cloud_id } if not service: valid_services = [ options['service_name'] for options in configuration.cloud_services ] output_objects.append({ 'object_type': 'error_text', 'text': '%s is not among the valid cloud services: %s' % (cloud_id, ', '.join(valid_services)) }) return (output_objects, returnvalues.CLIENT_ERROR) valid_service = valid_cloud_service(configuration, service) if not valid_service: output_objects.append({ 'object_type': 'error_text', 'text': 'The service %s appears to be misconfigured, ' 'please contact a system administrator about this issue' % cloud_id }) return (output_objects, returnvalues.SYSTEM_ERROR) service_title = service['service_title'] if not action in valid_actions: output_objects.append({ 'object_type': 'error_text', 'text': '%s is not a valid action ' 'allowed actions include %s' % (action, ', '.join(valid_actions)) }) return (output_objects, returnvalues.CLIENT_ERROR) elif action in cloud_edit_actions: if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) cloud_flavor = service.get("service_flavor", "openstack") user_home_dir = os.path.join(configuration.user_home, client_dir) client_email = extract_field(client_id, 'email') if not client_email: logger.error("could not extract client email for %s!" % client_id) output_objects.append({ 'object_type': 'error_text', 'text': "No client ID found - can't continue" }) return (output_objects, returnvalues.SYSTEM_ERROR) ssh_auth_msg = "Login requires your private key for your public key:" instance_missing_msg = "Found no '%s' instance at %s. Please contact a " \ + "site administrator if it should be there." _label = instance_label if instance_id and not _label: _, _label, _ = cloud_split_instance_id(configuration, client_id, instance_id) if "create" == action: if not accept_terms: logger.error("refusing create without accepting terms for %s!" % client_id) output_objects.append({ 'object_type': 'error_text', 'text': "You MUST accept the cloud user terms to create instances" }) return (output_objects, returnvalues.CLIENT_ERROR) # Load all instances and make sure none contains label in ID saved_instances = cloud_load_instance(configuration, client_id, cloud_id, keyword_all) for (saved_id, instance) in saved_instances.items(): if instance_label == instance.get('INSTANCE_LABEL', saved_id): logger.error("Refused %s re-create %s cloud instance %s!" % (client_id, cloud_id, instance_label)) output_objects.append({ 'object_type': 'error_text', 'text': "You already have an instance with the label '%s'!" % instance_label }) return (output_objects, returnvalues.CLIENT_ERROR) max_instances = lookup_user_service_value( configuration, client_id, service, 'service_max_user_instances') max_user_instances = int(max_instances) # NOTE: a negative max value means unlimited but 0 or more is enforced if max_user_instances >= 0 and \ len(saved_instances) >= max_user_instances: logger.error("Refused %s create additional %s cloud instances!" % (client_id, cloud_id)) output_objects.append({ 'object_type': 'error_text', 'text': "You already have the maximum allowed %s instances (%d)!" % (service_title, max_user_instances) }) return (output_objects, returnvalues.CLIENT_ERROR) if not instance_label: logger.error("Refused %s create unlabelled %s cloud instance!" % (client_id, cloud_id)) output_objects.append({ 'object_type': 'error_text', 'text': "No instance label provided!" }) return (output_objects, returnvalues.CLIENT_ERROR) # Lookup user-specific allowed images (colon-separated image names) allowed_images = allowed_cloud_images(configuration, client_id, cloud_id, cloud_flavor) if not allowed_images: output_objects.append({ 'object_type': 'error_text', 'text': "No valid / allowed cloud images found!" }) return (output_objects, returnvalues.CLIENT_ERROR) if not instance_image: instance_image = allowed_images[0] logger.info("No image specified - using first for %s in %s: %s" % (client_id, cloud_id, instance_image)) image_id = None for (img_name, img_id, img_alias) in allowed_images: if instance_image == img_name: image_id = img_id break if not image_id: logger.error("No matching image ID found for %s in %s: %s" % (client_id, cloud_id, instance_image)) output_objects.append({ 'object_type': 'error_text', 'text': "No such image found: %s" % instance_image }) return (output_objects, returnvalues.CLIENT_ERROR) # TODO: remove this direct key injection if we can delay it cloud_settings = load_cloud(client_id, configuration) raw_keys = cloud_settings.get('authkeys', '').split('\n') auth_keys = [i.split('#', 1)[0].strip() for i in raw_keys] auth_keys = [i for i in auth_keys if i] if not auth_keys: logger.error("No cloud pub keys setup for %s - refuse create" % client_id) output_objects.append({ 'object_type': 'error_text', 'text': """ You haven't provided any valid ssh pub key(s) for cloud instance login, which is stricly required for all use. Please do so before you try again. """ }) output_objects.append({ 'object_type': 'link', 'destination': 'setup.py?topic=cloud', 'text': 'Open cloud setup', 'class': 'cloudsetuplink iconspace', 'title': 'open cloud setup', 'target': '_blank' }) return (output_objects, returnvalues.CLIENT_ERROR) logger.debug("Continue create for %s with auth_keys: %s" % (client_id, auth_keys)) # Create a new internal keyset and session id (priv_key, pub_key) = generate_ssh_rsa_key_pair(encode_utf8=True) session_id = generate_random_ascii(session_id_bytes, charset='0123456789abcdef') # We make sure to create instance with a globally unique ID on the # cloud while only showing the requested instance_label to the user. instance_id = cloud_build_instance_id(configuration, client_email, instance_label, session_id) # TODO: make more fields flexible/conf cloud_dict = { 'INSTANCE_ID': instance_id, 'INSTANCE_LABEL': instance_label, 'INSTANCE_IMAGE': instance_image, 'IMAGE_ID': image_id, 'AUTH_KEYS': auth_keys, 'USER_CERT': client_id, 'INSTANCE_PRIVATE_KEY': priv_key, 'INSTANCE_PUBLIC_KEY': pub_key, # don't need fraction precision, also not all systems provide fraction # precision. 'CREATED_TIMESTAMP': int(time.time()), # Init unset ssh address and leave for floating IP assigment below 'INSTANCE_SSH_IP': '', 'INSTANCE_SSH_PORT': 22, } (action_status, action_msg) = create_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id, image_id, auth_keys) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, instance_label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) # On success the action_msg contains the assigned floating IP address instance_ssh_fqdn = action_msg cloud_dict['INSTANCE_SSH_IP'] = instance_ssh_fqdn if not cloud_save_instance(configuration, client_id, cloud_id, instance_id, cloud_dict): logger.error("save new %s cloud instance %s for %s failed" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': 'Error saving your %s cloud instance setup' % service_title }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, instance_label, service_title, "success") }) output_objects.append({ 'object_type': 'html_form', 'text': _ssh_help(configuration, client_id, cloud_id, cloud_dict, instance_id) }) elif "delete" == action: saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to delete" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) (action_status, action_msg) = delete_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) if not cloud_purge_instance(configuration, client_id, cloud_id, instance_id): logger.error("purge %s cloud instance %s for %s failed" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': 'Error deleting your %s cloud instance setup' % service_title }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, _label, service_title, "success") }) elif "status" == action: saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to query" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) (action_status, action_msg) = status_of_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, _label, service_title, action_msg) }) # Show instance access details if running if action_msg in ('ACTIVE', 'RUNNING'): # Only include web console if explicitly configured if configuration.user_cloud_console_access: (console_status, console_msg) = web_access_cloud_instance( configuration, client_id, cloud_id, cloud_flavor, instance_id) if not console_status: logger.error( "%s cloud instance %s console for %s failed: %s" % \ (cloud_id, instance_id, client_id, console_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Failed to get instance %s at %s console: %s' % (_label, service_title, console_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) logger.info("%s cloud instance %s console for %s: %s" % (cloud_id, instance_id, client_id, console_msg)) output_objects.append({ 'object_type': 'link', 'destination': console_msg, 'text': 'Open web console', 'class': 'consolelink iconspace', 'title': 'open web console', 'target': '_blank' }) output_objects.append({'object_type': 'text', 'text': ''}) output_objects.append({ 'object_type': 'html_form', 'text': _ssh_help(configuration, client_id, cloud_id, saved_instance, instance_id) }) output_objects.append({'object_type': 'text', 'text': ''}) elif "start" == action: saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to start" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) (action_status, action_msg) = start_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, _label, service_title, "success") }) output_objects.append({ 'object_type': 'html_form', 'text': _ssh_help(configuration, client_id, cloud_id, saved_instance, instance_id) }) elif action in ("softrestart", "hardrestart"): boot_strength = action.replace("restart", "").upper() saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to restart" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) (action_status, action_msg) = restart_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id, boot_strength) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, _label, service_title, "success") }) output_objects.append({ 'object_type': 'html_form', 'text': _ssh_help(configuration, client_id, cloud_id, saved_instance, instance_id) }) elif "stop" == action: saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to %s" % (cloud_id, instance_id, client_id, action)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) (action_status, action_msg) = stop_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, _label, service_title, "success") }) elif "webaccess" == action: saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to query" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) if not configuration.user_cloud_console_access: logger.error("web console not enabled in conf!") output_objects.append({ 'object_type': 'error_text', 'text': 'Site does not expose cloud web console!' }) return (output_objects, returnvalues.CLIENT_ERROR) (action_status, action_msg) = web_access_cloud_instance(configuration, client_id, cloud_id, cloud_flavor, instance_id) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, service_title, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s" % (action, _label, service_title) }) output_objects.append({ 'object_type': 'link', 'destination': action_msg, 'text': 'Open web console', 'class': 'consolelink iconspace', 'title': 'open web console', 'target': '_blank' }) output_objects.append({'object_type': 'text', 'text': ''}) output_objects.append({ 'object_type': 'html_form', 'text': _ssh_help(configuration, client_id, cloud_id, saved_instance, instance_id) }) elif "updatekeys" == action: saved_instance = cloud_load_instance(configuration, client_id, cloud_id, instance_id) if not saved_instance: logger.error("no saved %s cloud instance %s for %s to update" % (cloud_id, instance_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': instance_missing_msg % (_label, service_title) }) return (output_objects, returnvalues.CLIENT_ERROR) cloud_settings = load_cloud(client_id, configuration) auth_keys = cloud_settings.get('authkeys', '').split('\n') (action_status, action_msg) = update_cloud_instance_keys(configuration, client_id, cloud_id, cloud_flavor, instance_id, auth_keys) if not action_status: logger.error( "%s %s cloud instance %s for %s failed: %s" % (action, cloud_id, instance_id, client_id, action_msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Your %s instance %s at %s did not succeed: %s' % (action, _label, service_title, action_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'text', 'text': "%s instance %s at %s: %s" % (action, _label, service_title, "success") }) output_objects.append({ 'object_type': 'html_form', 'text': _ssh_help(configuration, client_id, cloud_id, saved_instance, instance_id) }) output_objects.append({'object_type': 'text', 'text': ssh_auth_msg}) for pub_key in auth_keys: output_objects.append({'object_type': 'text', 'text': pub_key}) else: output_objects.append({ 'object_type': 'error_text', 'text': 'Unknown action: %s' % action }) return_status = returnvalues.CLIENT_ERROR output_objects.append({ 'object_type': 'link', 'destination': 'cloud.py', 'class': 'backlink iconspace', 'title': 'Go back to cloud management', 'text': 'Back to cloud management' }) return (output_objects, return_status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Remove %s Member" % label output_objects.append({ 'object_type': 'header', 'text': 'Remove %s Member' % label }) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] cert_id = accepted['cert_id'][-1] cert_dir = client_id_dir(cert_id) if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) # always allow member to remove self if client_id != cert_id: user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append({ 'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label }) return (output_objects, returnvalues.CLIENT_ERROR) # make sure vgrid settings allow this owner to edit other members (allow_status, allow_msg) = allow_members_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({ 'object_type': 'error_text', 'text': allow_msg }) return (output_objects, returnvalues.CLIENT_ERROR) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'member', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) # don't remove if not a member if not vgrid_is_member(vgrid_name, cert_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': '%s is not a member of %s or a parent %s.' % (cert_id, vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) # owner of subvgrid? (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration) if not list_status: output_objects.append({ 'object_type': 'error_text', 'text': 'Error getting list of sub%ss: %s' % (label, subvgrids) }) return (output_objects, returnvalues.SYSTEM_ERROR) # TODO: we DO allow ownership of sub vgrids with parent membership so we # should support the (cumbersome) relinking of vgrid shares here. Leave it # to user to do it manually for now with temporary removal of ownership for subvgrid in subvgrids: if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False): output_objects.append({ 'object_type': 'error_text', 'text': """%(cert_id)s is already an owner of a sub-%(vgrid_label)s ('%(subvgrid)s'). While we DO support members being owners of sub-%(vgrid_label)ss, we do not support removing parent %(vgrid_label)s members at the moment. Please (temporarily) remove the person as owner of all sub-%(vgrid_label)ss first and then try this operation again.""" % { 'cert_id': cert_id, 'subvgrid': subvgrid, 'vgrid_label': label } }) return (output_objects, returnvalues.CLIENT_ERROR) # Please note that base_dir must end in slash to avoid access to other # vgrid dirs when own name is a prefix of another name base_dir = os.path.abspath( os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep # remove symlink from users home directory to vgrid directory # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep dst = user_dir + vgrid_name try: os.remove(dst) except Exception, exc: # ouch, not good. Email admin? pass
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) logger.debug("User: %s executing %s", client_id, op_name) if not configuration.site_enable_cloud: output_objects.append({ 'object_type': 'error_text', 'text': 'The cloud service is not enabled on the system' }) return (output_objects, returnvalues.SYSTEM_ERROR) status = returnvalues.OK user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of cloud access permission if not user_dict or not cloud_access_allowed(configuration, user_dict): output_objects.append({ 'object_type': 'error_text', 'text': "You don't have permission to access the cloud facilities on " "this site" }) return (output_objects, returnvalues.CLIENT_ERROR) services = configuration.cloud_services # Show cloud services menu (add_import, add_init, add_ready) = man_base_js(configuration, []) add_init += ''' function get_instance_id() { console.log("in get_instance_id"); console.log("found val: "+$("#select-instance-id").val()); return $("#select-instance-id").val(); } function get_instance_label() { console.log("in get_instance_label"); console.log("found val: "+$("#select-instance-id > option:selected").text()); return $("#select-instance-id > option:selected").text(); } ''' add_ready += ''' /* NOTE: requires managers CSS fix for proper tab bar height */ $(".cloud-tabs").tabs(); ''' title_entry = find_entry(output_objects, 'title') title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({ 'object_type': 'html_form', 'text': man_base_html(configuration) }) output_objects.append({ 'object_type': 'header', 'text': 'Select a Cloud Service' }) fill_helpers = { 'cloud_tabs': ''.join([ '<li><a href="#%s-tab">%s</a></li>' % (service['service_name'], service['service_title']) for service in services ]) } output_objects.append({ 'object_type': 'html_form', 'text': ''' <div id="wrap-tabs" class="cloud-tabs"> <ul> %(cloud_tabs)s </ul> ''' % fill_helpers }) form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'site': configuration.short_title, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } target_op = 'reqcloudservice' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) action_list = [ ('start', 'Start'), ('stop', 'Stop'), ('softrestart', 'Soft boot'), ('hardrestart', 'Hard boot'), ('status', 'Status'), # NOTE: expose console on status page #('webaccess', 'Console'), ('updatekeys', 'Set keys on'), ('create', 'Create'), ('delete', 'Delete') ] # Delete instance form helper shared for all cloud services helper = html_post_helper( "%s" % target_op, '%s.py' % target_op, { 'instance_id': '__DYNAMIC__', 'service': '__DYNAMIC__', 'action': 'delete', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) for service in services: logger.debug("service: %s" % service) cloud_id = service['service_name'] cloud_title = service['service_title'] rules_of_conduct = service['service_rules_of_conduct'] cloud_flavor = service.get("service_provider_flavor", "openstack") output_objects.append({ 'object_type': 'html_form', 'text': ''' <div id="%s-tab"> ''' % cloud_id }) if service['service_desc']: output_objects.append({ 'object_type': 'sectionheader', 'text': 'Service Description' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <div class="cloud-description"> <span>%s</span> </div> ''' % service['service_desc'] }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <br/> ''' }) if not check_cloud_available(configuration, client_id, cloud_id, cloud_flavor): logger.error("Failed to connect to cloud: %s" % cloud_id) output_objects.append( {'object_type': 'error_text', 'text': 'The %s cloud service is currently unavailable' % \ cloud_title}) output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) status = returnvalues.SYSTEM_ERROR continue # Lookup user-specific allowed images (colon-separated image names) allowed_images = allowed_cloud_images(configuration, client_id, cloud_id, cloud_flavor) if not allowed_images: output_objects.append({ 'object_type': 'error_text', 'text': "No valid instance images for %s" % cloud_title }) output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) continue fill_helpers.update({ 'cloud_id': cloud_id, 'cloud_title': cloud_title, 'target_op': target_op, 'rules_of_conduct': rules_of_conduct }) delete_html = "" # Manage existing instances saved_instances = cloud_load_instance(configuration, client_id, cloud_id, keyword_all) saved_fields = ['INSTANCE_IMAGE'] instance_fields = ['public_fqdn', 'status'] status_map = status_all_cloud_instances(configuration, client_id, cloud_id, cloud_flavor, saved_instances.keys(), instance_fields) # TODO: halfwidth styling does not really work on select elements delete_html += """ <div class='cloud-instance-delete fillwidth'> <h3>Permanently delete a %(cloud_title)s cloud instance</h3> <form class='delete-cloud-instance' target='#'> <p class='cloud-instance-input fillwidth'> <label class='fieldlabel halfwidth'>Instance</label> <span class='halfwidth'> <select id='select-instance-id' class='styled-select html-select halfwidth padspace' name='instance_id'> """ % fill_helpers output_objects.append({ 'object_type': 'html_form', 'text': """ <div class='cloud-management fillwidth'> <h3>Manage %(cloud_title)s instances</h3> <br/> <div class='cloud-instance-grid'> <div class='cloud-instance-grid-left'> <label class='fieldlabel fieldheader'>Name</label> </div> <div class='cloud-instance-grid-middle'> <label class='fieldlabel fieldheader'>Instance Details</label> </div> <div class='cloud-instance-grid-right'> <label class='fieldlabel fieldheader'>Actions</label> </div> """ % fill_helpers }) for (instance_id, instance_dict) in saved_instances.items(): instance_label = instance_dict.get('INSTANCE_LABEL', instance_id) logger.debug("Management entries for %s %s cloud instance %s" % (client_id, cloud_id, instance_id)) instance_html = """ <div class='cloud-instance-grid-left'> <label class='fieldlabel'>%s</label> </div> <div class='cloud-instance-grid-middle'> """ % instance_label for field in saved_fields: field_val = saved_instances[instance_id].get(field, "-") if field == 'INSTANCE_IMAGE': for (img_name, _, img_alias) in allowed_images: if img_name == field_val: field_val = img_alias instance_html += """ <span class='fieldstatus entry leftpad'>%s</span> """ % field_val for field in instance_fields: field_val = status_map[instance_id].get(field, "-") instance_html += """ <span class='fieldstatus entry leftpad'>%s</span> """ % field_val instance_html += """ </div> <div class='cloud-instance-grid-right'> """ output_objects.append({ 'object_type': 'html_form', 'text': instance_html }) for (action, title) in action_list: if action in cloud_edit_actions: continue query = 'action=%s;service=%s;instance_id=%s' % \ (action, cloud_id, instance_id) url = 'reqcloudservice.py?%s' % query #output_service = { # 'object_type': 'service', # 'name': "%s" % title, # 'targetlink': url #} #output_objects.append(output_service) output_objects.append({ 'object_type': 'link', 'destination': url, 'text': title, 'class': 'ui-button', 'title': '%s %s' % (title, instance_label) }) output_objects.append({ 'object_type': 'html_form', 'text': """ </div> """ }) delete_html += """<option value='%s'>%s</option> """ % (instance_id, instance_label) output_objects.append({ 'object_type': 'html_form', 'text': """ </div> </div> """ }) delete_html += """ </select> </span> </p> <p class='fillwidth'> <input type='submit' value='Delete Instance' onClick='javascript:confirmDialog(%(target_op)s, \"Really permanently delete your %(cloud_title)s \"+get_instance_label()+\" instance including all local data?\", undefined, {instance_id: get_instance_id(), service: \"%(cloud_id)s\"}); return false;' /> </p> </form> </div> """ % fill_helpers # Create new instance create_html = """ <div class='cloud-instance-create fillwidth'> <h3>Create a new %(cloud_title)s cloud instance</h3> <form class='create_cloud_instance' method='%(form_method)s' action='%(target_op)s.py'> <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' /> <input type='hidden' name='service' value='%(cloud_id)s' /> <input type='hidden' name='action' value='create' /> <p class='cloud-instance-input fillwidth'> <label class='fieldlabel halfwidth'>Label</label> <span class='halfwidth'> <input class='halfwidth padspace' type='text' name='instance_label' value='' /> </span> </p> <p class='cloud-instance-input fillwidth'> <label class='fieldlabel halfwidth'>Image</label> <span class='halfwidth'> <select class='styled-select html-select halfwidth padspace' name='instance_image'> """ for (image_name, _, image_alias) in allowed_images: create_html += """<option value='%s'>%s</option> """ % (image_name, image_alias) create_html += """ </select> </span> </p> <p class='cloud-instance-input fillwidth'> <label class='fieldlabel halfwidth'> Accept <a href='%(rules_of_conduct)s'>Cloud Rules of Conduct</a> </label> <span class='halfwidth'> <label class='switch'> <input type='checkbox' mandatory name='accept_terms'> <span class='slider round'></span></label> </span> </p> <p class='fillwidth'> <input type='submit' value='Create Instance' /> </p> </form> </div> """ output_objects.append({ 'object_type': 'html_form', 'text': create_html % fill_helpers }) if saved_instances: output_objects.append({ 'object_type': 'html_form', 'text': delete_html % fill_helpers }) output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Save %s Settings" % label output_objects.append( {'object_type': 'header', 'text': 'Save %s Settings' % label}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append( {'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() new_settings = {'vgrid_name': vgrid_name} # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, ret_variables) = \ init_vgrid_script_add_rem(vgrid_name, client_id, new_settings.items(), 'settings', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) elif msg: # In case of warnings, msg is non-empty while ret_val remains True output_objects.append({'object_type': 'warning', 'text': msg}) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append( {'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label}) return (output_objects, returnvalues.CLIENT_ERROR) # Check if this owner is allowed to change settings (allow_status, allow_msg) = allow_settings_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({'object_type': 'error_text', 'text': allow_msg}) return (output_objects, returnvalues.CLIENT_ERROR) # Build current settings, leaving out unset ones for default/inherit if not keyword_auto in accepted['description']: new_settings['description'] = '\n'.join( accepted['description']).strip() if not keyword_auto in accepted['visible_owners']: visible_owners = accepted['visible_owners'][-1] if visible_owners in _valid_visible: new_settings['visible_owners'] = visible_owners else: msg = "invalid visible_owners value: %s" % visible_owners logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not keyword_auto in accepted['visible_members']: visible_members = accepted['visible_members'][-1] if visible_members in _valid_visible: new_settings['visible_members'] = visible_members else: msg = "invalid visible_members value: %s" % visible_members logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not keyword_auto in accepted['visible_resources']: visible_resources = accepted['visible_resources'][-1] if visible_resources in _valid_visible: new_settings['visible_resources'] = visible_resources else: msg = "invalid visible_resources value: %s" % visible_resources logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not keyword_auto in accepted['create_sharelink']: create_sharelink = accepted['create_sharelink'][-1] if create_sharelink in _valid_sharelink: new_settings['create_sharelink'] = create_sharelink else: msg = "invalid create_sharelink value: %s" % create_sharelink logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not _keyword_auto_int in accepted['request_recipients']: try: request_recipients = accepted['request_recipients'][-1] request_recipients = int(request_recipients) new_settings['request_recipients'] = request_recipients except ValueError: msg = "invalid request_recipients value: %s" % request_recipients logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not _keyword_auto_int in accepted['restrict_settings_adm']: try: restrict_settings_adm = accepted['restrict_settings_adm'][-1] restrict_settings_adm = int(restrict_settings_adm) new_settings['restrict_settings_adm'] = restrict_settings_adm except ValueError: msg = "invalid restrict_settings_adm value: %s" % \ restrict_settings_adm logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) else: restrict_settings_adm = default_vgrid_settings_limit if not _keyword_auto_int in accepted['restrict_owners_adm']: try: restrict_owners_adm = accepted['restrict_owners_adm'][-1] restrict_owners_adm = int(restrict_owners_adm) new_settings['restrict_owners_adm'] = restrict_owners_adm except ValueError: msg = "invalid restrict_owners_adm value: %s" % restrict_owners_adm logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) else: restrict_owners_adm = default_vgrid_settings_limit if not _keyword_auto_int in accepted['restrict_members_adm']: try: restrict_members_adm = accepted['restrict_members_adm'][-1] restrict_members_adm = int(restrict_members_adm) new_settings['restrict_members_adm'] = restrict_members_adm except ValueError: msg = "invalid restrict_members_adm value: %s" % \ restrict_members_adm logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not _keyword_auto_int in accepted['restrict_resources_adm']: try: restrict_resources_adm = accepted['restrict_resources_adm'][-1] restrict_resources_adm = int(restrict_resources_adm) new_settings['restrict_resources_adm'] = restrict_resources_adm except ValueError: msg = "invalid restrict_resources_adm value: %s" % \ restrict_resources_adm logger.warning(msg) output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if keyword_auto in accepted['write_shared_files']: write_shared_files = keyword_members else: write_shared_files = accepted['write_shared_files'][-1] if write_shared_files in _valid_write_access: new_settings['write_shared_files'] = write_shared_files else: msg = 'unknown write_shared_files value: %s' % write_shared_files output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if keyword_auto in accepted['write_priv_web']: write_priv_web = keyword_owners else: write_priv_web = accepted['write_priv_web'][-1] if write_priv_web in _valid_write_access: new_settings['write_priv_web'] = write_priv_web else: msg = 'unknown write_priv_web value: %s' % write_priv_web output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if keyword_auto in accepted['write_pub_web']: write_pub_web = keyword_owners else: write_pub_web = accepted['write_pub_web'][-1] if write_pub_web in _valid_write_access: new_settings['write_pub_web'] = write_pub_web else: msg = 'unknown write_pub_web value: %s' % write_pub_web output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) if not keyword_auto in accepted['hidden']: hidden = accepted['hidden'][-1] is_hidden = False if hidden.lower() in ("true", "1", "yes"): is_hidden = True new_settings['hidden'] = is_hidden if restrict_settings_adm > restrict_owners_adm: output_objects.append({'object_type': 'html_form', 'text': ''' <span class="warningtext">Warning: Restrict owner administration may still be circumvented by some owners unless Restrict settings administration is set to a lower or equal number.</span>'''}) # TODO: remove this bail-out once we've implemented wider web write access if write_priv_web != keyword_owners or write_pub_web != keyword_owners: output_objects.append( {'object_type': 'error_text', 'text': """%s does not yet support changing write access to the private and public web pages""" % configuration.short_title}) return (output_objects, returnvalues.CLIENT_ERROR) # Handle any write access limit changes first (load_old, old_settings) = vgrid_settings(vgrid_name, configuration, recursive=False, as_dict=True) if not load_old: output_objects.append( {'object_type': 'error_text', 'text': 'failed to load saved %s settings' % vgrid_name}) return (output_objects, returnvalues.SYSTEM_ERROR) old_write_shared = old_settings.get('write_shared_files', keyword_members) contact_text = """Please contact the %s admins if you then still get refused. Then it is probably because they need to upgrade your %s %s to the new layout format first.""" % (configuration.short_title, vgrid_name, label) # TODO: remove this bail-out once we've implemented owner-only write access if write_shared_files == keyword_owners: output_objects.append( {'object_type': 'error_text', 'text': """Owner-only write access is not supported yet"""}) return (output_objects, returnvalues.CLIENT_ERROR) elif old_write_shared == write_shared_files: logger.debug("write shared status (%s) is unchanged" % old_write_shared) else: if not vgrid_allow_restrict_write(vgrid_name, write_shared_files, configuration): if write_shared_files != keyword_members: # Refuse if any child vgrid is writable output_objects.append( {'object_type': 'error_text', 'text': """Refused to tighten write access for %s - layout or child prevents it! You need to make sure all child %ss have at least as strict write access before you can proceed to restrict %s. %s.""" % (vgrid_name, label, vgrid_name, contact_text)}) else: # Refuse if parent vgrid restricts write output_objects.append( {'object_type': 'error_text', 'text': """Refused to make %s fully writable - layout or parent prevents it! You need to remove write restrictions on all parent %ss before you can make %s writable. %s.""" % (vgrid_name, label, vgrid_name, contact_text)}) return (output_objects, returnvalues.CLIENT_ERROR) if not vgrid_restrict_write(vgrid_name, write_shared_files, configuration): if write_shared_files != keyword_members: output_objects.append( {'object_type': 'error_text', 'text': """Failed to restrict write to %s on %s shared files""" % (write_shared_files.lower(), vgrid_name)}) else: output_objects.append( {'object_type': 'error_text', 'text': """Failed to make %s fully writable""" % vgrid_name}) return (output_objects, returnvalues.SYSTEM_ERROR) # format as list of tuples to fit usual form and then pickle (set_status, set_msg) = vgrid_set_settings(configuration, vgrid_name, new_settings.items()) if not set_status: output_objects.append({'object_type': 'error_text', 'text': '%s' % set_msg}) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({'object_type': 'text', 'text': 'Settings saved for %s %s!' % (vgrid_name, label)}) output_objects.append({'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Add %s Resource" % label output_objects.append({ 'object_type': 'header', 'text': 'Add %s Resource(s)' % label }) status = returnvalues.OK (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() res_id_list = accepted['unique_resource_name'] request_name = unhexlify(accepted['request_name'][-1]) rank_list = accepted['rank'] + ['' for _ in res_id_list] if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional site-wide limitation of manage vgrid permission if not user_dict or \ not vgrid_manage_allowed(configuration, user_dict): logger.warning("user %s is not allowed to manage vgrids!" % client_id) output_objects.append({ 'object_type': 'error_text', 'text': 'Only privileged users can manage %ss' % label }) return (output_objects, returnvalues.CLIENT_ERROR) # make sure vgrid settings allow this owner to edit resources (allow_status, allow_msg) = allow_resources_adm(configuration, vgrid_name, client_id) if not allow_status: output_objects.append({'object_type': 'error_text', 'text': allow_msg}) return (output_objects, returnvalues.CLIENT_ERROR) res_id_added = [] for (res_id, rank_str) in zip(res_id_list, rank_list): unique_resource_name = res_id.lower().strip() try: rank = int(rank_str) except ValueError: rank = None # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, ret_variables) = \ init_vgrid_script_add_rem(vgrid_name, client_id, unique_resource_name, 'resource', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) status = returnvalues.CLIENT_ERROR continue elif msg: # In case of warnings, msg is non-empty while ret_val remains True output_objects.append({'object_type': 'warning', 'text': msg}) # don't add if already in vgrid or parent vgrid unless rank is given if rank is None and vgrid_is_resource(vgrid_name, unique_resource_name, configuration): output_objects.append({ 'object_type': 'error_text', 'text': '%s is already a resource in the %s' % (unique_resource_name, label) }) status = returnvalues.CLIENT_ERROR continue # don't add if already in subvgrid (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration) if not list_status: output_objects.append({ 'object_type': 'error_text', 'text': 'Error getting list of sub%ss: %s' % (label, subvgrids) }) status = returnvalues.SYSTEM_ERROR continue skip_entity = False for subvgrid in subvgrids: if vgrid_is_resource(subvgrid, unique_resource_name, configuration, recursive=False): output_objects.append({ 'object_type': 'error_text', 'text': '''%(res_name)s is already in a sub-%(vgrid_label)s (%(subvgrid)s). Please remove the resource from the sub-%(vgrid_label)s and try again''' % { 'res_name': unique_resource_name, 'subvgrid': subvgrid, 'vgrid_label': label } }) status = returnvalues.CLIENT_ERROR skip_entity = True break if skip_entity: continue # Check if only rank change was requested and apply if so if rank is not None: (add_status, add_msg) = vgrid_add_resources(configuration, vgrid_name, [unique_resource_name], rank=rank) if not add_status: output_objects.append({ 'object_type': 'error_text', 'text': add_msg }) status = returnvalues.SYSTEM_ERROR else: output_objects.append({ 'object_type': 'text', 'text': 'changed %s to resource %d' % (res_id, rank) }) # No further action after rank change as everything else exists continue # Getting here means res_id is neither resource of any parent or # sub-vgrids. # Please note that base_dir must end in slash to avoid access to other # vgrid dirs when own name is a prefix of another name base_dir = os.path.abspath(configuration.vgrid_home + os.sep + vgrid_name) + os.sep resources_file = base_dir + 'resources' # Add to list and pickle (add_status, add_msg) = vgrid_add_resources(configuration, vgrid_name, [unique_resource_name]) if not add_status: output_objects.append({ 'object_type': 'error_text', 'text': '%s' % add_msg }) status = returnvalues.SYSTEM_ERROR continue res_id_added.append(unique_resource_name) if request_name: request_dir = os.path.join(configuration.vgrid_home, vgrid_name) if not delete_access_request(configuration, request_dir, request_name): logger.error("failed to delete res request for %s in %s" % (vgrid_name, request_name)) output_objects.append({ 'object_type': 'error_text', 'text': 'Failed to remove saved request for %s in %s!' % (vgrid_name, request_name) }) if res_id_added: output_objects.append({ 'object_type': 'html_form', 'text': 'New resource(s)<br />%s<br />successfully added to %s %s!' '' % ('<br />'.join(res_id_added), vgrid_name, label) }) res_id_fields = '' for res_id in res_id_added: res_id_fields += """ <input type=hidden name=unique_resource_name value='%s' />""" % res_id form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'vgrid_name': vgrid_name, 'unique_resource_name': unique_resource_name, 'protocol': any_protocol, 'short_title': configuration.short_title, 'vgrid_label': label, 'res_id_fields': res_id_fields, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': """ <form method='%(form_method)s' action='%(target_op)s.py'> <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' /> <input type=hidden name=request_type value='vgridaccept' /> <input type=hidden name=vgrid_name value='%(vgrid_name)s' /> %(res_id_fields)s <input type=hidden name=protocol value='%(protocol)s' /> <table> <tr> <td class='title'>Custom message to resource owners</td> </tr><tr> <td><textarea name=request_text cols=72 rows=10> We have granted your %(unique_resource_name)s resource access to our %(vgrid_name)s %(vgrid_label)s. You can assign it to accept jobs from the %(vgrid_name)s %(vgrid_label)s from your Resources page on %(short_title)s. Regards, the %(vgrid_name)s %(vgrid_label)s owners </textarea></td> </tr> <tr> <td><input type='submit' value='Inform owners' /></td> </tr> </table> </form> <br /> """ % fill_helpers }) output_objects.append({ 'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name }) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Create %s' % configuration.site_vgrid_label output_objects.append({'object_type': 'header', 'text': 'Create %s' % \ configuration.site_vgrid_label}) # No owner check here so we need to specifically check for illegal # directory access reserved_names = (default_vgrid, any_vgrid, all_vgrids) if vgrid_name in reserved_names or \ not valid_dir_input(configuration.vgrid_home, vgrid_name): output_objects.append({'object_type': 'error_text', 'text' : 'Illegal vgrid_name: %s' % vgrid_name}) logger.warning("""createvgrid possible illegal directory access attempt by '%s': vgrid_name '%s'""" % (client_id, vgrid_name)) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of create vgrid permission if not user_dict or \ not vgrid_create_allowed(configuration, user_dict): logger.warning("user %s is not allowed to create %ss!" % \ (client_id, configuration.site_vgrid_label)) output_objects.append( {'object_type': 'error_text', 'text' : 'Only privileged users can create %ss' % \ configuration.site_vgrid_label}) return (output_objects, returnvalues.CLIENT_ERROR) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep public_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name)) + os.sep public_scm_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name, '.vgridscm')) + os.sep public_tracker_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name, '.vgridtracker')) + os.sep private_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name)) + os.sep private_scm_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name, '.vgridscm')) + os.sep private_tracker_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name, '.vgridtracker')) + os.sep private_forum_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name, '.vgridforum')) + os.sep vgrid_files_dir = \ os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name)) + os.sep vgrid_scm_dir = \ os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name, '.vgridscm')) + os.sep vgrid_tracker_dir = \ os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name, '.vgridtracker')) + os.sep # does vgrid exist? if os.path.isdir(base_dir): output_objects.append( {'object_type': 'error_text', 'text' : '%s %s cannot be created because it already exists!' % (configuration.site_vgrid_label, vgrid_name)}) return (output_objects, returnvalues.CLIENT_ERROR) # verify that client is owner of imada or imada/topology if trying to # create imada/topology/test vgrid_name_list = vgrid_name.split('/') vgrid_name_list_length = len(vgrid_name_list) if vgrid_name_list_length <= 0: output_objects.append({'object_type': 'error_text', 'text' : 'vgrid_name not specified?'}) return (output_objects, returnvalues.SYSTEM_ERROR) elif vgrid_name_list_length == 1: # anyone can create base vgrid new_base_vgrid = True else: new_base_vgrid = False vgrid_name_without_last_fragment = \ '/'.join(vgrid_name_list[0:vgrid_name_list_length - 1]) parent_base = os.path.dirname(base_dir.rstrip(os.sep)) if not os.path.isdir(parent_base): output_objects.append( {'object_type': 'error_text', 'text' : 'Parent %s %s does not exist!' % \ (configuration.site_vgrid_label, vgrid_name_without_last_fragment) }) return (output_objects, returnvalues.CLIENT_ERROR) if not vgrid_is_owner(vgrid_name_without_last_fragment, client_id, configuration): output_objects.append( {'object_type': 'error_text', 'text' : 'You must own a parent %s to create a sub vgrid' % \ configuration.site_vgrid_label }) return (output_objects, returnvalues.CLIENT_ERROR) # make sure all dirs can be created (that a file or directory with the same # name do not exist prior to the vgrid creation) try_again_string = \ """%s cannot be created, a file or directory exists with the same name, please try again with a new name!""" % configuration.site_vgrid_label if os.path.exists(public_base_dir): output_objects.append({'object_type': 'error_text', 'text' : try_again_string}) return (output_objects, returnvalues.CLIENT_ERROR) if os.path.exists(private_base_dir): output_objects.append({'object_type': 'error_text', 'text' : try_again_string}) return (output_objects, returnvalues.CLIENT_ERROR) if os.path.exists(vgrid_files_dir): output_objects.append({'object_type': 'error_text', 'text' : try_again_string}) return (output_objects, returnvalues.CLIENT_ERROR) # create directory to store vgrid files try: os.mkdir(base_dir) except Exception, exc: output_objects.append( {'object_type': 'error_text', 'text' : """Could not create %(_label)s directory, remember to create parent %(_label)s before creating a sub-%(_label)s.""" % \ {'_label': configuration.site_vgrid_label} }) return (output_objects, returnvalues.CLIENT_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) (stat, vgrid_list) = vgrid_list_vgrids(configuration) if not stat: output_objects.append({'object_type': 'error_text', 'text' : 'Error getting list of %s.' % \ configuration.site_vgrid_label}) # Check if user wants advanced VGrid component links settings = load_settings(client_id, configuration) collaboration_links = settings.get('SITE_COLLABORATION_LINKS', 'default') if not collaboration_links in configuration.site_collaboration_links or \ collaboration_links == 'default': active_vgrid_links = configuration.site_default_vgrid_links elif collaboration_links == 'advanced': active_vgrid_links = configuration.site_advanced_vgrid_links # Iterate through vgrids and print details for each member_list = {'object_type': 'vgrid_list', 'vgrids': [], 'components': active_vgrid_links} if 'monitor' in active_vgrid_links: vgrid_list = [all_vgrids] + vgrid_list else: vgrid_list.remove(default_vgrid) for vgrid_name in vgrid_list: vgrid_obj = {'object_type': 'vgrid', 'name': vgrid_name} if vgrid_name == default_vgrid: # Everybody is member and allowed to see statistics, Noone # can own it or leave it. Do not add any page links. vgrid_obj['privatemonitorlink'] = {'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s'\ % vgrid_name, 'class': 'monitorlink', 'title': 'View %s monitor' % vgrid_name, 'text': 'View'} vgrid_obj['memberlink'] = {'object_type': 'link', 'destination':'', 'class': 'infolink', 'title': 'Every user is member of the %s %s' \ % (default_vgrid, configuration.site_vgrid_label), 'text': ''} vgrid_obj['administratelink'] = {'object_type': 'link', 'destination':'', 'class': 'infolink', 'title': 'Nobody owns the %s %s' \ % (default_vgrid, configuration.site_vgrid_label), 'text': ''} member_list['vgrids'].append(vgrid_obj) continue elif vgrid_name == all_vgrids: # Only show global monitor link for all_vgrids, Noone # can own it or leave it. Do not add any page links. vgrid_obj['privatemonitorlink'] = {'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s'\ % vgrid_name, 'class': 'monitorlink', 'title': 'View global monitor', 'text': 'View'} vgrid_obj['memberlink'] = {'object_type': 'link', 'destination':'', 'class': 'infolink', 'title': 'Not a real %s - only for global monitor' % \ configuration.site_vgrid_label, 'text': ''} vgrid_obj['administratelink'] = {'object_type': 'link', 'destination':'', 'class': 'infolink', 'title': 'Not a real %s - only for global monitor' % \ configuration.site_vgrid_label, 'text': ''} member_list['vgrids'].append(vgrid_obj) continue # links for everyone: public pages and membership request vgrid_obj['publicscmlink'] = {'object_type': 'link', 'destination': '%s/vgridpublicscm/%s'\ % (configuration.migserver_http_url, vgrid_name), 'class': 'scmlink public', 'title': 'Open %s public SCM' % \ vgrid_name, 'text': 'Open'} vgrid_obj['publictrackerlink'] = {'object_type': 'link', 'destination': '%s/vgridpublictracker/%s'\ % (configuration.migserver_http_url, vgrid_name), 'class': 'trackerlink public', 'title': 'Open %s public tracker' % \ vgrid_name, 'text': 'Open'} vgrid_obj['enterpubliclink'] = {'object_type': 'link', 'destination': '%s/vgrid/%s/path/index.html' % \ (configuration.migserver_http_url, vgrid_name), 'class': 'urllink member', 'title': 'View public %s web page' % \ vgrid_name, 'text': 'View'} # link to become member: overwritten later for members js_name = 'reqvgridmember%s' % hexlify(vgrid_name) helper = html_post_helper(js_name, 'sendrequestaction.py', {'vgrid_name': vgrid_name, 'request_type': 'vgridmember', 'request_text': ''}) output_objects.append({'object_type': 'html_form', 'text': helper}) vgrid_obj['memberlink'] = \ {'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s');"\ % (js_name, "Request membership of " + \ vgrid_name + ":<br/>" + \ "\nPlease write a message to the owners (field below).", 'request_text'), 'class': 'addlink', 'title': 'Request membership of %s' % \ vgrid_name, 'text': ''} # link to become owner: overwritten later for owners js_name = 'reqvgridowner%s' % hexlify(vgrid_name) helper = html_post_helper(js_name, 'sendrequestaction.py', {'vgrid_name': vgrid_name, 'request_type': 'vgridowner', 'request_text': ''}) output_objects.append({'object_type': 'html_form', 'text': helper}) vgrid_obj['administratelink'] = \ {'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s');"\ % (js_name, "Request ownership of " + \ vgrid_name + ":<br/>" + \ "\nPlease write a message to the owners (field below).", 'request_text'), 'class': 'addadminlink', 'title': 'Request ownership of %s' % \ vgrid_name, 'text': ''} # members/owners are allowed to view private pages and monitor if vgrid_is_owner_or_member(vgrid_name, client_id, configuration): vgrid_obj['enterprivatelink'] = {'object_type': 'link', 'destination': '../vgrid/%s/path/index.html' % \ vgrid_name, 'class': 'urllink owner', 'title': 'View private %s web page' % \ vgrid_name, 'text': 'View'} vgrid_obj['sharedfolderlink'] = {'object_type': 'link', 'destination': 'fileman.py?path=%s/' % vgrid_name, 'class': 'sharedfolderlink', 'title': 'Open shared %s folder' \ % vgrid_name, 'text': 'Open'} vgrid_obj['memberscmlink'] = {'object_type': 'link', 'destination': '/vgridscm/%s' % \ vgrid_name, 'class': 'scmlink member', 'title': 'View %s members scm' % \ vgrid_name, 'text': 'View'} vgrid_obj['membertrackerlink'] = {'object_type': 'link', 'destination': '/vgridtracker/%s' % \ vgrid_name, 'class': 'trackerlink member', 'title': 'View %s members tracker' % \ vgrid_name, 'text': 'View'} vgrid_obj['privateforumlink'] = {'object_type': 'link', 'destination': 'vgridforum.py?vgrid_name=%s' % \ vgrid_name, 'class': 'forumlink', 'title': 'Open %s private forum' \ % vgrid_name, 'text': 'Open'} vgrid_obj['privateworkflowslink'] = {'object_type': 'link', 'destination': 'vgridworkflows.py?vgrid_name=%s' % \ vgrid_name, 'class': 'workflowslink', 'title': 'Open %s private workflows' \ % vgrid_name, 'text': 'Open'} vgrid_obj['privatemonitorlink'] = {'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s'\ % vgrid_name, 'class': 'monitorlink', 'title': 'View %s monitor' % \ vgrid_name, 'text': 'View'} # to leave this VGrid (remove ourselves). Note that we are # going to overwrite the link later for owners. js_name = 'rmvgridmember%s' % hexlify(vgrid_name) helper = html_post_helper(js_name, 'rmvgridmember.py', {'vgrid_name': vgrid_name, 'cert_id': client_id}) output_objects.append({'object_type': 'html_form', 'text': helper}) vgrid_obj['memberlink'] = \ {'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s');"\ % (js_name, "Really leave " + vgrid_name + "?"), 'class': 'removelink', 'title': 'Leave %s members' % vgrid_name, 'text': ''} # owners are allowed to edit pages and administrate if vgrid_is_owner(vgrid_name, client_id, configuration): vgrid_obj['ownerscmlink'] = {'object_type': 'link', 'destination': '/vgridownerscm/%s' % \ vgrid_name, 'class': 'scmlink owner', 'title': 'View %s owners scm' % \ vgrid_name, 'text': 'View'} vgrid_obj['ownertrackerlink'] = {'object_type': 'link', 'destination': '/vgridownertracker/%s' % \ vgrid_name, 'class': 'trackerlink owner', 'title': 'View %s owners tracker' % \ vgrid_name, 'text': 'View'} # correct the link to leave the VGrid js_name = 'rmvgridowner%s' % hexlify(vgrid_name) helper = html_post_helper(js_name, 'rmvgridowner.py', {'vgrid_name': vgrid_name, 'cert_id': client_id}) output_objects.append({'object_type': 'html_form', 'text': helper}) vgrid_obj['memberlink']['destination'] = \ "javascript: confirmDialog(%s,'%s');" % \ (js_name, "Really leave " + vgrid_name + "?") vgrid_obj['memberlink']['class'] = 'removeadminlink' vgrid_obj['memberlink']['title'] = 'Leave %s owners' % vgrid_name # add more links: administrate and edit pages vgrid_obj['administratelink'] = {'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s'\ % vgrid_name, 'class': 'adminlink', 'title': 'Administrate %s' % vgrid_name, 'text': ''} vgrid_obj['editprivatelink'] = {'object_type': 'link', 'destination': 'fileman.py?path=private_base/%s/'\ % vgrid_name, 'class': 'editlink owner', 'title': 'Edit private %s web page' % vgrid_name, 'text': 'Edit'} vgrid_obj['editpubliclink'] = {'object_type': 'link', 'destination': 'fileman.py?path=public_base/%s/'\ % vgrid_name, 'class': 'editlink member', 'title': 'Edit public %s web page' % vgrid_name, 'text': 'Edit'} member_list['vgrids'].append(vgrid_obj) title_entry = find_entry(output_objects, 'title') label = "%ss" % configuration.site_vgrid_label # Append VGrid note if custom if label != 'VGrid': label += ' (i.e. VGrids)' title_entry['text'] = '%s administration' % label # jquery support for tablesorter and confirmation on "leave": title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <script type="text/javascript" src="/images/js/jquery.confirm.js"></script> <script type="text/javascript" > $(document).ready(function() { // init confirmation dialog $( "#confirm_dialog" ).dialog( // see http://jqueryui.com/docs/dialog/ for options { autoOpen: false, modal: true, closeOnEscape: true, width: 500, buttons: { "Cancel": function() { $( "#" + name ).dialog("close"); } } }); // table initially sorted by col. 1 (admin), then 2 (member), then 0 (name) var sortOrder = [[1,1],[2,1],[0,0]]; // use image path for sorting if there is any inside var imgTitle = function(contents) { var key = $(contents).find("a").attr("class"); if (key == null) { key = $(contents).html(); } return key; } $("#vgridtable").tablesorter({widgets: ["zebra", "saveSort"], sortList:sortOrder, textExtraction: imgTitle }) .tablesorterPager({ container: $("#pager"), size: %s }); } ); </script> ''' % default_pager_entries output_objects.append({'object_type': 'html_form', 'text':''' <div id="confirm_dialog" title="Confirm" style="background:#fff;"> <div id="confirm_text"><!-- filled by js --></div> <textarea cols="40" rows="4" id="confirm_input" style="display:none;"></textarea> </div> ''' }) output_objects.append({'object_type': 'header', 'text': label}) output_objects.append({'object_type': 'text', 'text' : ''' %ss share files, a number of collaboration tools and resources. Members can access web pages, files, tools and resources. Owners can additionally edit pages, as well as add and remove members or resources. ''' % configuration.site_vgrid_label }) if configuration.site_vgrid_label != 'VGrid': output_objects.append({'object_type': 'text', 'text' : """Please note that for historical reasons %ss are also referred to as VGrids in some contexts.""" % \ configuration.site_vgrid_label}) output_objects.append({'object_type': 'sectionheader', 'text' : '%ss managed on this server' % \ configuration.site_vgrid_label}) output_objects.append({'object_type': 'table_pager', 'entry_name': '%ss' % \ configuration.site_vgrid_label, 'default_entries': default_pager_entries}) output_objects.append(member_list) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of create vgrid permission if user_dict and vgrid_create_allowed(configuration, user_dict): output_objects.append({'object_type': 'sectionheader', 'text' : 'Additional %ss' % \ configuration.site_vgrid_label}) output_objects.append( {'object_type': 'text', 'text': '''Please enter a name for the new %(label)s to add, using slashes to specify nesting. I.e. if you own a %(label)s called ABC, you can create a sub-%(label)s called DEF by entering ABC/DEF below.''' % \ {'label': configuration.site_vgrid_label}}) output_objects.append({'object_type': 'html_form', 'text': '''<form method="post" action="createvgrid.py"> <input type="text" size=40 name="vgrid_name" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Create %s" /> </form> ''' % configuration.site_vgrid_label}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Request Access to %ss' % \ configuration.site_vgrid_label}) output_objects.append( {'object_type': 'text', 'text': '''You can request access to %(label)ss using the individual plus-icons above directly or by entering the name of the %(label)s to request access to, what kind of access and an optional message to the admins below''' % \ {'label': configuration.site_vgrid_label}}) output_objects.append({'object_type': 'html_form', 'text': '''<form method="post" action="sendrequestaction.py"> <input type="text" size=40 name="vgrid_name" /> <select name="request_type"> <option value="vgridmember">membership</option> <option value="vgridowner">ownership</option> </select> <input type="text" size=50 name="request_text" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Request %s access" /> </form> ''' % configuration.site_vgrid_label}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "%s Management" % label (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) operation = accepted['operation'][-1] caching = (accepted['caching'][-1].lower() in ('true', 'yes')) if not operation in allowed_operations: output_objects.append({ 'object_type': 'error_text', 'text': '''Operation must be one of %s.''' % ', '.join(allowed_operations) }) return (output_objects, returnvalues.OK) logger.info("%s %s begin for %s" % (op_name, operation, client_id)) vgrid_items, active_vgrid_links = [], [] member_list = { 'object_type': 'vgrid_list', 'vgrids': vgrid_items, 'components': active_vgrid_links } # Check if user wants advanced VGrid component links user_settings = title_entry.get('user_settings', {}) collaboration_links = user_settings.get('SITE_COLLABORATION_LINKS', 'default') if not collaboration_links in configuration.site_collaboration_links or \ collaboration_links == 'default': active_vgrid_links += configuration.site_default_vgrid_links elif collaboration_links == 'advanced': active_vgrid_links += configuration.site_advanced_vgrid_links # General fill helpers including CSRF fields form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'vgrid_label': label, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } if operation in show_operations: # jquery support for tablesorter and confirmation on request and leave # table initially sorted by col. 2 (admin), then 3 (member), then 0 (name) # NOTE: We distinguish between caching on page load and forced refresh refresh_helper = 'ajax_vgridman("%s", %s, %%s)' refresh_call = refresh_helper % (label, active_vgrid_links) table_spec = { 'table_id': 'vgridtable', 'sort_order': '[[2,1],[3,1],[0,0]]', 'refresh_call': refresh_call % 'false' } (add_import, add_init, add_ready) = man_base_js(configuration, [table_spec]) if operation == "show": add_ready += '%s;' % (refresh_call % 'true') title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({ 'object_type': 'html_form', 'text': man_base_html(configuration) }) # Append VGrid alias note if custom if label != 'VGrid': long_label = '%ss (i.e. VGrids)' % label else: long_label = "%ss" % label output_objects.append({ 'object_type': 'header', 'text': "%s" % long_label }) output_objects.append({ 'object_type': 'text', 'text': '''%ss share files, a number of collaboration tools and resources. Members can access web pages, files, tools and resources. Owners can additionally edit pages, as well as add and remove members or resources.''' % label }) if label != 'VGrid': output_objects.append({ 'object_type': 'text', 'text': """Please note that for historical reasons %ss are also referred to as VGrids in some contexts.""" % label }) output_objects.append({ 'object_type': 'sectionheader', 'text': '%ss managed on this server' % label }) # Helper forms for requests and removes for post_type in ["vgridowner", "vgridmember"]: target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( 'req%s' % post_type, '%s.py' % target_op, { 'vgrid_name': '__DYNAMIC__', 'request_type': post_type, 'request_text': '', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) for post_type in ["vgridowner", "vgridmember"]: target_op = 'rm%s' % post_type csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( target_op, '%s.py' % target_op, { 'vgrid_name': '__DYNAMIC__', 'cert_id': client_id, csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({ 'object_type': 'table_pager', 'entry_name': '%ss' % label, 'default_entries': default_pager_entries }) if operation in list_operations: logger.info("get vgrid map with caching %s" % caching) vgrid_map = get_vgrid_map(configuration, caching=caching) member_list['pending_updates'] = False if caching: modified_vgrids, _ = check_vgrids_modified(configuration) if modified_vgrids: logger.info("pending cache updates: %s" % modified_vgrids) member_list['pending_updates'] = True else: logger.info("no pending cache updates") vgrid_list = vgrid_map[VGRIDS].keys() # Iterate through vgrids and print details for each if 'monitor' in active_vgrid_links: vgrid_list = [all_vgrids] + vgrid_list else: vgrid_list.remove(default_vgrid) # User vgrid_list here to include default and all mangling above for vgrid_name in vgrid_list: vgrid_dict = vgrid_map[VGRIDS].get(vgrid_name, {}) settings_dict = dict(vgrid_dict.get(SETTINGS, [])) # Mark and show hidden vgrids if owner or member and hide otherwise view_icon, hidden_status = "infolink", " " if settings_dict.get('hidden', False): if client_id in vgrid_dict[OWNERS] + vgrid_dict[MEMBERS]: logger.debug("show hidden vgrid %s for participant" % vgrid_name) view_icon, hidden_status = "shadeinfolink", " hidden " else: logger.debug("skip hidden vgrid %s" % vgrid_name) continue vgrid_obj = {'object_type': 'vgrid', 'name': vgrid_name} if vgrid_name == default_vgrid: # Everybody is member and allowed to see statistics, Noone # can own it or leave it. Do not add any page links. vgrid_obj['privatemonitorlink'] = { 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s' % vgrid_name, 'class': 'monitorlink iconspace', 'title': 'View %s monitor' % vgrid_name, 'text': 'View' } vgrid_obj['memberlink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Every user is member of the %s %s' % (default_vgrid, label), 'text': '' } vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Nobody owns the %s %s' % (default_vgrid, label), 'text': '' } vgrid_obj['viewvgridlink'] = { 'object_type': 'link', 'destination': 'viewvgrid.py?vgrid_name=%s' % vgrid_name, 'class': 'infolink iconspace', 'title': 'View details for the %s %s' % (default_vgrid, label), 'text': '' } vgrid_items.append(vgrid_obj) continue elif vgrid_name == all_vgrids: # Only show global monitor link for all_vgrids, Noone # can own it or leave it. Do not add any page links. vgrid_obj['privatemonitorlink'] = { 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s' % vgrid_name, 'class': 'monitorlink iconspace', 'title': 'View global monitor', 'text': 'View' } vgrid_obj['memberlink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Not a real %s - only for global monitor' % label, 'text': '' } vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': '', 'class': '', 'title': '', 'text': '' } vgrid_obj['viewvgridlink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Not a real %s - only for global monitor' % label, 'text': '' } vgrid_items.append(vgrid_obj) continue # links for everyone: public pages and membership request vgrid_obj['publicscmlink'] = { 'object_type': 'link', 'destination': '%s/vgridpublicscm/%s' % (configuration.migserver_http_url, vgrid_name), 'class': 'scmlink public iconspace', 'title': 'Open %s public SCM' % vgrid_name, 'text': 'Open' } vgrid_obj['publictrackerlink'] = { 'object_type': 'link', 'destination': '%s/vgridpublictracker/%s' % (configuration.migserver_http_url, vgrid_name), 'class': 'trackerlink public iconspace', 'title': 'Open %s public tracker' % vgrid_name, 'text': 'Open' } vgrid_obj['enterpubliclink'] = { 'object_type': 'link', 'destination': '%s/vgrid/%s/path/index.html' % (configuration.migserver_http_url, vgrid_name), 'class': 'urllink member iconspace', 'title': 'View public %s web page' % vgrid_name, 'text': 'View' } # Link to show vgrid details vgrid_obj['viewvgridlink'] = \ {'object_type': 'link', 'destination': 'viewvgrid.py?vgrid_name=%s' % vgrid_name, 'class': '%s iconspace' % view_icon, 'title': 'View details for the %s%s%s' % (vgrid_name, hidden_status, label), 'text': ''} # link to become member: overwritten later for members vgrid_obj['memberlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s', %s);" % ('reqvgridmember', "Request membership of " + vgrid_name + ":<br/>\nPlease write a message to the owners (field below).", 'request_text', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'addlink iconspace', 'title': 'Request membership of %s' % vgrid_name, 'text': '' } # link to become owner: overwritten later for owners vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s', %s);" % ('reqvgridowner', "Request ownership of " + vgrid_name + ":<br/>\nPlease write a message to the owners (field below).", 'request_text', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'addadminlink iconspace', 'title': 'Request ownership of %s' % vgrid_name, 'text': '' } # members/owners are allowed to view private pages and monitor if client_id in vgrid_dict[OWNERS] + vgrid_dict[MEMBERS]: vgrid_obj['enterprivatelink'] = { 'object_type': 'link', 'destination': '../vgrid/%s/path/index.html' % vgrid_name, 'class': 'urllink owner iconspace', 'title': 'View private %s web page' % vgrid_name, 'text': 'View' } vgrid_obj['sharedfolderlink'] = { 'object_type': 'link', 'destination': 'fileman.py?path=%s/' % vgrid_name, 'class': 'sharedfolderlink iconspace', 'title': 'Open shared %s folder' % vgrid_name, 'text': 'Open' } vgrid_obj['memberscmlink'] = { 'object_type': 'link', 'destination': '/vgridscm/%s' % vgrid_name, 'class': 'scmlink member iconspace', 'title': 'View %s members scm' % vgrid_name, 'text': 'View' } vgrid_obj['membertrackerlink'] = { 'object_type': 'link', 'destination': '/vgridtracker/%s' % vgrid_name, 'class': 'trackerlink member iconspace', 'title': 'View %s members tracker' % vgrid_name, 'text': 'View' } vgrid_obj['privateforumlink'] = { 'object_type': 'link', 'destination': 'vgridforum.py?vgrid_name=%s' % vgrid_name, 'class': 'forumlink iconspace', 'title': 'Open %s private forum' % vgrid_name, 'text': 'Open' } vgrid_obj['privateworkflowslink'] = { 'object_type': 'link', 'destination': 'vgridworkflows.py?vgrid_name=%s' % vgrid_name, 'class': 'workflowslink iconspace', 'title': 'Open %s private workflows' % vgrid_name, 'text': 'Open' } vgrid_obj['privatemonitorlink'] = { 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s' % vgrid_name, 'class': 'monitorlink iconspace', 'title': 'View %s monitor' % vgrid_name, 'text': 'View' } # to leave this VGrid (remove ourselves). Note that we are # going to overwrite the link later for owners. vgrid_obj['memberlink'].update({ 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ('rmvgridmember', "Really leave " + vgrid_name + "?", 'undefined', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'removelink iconspace', 'title': 'Leave %s members' % vgrid_name, }) # owners are allowed to edit pages and administrate if client_id in vgrid_dict[OWNERS]: vgrid_obj['ownerscmlink'] = { 'object_type': 'link', 'destination': '/vgridownerscm/%s' % vgrid_name, 'class': 'scmlink owner iconspace', 'title': 'View %s owners scm' % vgrid_name, 'text': 'View' } vgrid_obj['ownertrackerlink'] = { 'object_type': 'link', 'destination': '/vgridownertracker/%s' % vgrid_name, 'class': 'trackerlink owner iconspace', 'title': 'View %s owners tracker' % vgrid_name, 'text': 'View' } # correct the link to leave the VGrid vgrid_obj['memberlink'].update({ 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ('rmvgridowner', "Really leave " + vgrid_name + "?", 'undefined', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'removeadminlink iconspace', 'title': 'Leave %s owners' % vgrid_name }) # add more links: administrate and edit pages vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'class': 'adminlink iconspace', 'title': 'Administrate %s' % vgrid_name, 'text': '' } vgrid_obj['editprivatelink'] = { 'object_type': 'link', 'destination': 'fileman.py?path=private_base/%s/' % vgrid_name, 'class': 'editlink owner iconspace', 'title': 'Edit private %s web page' % vgrid_name, 'text': 'Edit' } vgrid_obj['editpubliclink'] = { 'object_type': 'link', 'destination': 'fileman.py?path=public_base/%s/' % vgrid_name, 'class': 'editlink member iconspace', 'title': 'Edit public %s web page' % vgrid_name, 'text': 'Edit' } vgrid_items.append(vgrid_obj) if operation == "show": # insert dummy placeholder to build table vgrid_obj = {'object_type': 'vgrid', 'name': default_vgrid} for field in active_vgrid_links: vgrid_obj[field] = '' vgrid_items.append(vgrid_obj) output_objects.append(member_list) if operation in show_operations: user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of create vgrid permission if user_dict and vgrid_create_allowed(configuration, user_dict): output_objects.append({ 'object_type': 'sectionheader', 'text': 'Additional %ss' % label }) output_objects.append({ 'object_type': 'text', 'text': '''Please enter a name for the new %(vgrid_label)s to add, using slashes to specify nesting. I.e. if you own a %(vgrid_label)s called ABC, you can create a sub-%(vgrid_label)s called DEF by entering ABC/DEF below. ''' % fill_helpers }) target_op = 'createvgrid' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({ 'target_op': target_op, 'csrf_token': csrf_token }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> <input class="p60width" type="text" name="vgrid_name" required pattern="[a-zA-Z0-9 /_.-]*" title="unique name of ASCII letters and digits separated only by underscores, periods, spaces and hyphens. Slashes are additionally allowed when creating nested sub-%(vgrid_label)ss" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Create %(vgrid_label)s" /> </form> ''' % fill_helpers }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Request Access to %ss' % label }) output_objects.append({ 'object_type': 'text', 'text': '''You can request access to %(vgrid_label)ss using the individual plus-icons above directly or by entering the name of the %(vgrid_label)s to request access to, what kind of access and an optional message to the admins below''' % fill_helpers }) target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> <input class="p60width" type="text" name="vgrid_name" required pattern="[a-zA-Z0-9 /_.-]*" title="the name of an existing %(vgrid_label)s" /> <select class="styled-select html-select" name="request_type"> <option value="vgridmember">membership</option> <option value="vgridowner">ownership</option> </select> <br/> <input class="p60width" type="text" name="request_text" required /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Request %(vgrid_label)s access" /> </form> ''' % fill_helpers }) logger.info("%s %s end for %s" % (op_name, operation, client_id)) return (output_objects, status)