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'] = '%s send request' % configuration.short_title output_objects.append({ 'object_type': 'header', 'text': '%s send request' % configuration.short_title }) (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) target_id = client_id vgrid_name = accepted['vgrid_name'][-1].strip() visible_user_names = accepted['cert_id'] visible_res_names = accepted['unique_resource_name'] request_type = accepted['request_type'][-1].strip().lower() request_text = accepted['request_text'][-1].strip() protocols = [proto.strip() for proto in accepted['protocol']] use_any = False if any_protocol in protocols: use_any = True protocols = configuration.notify_protocols protocols = [proto.lower() for proto in protocols] 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) valid_request_types = [ 'resourceowner', 'resourceaccept', 'resourcereject', 'vgridowner', 'vgridmember', 'vgridresource', 'vgridaccept', 'vgridreject', 'plain' ] if not request_type in valid_request_types: output_objects.append({ 'object_type': 'error_text', 'text': '%s is not a valid request_type (valid types: %s)!' % (request_type.lower(), valid_request_types) }) return (output_objects, returnvalues.CLIENT_ERROR) if not protocols: output_objects.append({ 'object_type': 'error_text', 'text': 'No protocol specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_user_map(configuration) reply_to = user_map[client_id][USERID] # Try to point replies to client_id email client_email = extract_field(reply_to, 'email') if request_type == "plain": if not visible_user_names: output_objects.append({ 'object_type': 'error_text', 'text': 'No user ID specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) user_id = visible_user_names[-1].strip() anon_map = anon_to_real_user_map(configuration) if user_id in anon_map: user_id = anon_map[user_id] if user_id not in user_map: output_objects.append({ 'object_type': 'error_text', 'text': 'No such user: %s' % user_id }) return (output_objects, returnvalues.CLIENT_ERROR) target_name = user_id user_dict = user_map[user_id] vgrid_access = user_vgrid_access(configuration, client_id) vgrids_allow_email = user_dict[CONF].get('VGRIDS_ALLOW_EMAIL', []) vgrids_allow_im = user_dict[CONF].get('VGRIDS_ALLOW_IM', []) if any_vgrid in vgrids_allow_email: email_vgrids = vgrid_access else: email_vgrids = set(vgrids_allow_email).intersection(vgrid_access) if any_vgrid in vgrids_allow_im: im_vgrids = vgrid_access else: im_vgrids = set(vgrids_allow_im).intersection(vgrid_access) if use_any: # Do not try disabled protocols if ANY was requested if not email_vgrids: protocols = [ proto for proto in protocols if proto not in email_keyword_list ] if not im_vgrids: protocols = [ proto for proto in protocols if proto in email_keyword_list ] if not email_vgrids and [ proto for proto in protocols if proto in email_keyword_list ]: output_objects.append({ 'object_type': 'error_text', 'text': 'You are not allowed to send emails to %s!' % user_id }) return (output_objects, returnvalues.CLIENT_ERROR) if not im_vgrids and [ proto for proto in protocols if proto not in email_keyword_list ]: output_objects.append({ 'object_type': 'error_text', 'text': 'You are not allowed to send instant messages to %s!' % user_id }) return (output_objects, returnvalues.CLIENT_ERROR) for proto in protocols: if not user_dict[CONF].get(proto.upper(), False): if use_any: # Remove missing protocols if ANY protocol was requested protocols = [i for i in protocols if i != proto] else: output_objects.append({ 'object_type': 'error_text', 'text': 'User %s does not accept %s messages!' % (user_id, proto) }) return (output_objects, returnvalues.CLIENT_ERROR) if not protocols: output_objects.append({ 'object_type': 'error_text', 'text': 'User %s does not accept requested protocol(s) messages!' % user_id }) return (output_objects, returnvalues.CLIENT_ERROR) target_list = [user_id] elif request_type in ["vgridaccept", "vgridreject"]: # Always allow accept messages but only between owners/members if not visible_user_names and not visible_res_names: output_objects.append({ 'object_type': 'error_text', 'text': 'No user or resource ID specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) if not vgrid_name: output_objects.append({ 'object_type': 'error_text', 'text': 'No vgrid_name specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) if vgrid_name.upper() == default_vgrid.upper(): output_objects.append({ 'object_type': 'error_text', 'text': 'No requests for %s are allowed!' % default_vgrid }) return (output_objects, returnvalues.CLIENT_ERROR) if not vgrid_is_owner(vgrid_name, client_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': 'You are not an owner of %s or a parent %s!' % (vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) # NOTE: we support exactly one vgrid but multiple users/resources here if visible_user_names: logger.info("setting user recipients: %s" % visible_user_names) target_list = [user_id.strip() for user_id in visible_user_names] elif visible_res_names: # vgrid resource accept - lookup and notify resource owners logger.info("setting res owner recipients: %s" % visible_res_names) target_list = [] for unique_resource_name in visible_res_names: logger.info("loading res owners for %s" % unique_resource_name) (load_status, res_owners) = resource_owners(configuration, unique_resource_name) if not load_status: output_objects.append({ 'object_type': 'error_text', 'text': 'Could not lookup owners of %s!' % unique_resource_name }) continue logger.info("adding res owners to recipients: %s" % res_owners) target_list += [user_id for user_id in res_owners] target_id = '%s %s owners' % (vgrid_name, label) target_name = vgrid_name elif request_type in ["resourceaccept", "resourcereject"]: # Always allow accept messages between actual resource owners if not visible_user_names: output_objects.append({ 'object_type': 'error_text', 'text': 'No user ID specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) if not visible_res_names: output_objects.append({ 'object_type': 'error_text', 'text': 'No resource ID specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) # NOTE: we support exactly one resource but multiple users here unique_resource_name = visible_res_names[-1].strip() target_name = unique_resource_name res_map = get_resource_map(configuration) if unique_resource_name not in res_map: output_objects.append({ 'object_type': 'error_text', 'text': 'No such resource: %s' % unique_resource_name }) return (output_objects, returnvalues.CLIENT_ERROR) owners_list = res_map[unique_resource_name][OWNERS] if not client_id in owners_list: output_objects.append({ 'object_type': 'error_text', 'text': 'You are not an owner of %s!' % unique_resource_name }) output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid resource %s message!' % request_type }) return (output_objects, returnvalues.CLIENT_ERROR) target_id = '%s resource owners' % unique_resource_name target_name = unique_resource_name target_list = [user_id.strip() for user_id in visible_user_names] elif request_type == "resourceowner": if not visible_res_names: output_objects.append({ 'object_type': 'error_text', 'text': 'No resource ID specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) # NOTE: we support exactly one resource but multiple users here unique_resource_name = visible_res_names[-1].strip() anon_map = anon_to_real_res_map(configuration.resource_home) if unique_resource_name in anon_map: unique_resource_name = anon_map[unique_resource_name] target_name = unique_resource_name res_map = get_resource_map(configuration) if unique_resource_name not in res_map: output_objects.append({ 'object_type': 'error_text', 'text': 'No such resource: %s' % unique_resource_name }) return (output_objects, returnvalues.CLIENT_ERROR) target_list = res_map[unique_resource_name][OWNERS] if client_id in target_list: output_objects.append({ 'object_type': 'error_text', 'text': 'You are already an owner of %s!' % unique_resource_name }) return (output_objects, returnvalues.CLIENT_ERROR) request_dir = os.path.join(configuration.resource_home, unique_resource_name) access_request = { 'request_type': request_type, 'entity': client_id, 'target': unique_resource_name, 'request_text': request_text } if not save_access_request(configuration, request_dir, access_request): output_objects.append({ 'object_type': 'error_text', 'text': 'Could not save request - owners may still manually add you' }) return (output_objects, returnvalues.SYSTEM_ERROR) elif request_type in ["vgridmember", "vgridowner", "vgridresource"]: if not vgrid_name: output_objects.append({ 'object_type': 'error_text', 'text': 'No vgrid_name specified!' }) return (output_objects, returnvalues.CLIENT_ERROR) # default vgrid is read-only if vgrid_name.upper() == default_vgrid.upper(): output_objects.append({ 'object_type': 'error_text', 'text': 'No requests for %s are not allowed!' % default_vgrid }) return (output_objects, returnvalues.CLIENT_ERROR) # stop owner or member request if already an owner # and prevent repeated resource access requests if request_type == 'vgridresource': # NOTE: we support exactly one resource here unique_resource_name = visible_res_names[-1].strip() target_id = entity = unique_resource_name if vgrid_is_resource(vgrid_name, unique_resource_name, configuration): output_objects.append({ 'object_type': 'error_text', 'text': 'You already have access to %s or a parent %s.' % (vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) else: target_id = entity = client_id if vgrid_is_owner(vgrid_name, client_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': 'You are already an owner of %s or a parent %s!' % (vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) # only ownership requests are allowed for existing members if request_type == 'vgridmember': if vgrid_is_member(vgrid_name, client_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': 'You are already a member of %s or a parent %s.' % (vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) # Find all VGrid owners configured to receive notifications target_name = vgrid_name (settings_status, settings_dict) = vgrid_settings(vgrid_name, configuration, recursive=True, as_dict=True) if not settings_status: settings_dict = {} request_recipients = settings_dict.get('request_recipients', default_vgrid_settings_limit) # We load and use direct owners first if any - otherwise inherited owners_list = [] for inherited in (False, True): (owners_status, owners_list) = vgrid_owners(vgrid_name, configuration, recursive=inherited) if not owners_status: output_objects.append({ 'object_type': 'error_text', 'text': 'Failed to lookup owners for %s %s - sure it exists?' % (vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) elif owners_list: break if not owners_list: output_objects.append({ 'object_type': 'error_text', 'text': 'Failed to lookup owners for %s %s - sure it exists?' % (vgrid_name, label) }) return (output_objects, returnvalues.CLIENT_ERROR) # Now we have direct or inherited owners to notify target_list = owners_list[:request_recipients] request_dir = os.path.join(configuration.vgrid_home, vgrid_name) access_request = { 'request_type': request_type, 'entity': entity, 'target': vgrid_name, 'request_text': request_text } if not save_access_request(configuration, request_dir, access_request): output_objects.append({ 'object_type': 'error_text', 'text': 'Could not save request - owners may still manually add you' }) return (output_objects, returnvalues.SYSTEM_ERROR) else: output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid request type: %s' % request_type }) return (output_objects, returnvalues.CLIENT_ERROR) # Now send request to all targets in turn # TODO: inform requestor if no owners have mail/IM set in their settings logger.debug("sending notification to recipients: %s" % target_list) for target in target_list: if not target: logger.warning("skipping empty notify target: %s" % target_list) continue # USER_CERT entry is destination notify = [] for proto in protocols: notify.append('%s: SETTINGS' % proto) job_dict = { 'NOTIFY': notify, 'JOB_ID': 'NOJOBID', 'USER_CERT': target, 'EMAIL_SENDER': client_email } notifier = notify_user_thread( job_dict, [target_id, target_name, request_type, request_text, reply_to], 'SENDREQUEST', logger, '', configuration, ) # Try finishing delivery but do not block forever on one message notifier.join(30) output_objects.append({ 'object_type': 'text', 'text': 'Sent %s message to %d people' % (request_type, len(target_list)) }) im_notify_protocols = [ i for i in configuration.notify_protocols if i != 'email' ] if im_notify_protocols: enabled_notify = 'IM / email' else: enabled_notify = 'email' output_objects.append({ 'object_type': 'text', 'text': """Please make sure you have %s notifications configured on your Setings page if you expect a reply to this message""" % enabled_notify }) 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'] = "Administrate %s" % label # NOTE: Delay header entry here to include vgrid name (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] # prepare for confirm dialog, tablesort and toggling the views (css/js) # jquery support for tablesorter and confirmation on request and leave # requests table initially sorted by 0, 4, 3 (type first, then date and # with alphabetical client ID last) # sharelinks table initially sorted by 5, 4 reversed (active first and # in growing age) table_specs = [{ 'table_id': 'accessrequeststable', 'pager_id': 'accessrequests_pager', 'sort_order': '[[0,0],[4,0],[3,0]]' }, { 'table_id': 'sharelinkstable', 'pager_id': 'sharelinks_pager', 'sort_order': '[[5,1],[4,1]]' }] (add_import, add_init, add_ready) = man_base_js(configuration, table_specs, {'width': 600}) add_init += ''' var toggleHidden = function(classname) { // classname supposed to have a leading dot $(classname).toggleClass("hidden"); }; /* helpers for dynamic form input fields */ function onOwnerInputChange() { makeSpareFields("#dynownerspares", "cert_id"); } function onMemberInputChange() { makeSpareFields("#dynmemberspares", "cert_id"); } function onResourceInputChange() { makeSpareFields("#dynresourcespares", "unique_resource_name"); } ''' add_ready += ''' /* init add owners/member/resource forms with dynamic input fields */ onOwnerInputChange(); $("#dynownerspares").on("blur", "input[name=cert_id]", function(event) { //console.debug("in add owner blur handler"); onOwnerInputChange(); } ); onMemberInputChange(); $("#dynmemberspares").on("blur", "input[name=cert_id]", function(event) { //console.debug("in add member blur handler"); onMemberInputChange(); } );''' if configuration.site_enable_resources: add_ready += ''' onResourceInputChange(); $("#dynresourcespares").on("blur", "input[name=unique_resource_name]", function(event) { console.debug("in resource blur handler"); onResourceInputChange(); } ); ''' 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) }) form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'short_title': configuration.short_title, 'vgrid_label': label, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } output_objects.append({ 'object_type': 'header', 'text': "Administrate '%s'" % vgrid_name }) if not vgrid_is_owner(vgrid_name, client_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': 'Only owners of %s can administrate it.' % vgrid_name }) target_op = "sendrequestaction" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) js_name = 'reqvgridowner%s' % hexlify(vgrid_name) helper = html_post_helper( js_name, '%s.py' % target_op, { 'vgrid_name': vgrid_name, 'request_type': 'vgridowner', 'request_text': '', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({ 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s');" % (js_name, "Request ownership of " + vgrid_name + ":<br/>" + "\nPlease write a message to the owners below.", 'request_text'), 'class': 'addadminlink iconspace', 'title': 'Request ownership of %s' % vgrid_name, 'text': 'Apply to become an owner' }) return (output_objects, returnvalues.SYSTEM_ERROR) for (item, scr) in zip(['owner', 'member', 'resource'], ['vgridowner', 'vgridmember', 'vgridres']): if item == 'resource' and not configuration.site_enable_resources: continue output_objects.append({ 'object_type': 'sectionheader', 'text': "%ss" % item.title() }) (init_status, oobjs) = vgrid_add_remove_table(client_id, vgrid_name, item, scr, configuration) if not init_status: output_objects.extend(oobjs) return (output_objects, returnvalues.SYSTEM_ERROR) else: output_objects.append({ 'object_type': 'html_form', 'text': '<div class="div-%s">' % item }) output_objects.append({ 'object_type': 'link', 'destination': "javascript:toggleHidden('.div-%s');" % item, 'class': 'removeitemlink iconspace', 'title': 'Toggle view', 'text': 'Hide %ss' % item.title() }) output_objects.extend(oobjs) output_objects.append({ 'object_type': 'html_form', 'text': '</div><div class="hidden div-%s">' % item }) output_objects.append({ 'object_type': 'link', 'destination': "javascript:toggleHidden('.div-%s');" % item, 'class': 'additemlink iconspace', 'title': 'Toggle view', 'text': 'Show %ss' % item.title() }) output_objects.append({ 'object_type': 'html_form', 'text': '</div>' }) # Pending requests target_op = "addvgridowner" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( "acceptvgridownerreq", "%s.py" % target_op, { 'vgrid_name': vgrid_name, 'cert_id': '__DYNAMIC__', 'request_name': '__DYNAMIC__', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) target_op = "addvgridmember" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( "acceptvgridmemberreq", "%s.py" % target_op, { 'vgrid_name': vgrid_name, 'cert_id': '__DYNAMIC__', 'request_name': '__DYNAMIC__', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) target_op = "addvgridres" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( "acceptvgridresourcereq", "%s.py" % target_op, { 'vgrid_name': vgrid_name, 'unique_resource_name': '__DYNAMIC__', 'request_name': '__DYNAMIC__', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) target_op = "rejectvgridreq" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( "rejectvgridreq", "%s.py" % target_op, { 'vgrid_name': vgrid_name, 'request_name': '__DYNAMIC__', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) request_dir = os.path.join(configuration.vgrid_home, vgrid_name) request_list = [] for req_name in list_access_requests(configuration, request_dir): req = load_access_request(configuration, request_dir, req_name) if not req: continue if not req.get('request_type', None) in ["vgridowner", "vgridmember", "vgridresource"]: logger.error("unexpected request_type %(request_type)s" % req) continue request_item = build_accessrequestitem_object(configuration, req) # Convert filename with exotic chars into url-friendly pure hex version shared_args = {"request_name": hexlify(req["request_name"])} accept_args, reject_args = {}, {} accept_args.update(shared_args) reject_args.update(shared_args) if req['request_type'] == "vgridresource": accept_args["unique_resource_name"] = req["entity"] else: accept_args["cert_id"] = req["entity"] request_item['acceptrequestlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ("accept%(request_type)sreq" % req, "Accept %(target)s %(request_type)s request from %(entity)s" % req, 'undefined', "{%s}" % ', '.join(["'%s': '%s'" % pair for pair in accept_args.items()])), 'class': 'addlink iconspace', 'title': 'Accept %(target)s %(request_type)s request from %(entity)s' % req, 'text': '' } request_item['rejectrequestlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ("rejectvgridreq", "Reject %(target)s %(request_type)s request from %(entity)s" % req, 'undefined', "%s" % reject_args), 'class': 'removelink iconspace', 'title': 'Reject %(target)s %(request_type)s request from %(entity)s' % req, 'text': '' } request_list.append(request_item) output_objects.append({ 'object_type': 'sectionheader', 'text': "Pending Requests" }) output_objects.append({ 'object_type': 'table_pager', 'id_prefix': 'accessrequests_', 'entry_name': 'access requests', 'default_entries': default_pager_entries }) output_objects.append({ 'object_type': 'accessrequests', 'accessrequests': request_list }) # VGrid Share links # Table columns to skip skip_list = [ 'editsharelink', 'delsharelink', 'invites', 'expire', 'single_file' ] # NOTE: Inheritance is a bit tricky for sharelinks because parent shares # only have relevance if they actually share a path that is a prefix of # vgrid_name. (share_status, share_list) = vgrid_sharelinks(vgrid_name, configuration) sharelinks = [] if share_status: for share_dict in share_list: rel_path = share_dict['path'].strip(os.sep) parent_vgrids = vgrid_list_parents(vgrid_name, configuration) include_share = False # Direct sharelinks (careful not to greedy match A/B with A/BCD) if rel_path == vgrid_name or \ rel_path.startswith(vgrid_name+os.sep): include_share = True # Parent vgrid sharelinks that in effect also give access here for parent in parent_vgrids: if rel_path == parent: include_share = True if include_share: share_item = build_sharelinkitem_object( configuration, share_dict) sharelinks.append(share_item) else: logger.warning("failed to load vgrid sharelinks for %s: %s" % (vgrid_name, share_list)) output_objects.append({ 'object_type': 'sectionheader', 'text': "Share Links" }) output_objects.append({ 'object_type': 'html_form', 'text': '<p>Current share links in %s shared folder</p>' % vgrid_name }) output_objects.append({ 'object_type': 'table_pager', 'id_prefix': 'sharelinks_', 'entry_name': 'share links', 'default_entries': default_pager_entries }) output_objects.append({ 'object_type': 'sharelinks', 'sharelinks': sharelinks, 'skip_list': skip_list }) # VGrid settings output_objects.append({'object_type': 'sectionheader', 'text': "Settings"}) (direct_status, direct_dict) = vgrid_settings(vgrid_name, configuration, recursive=False, as_dict=True) if not direct_status or not direct_dict: direct_dict = {} (settings_status, settings_dict) = vgrid_settings(vgrid_name, configuration, recursive=True, as_dict=True) if not settings_status or not settings_dict: settings_dict = {} form_method = 'post' csrf_limit = get_csrf_limit(configuration) # Always set these values settings_dict.update({ 'vgrid_name': vgrid_name, 'vgrid_label': label, 'owners': keyword_owners, 'members': keyword_members, 'all': keyword_all, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit }) target_op = 'vgridsettings' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) settings_dict.update({'target_op': target_op, 'csrf_token': csrf_token}) settings_form = ''' <form method="%(form_method)s" action="%(target_op)s.py"> <fieldset> <legend>%(vgrid_label)s configuration</legend> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> <input type="hidden" name="vgrid_name" value="%(vgrid_name)s" /> ''' description = settings_dict.get('description', '') settings_form += ''' <h4>Public description</h4> <textarea class="fillwidth padspace" name="description" rows=10 >%s</textarea> ''' % description settings_form += '<br/>' settings_form += '''<p>All visibility options below can be set to owners, members or everyone and by default only owners can see participation. In effect setting visibility to <em>members</em> means that owners and members can see the corresponding participants. Similarly setting a visibility flag to <em>everyone</em> means that all %s users can see the participants.</p> ''' % configuration.short_title visibility_options = [("Owners are visible to", "visible_owners"), ("Members are visible to", "visible_members"), ("Resources are visible to", "visible_resources")] for (title, field) in visibility_options: settings_form += '<h4>%s</h4>' % title if direct_dict.get(field, False): choices = _valid_visible + _reset_choice else: choices = _valid_visible + _keep_choice for (key, val) in choices: checked = '' if settings_dict.get(field, keyword_owners) == val: checked = "checked" settings_form += ''' <input type="radio" name="%s" value="%s" %s/> %s ''' % (field, val, checked, key) settings_form += '<br/>' field = 'restrict_settings_adm' restrict_settings_adm = settings_dict.get(field, default_vgrid_settings_limit) if direct_dict.get(field, False): direct_note = _reset_note else: direct_note = _keep_note settings_form += ''' <h4>Restrict Settings</h4> Restrict changing of these settings to only the first <input type="number" name="restrict_settings_adm" min=0 max=999 minlength=1 maxlength=3 value=%d required /> owners %s. ''' % (restrict_settings_adm, direct_note) settings_form += '<br/>' field = 'restrict_owners_adm' restrict_owners_adm = settings_dict.get(field, default_vgrid_settings_limit) if direct_dict.get(field, False): direct_note = _reset_note else: direct_note = _keep_note settings_form += ''' <h4>Restrict Owner Administration</h4> Restrict administration of owners to only the first <input type="number" name="restrict_owners_adm" min=0 max=999 minlength=1 maxlength=3 value=%d required /> owners %s. ''' % (restrict_owners_adm, direct_note) settings_form += '<br/>' field = 'restrict_members_adm' restrict_members_adm = settings_dict.get(field, default_vgrid_settings_limit) if direct_dict.get(field, False): direct_note = _reset_note else: direct_note = _keep_note settings_form += ''' <h4>Restrict Member Administration</h4> Restrict administration of members to only the first <input type="number" name="restrict_members_adm" min=0 max=999 minlength=1 maxlength=3 value=%d required /> owners %s. ''' % (restrict_members_adm, direct_note) settings_form += '<br/>' field = 'restrict_resources_adm' restrict_resources_adm = settings_dict.get(field, default_vgrid_settings_limit) if direct_dict.get(field, False): direct_note = _reset_note else: direct_note = _keep_note settings_form += ''' <h4>Restrict Resource Administration</h4> Restrict administration of resources to only the first <input type="number" name="restrict_resources_adm" min=0 max=999 minlength=1 maxlength=3 value=%d required /> owners %s. ''' % (restrict_resources_adm, direct_note) settings_form += '<br/>' if vgrid_restrict_write_support(configuration): settings_form += '''<p>All write access options below can be set to owners, members or none. By default only owners can write web pages while owners and members can edit data in the shared folders. In effect setting write access to <em>members</em> means that owners and members have full access. Similarly setting a write access flag to <em>owners</em> means that only owners can modify the data, while members can only read and use it. Finally setting a write access flag to <em>none</em> means that neither owners nor members can modify the data there, effectively making it read-only. Some options are not yet supported and thus are disabled below. </p> ''' writable_options = [ ("Shared files write access", "write_shared_files", keyword_members), ("Private web page write access", "write_priv_web", keyword_owners), ("Public web page write access", "write_pub_web", keyword_owners), ] else: writable_options = [] for (title, field, default) in writable_options: settings_form += '<h4>%s</h4>' % title if direct_dict.get(field, False): choices = _valid_write_access + _reset_choice else: choices = _valid_write_access + _keep_choice for (key, val) in choices: disabled = '' # TODO: remove these artifical limits once we support changing # TODO: also add check for vgrid web reshare in sharelink then if field == 'write_shared_files' and val == keyword_owners: disabled = 'disabled' elif field == 'write_priv_web' and val in [ keyword_members, keyword_none ]: disabled = 'disabled' elif field == 'write_pub_web' and val in [ keyword_members, keyword_none ]: disabled = 'disabled' checked = '' if settings_dict.get(field, default) == val: checked = "checked" settings_form += ''' <input type="radio" name="%s" value="%s" %s %s /> %s ''' % (field, val, checked, disabled, key) settings_form += '<br/>' sharelink_options = [("Limit sharelink creation to", "create_sharelink")] for (title, field) in sharelink_options: settings_form += '<h4>%s</h4>' % title if direct_dict.get(field, False): choices = _valid_sharelink + _reset_choice else: choices = _valid_sharelink + _keep_choice for (key, val) in choices: checked = '' if settings_dict.get(field, keyword_owners) == val: checked = "checked" settings_form += ''' <input type="radio" name="%s" value="%s" %s/> %s ''' % (field, val, checked, key) settings_form += '<br/>' field = 'request_recipients' request_recipients = settings_dict.get(field, default_vgrid_settings_limit) if direct_dict.get(field, False): direct_note = _reset_note else: direct_note = _keep_note settings_form += ''' <h4>Request Recipients</h4> Notify only first <input type="number" name="request_recipients" min=0 max=999 minlength=1 maxlength=3 value=%d required /> owners about access requests %s. ''' % (request_recipients, direct_note) settings_form += '<br/>' bool_options = [ ("Hidden", "hidden"), ] for (title, field) in bool_options: settings_form += '<h4>%s</h4>' % title if direct_dict.get(field, False): choices = _valid_bool + _reset_choice else: choices = _valid_bool + _keep_choice for (key, val) in choices: checked, inherit_note = '', '' if settings_dict.get(field, False) == val: checked = "checked" if direct_dict.get(field, False) != \ settings_dict.get(field, False): inherit_note = ''' <span class="warningtext iconspace"> Forced by a parent %(vgrid_label)s. Please disable there first if you want to change the value here.</span>''' % settings_dict settings_form += ''' <input type="radio" name="%s" value="%s" %s /> %s ''' % (field, val, checked, key) settings_form += '%s<br/>' % inherit_note settings_form += '<br/>' settings_form += ''' <input type="submit" value="Save settings" /> </fieldset> </form> ''' output_objects.append({ 'object_type': 'html_form', 'text': settings_form % settings_dict }) # Checking/fixing of missing components output_objects.append({ 'object_type': 'sectionheader', 'text': "Repair/Add Components" }) target_op = 'updatevgrid' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) settings_dict.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="vgrid_name" value="%(vgrid_name)s" /> <input type="submit" value="Repair components" /> </form> ''' % settings_dict }) (owners_status, owners_direct) = vgrid_owners(vgrid_name, configuration, False) if not owners_status: logger.error("failed to load owners for %s: %s" % (vgrid_name, owners_direct)) return (output_objects, returnvalues.SYSTEM_ERROR) (members_status, members_direct) = vgrid_members(vgrid_name, configuration, False) if not members_status: logger.error("failed to load members for %s: %s" % (vgrid_name, members_direct)) return (output_objects, returnvalues.SYSTEM_ERROR) (resources_status, resources_direct) = vgrid_resources(vgrid_name, configuration, False) if not resources_status: logger.error("failed to load resources for %s: %s" % (vgrid_name, resources_direct)) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({ 'object_type': 'sectionheader', 'text': "Delete %s " % vgrid_name }) if len(owners_direct) > 1 or members_direct or resources_direct: output_objects.append({ 'object_type': 'html_form', 'text': ''' To delete <b>%(vgrid)s</b> first remove all resources, members and owners ending with yourself. ''' % { 'vgrid': vgrid_name } }) else: output_objects.append({ 'object_type': 'html_form', 'text': ''' <p>As the last owner you can leave and delete <b>%(vgrid)s</b> including all associated shared files and components.<br/> </p> <p class="warningtext"> You cannot undo such delete operations, so please use with great care! </p> ''' % { 'vgrid': vgrid_name } }) target_op = "rmvgridowner" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) js_name = 'rmlastvgridowner' helper = html_post_helper( js_name, '%s.py' % target_op, { 'vgrid_name': vgrid_name, 'cert_id': client_id, 'flags': 'f', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({ 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s');" % (js_name, 'Really leave and delete %s?' % vgrid_name), 'class': 'removelink iconspace', 'title': 'Leave and delete %s' % vgrid_name, 'text': 'Leave and delete %s' % vgrid_name }) # Spacing output_objects.append({ 'object_type': 'html_form', 'text': ''' <div class="vertical-spacer"></div> ''' }) 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 Owner" % label output_objects.append({ 'object_type': 'header', 'text': 'Add %s Owner(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] # 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) 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 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) 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, 'owner', 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 unless rank is given if rank is None and 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 direct member if vgrid_is_member(vgrid_name, cert_id, configuration, recursive=False): output_objects.append({ 'object_type': 'error_text', 'text': '%s is already a member of %s - please remove first.' % (cert_id, vgrid_name) }) status = returnvalues.CLIENT_ERROR continue # 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) }) status = returnvalues.SYSTEM_ERROR continue 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': """%s is already an owner 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 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 # we DO allow ownership if member of parent vgrid - only handle with care 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 already a member of parent %s %s.''' % (cert_id, label, inherit_vgrid_member) }) # Check if only rank change was requested and apply if so if rank is not None: (add_status, add_msg) = vgrid_add_owners(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 owner %d' % (cert_id, rank) }) # No further action after rank change as everything else exists continue # Getting here means cert_id is not owner of any parent or child vgrids. # may still be member of a parent grid but not a child vgrid. public_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name)) + os.sep private_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name)) + os.sep # 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 user_public_base = os.path.abspath( os.path.join(user_dir, 'public_base')) + os.sep user_private_base = os.path.abspath( os.path.join(user_dir, 'private_base')) + 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 owner) if os.path.exists(user_public_base + vgrid_name): output_objects.append({ 'object_type': 'error_text', 'text': '''Could not add owner, a file or directory in public_base exists with the same name! %s''' % user_dir + vgrid_name }) status = returnvalues.CLIENT_ERROR continue if os.path.exists(user_private_base + vgrid_name): output_objects.append({ 'object_type': 'error_text', 'text': '''Could not add owner, a file or directory in private_base exists with the same name!''' }) status = returnvalues.CLIENT_ERROR continue # vgrid share already exists if user is a member of parent vgrid if not inherit_vgrid_member and os.path.exists(user_dir + vgrid_name): output_objects.append({ 'object_type': 'error_text', 'text': '''Could not add owner, a file or directory in the home directory exists with the same name!''' }) status = returnvalues.CLIENT_ERROR continue # Add (add_status, add_msg) = vgrid_add_owners(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 # create public_base in cert_ids home dir if it does not exists try: os.mkdir(user_public_base) except Exception as exc: pass # create private_base in cert_ids home dir if it does not exists try: os.mkdir(user_private_base) except Exception as exc: pass if is_subvgrid: share_dir = None try: # Example: # vgrid_name = IMADA/STUD/BACH # vgrid_name_last_fragment = BACH # vgrid_name_without_last_fragment = IMADA/STUD/ vgrid_name_last_fragment = \ vgrid_name_parts[len(vgrid_name_parts) - 1].strip() 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 share_dir = user_dir + vgrid_name_without_last_fragment if not os.path.isdir(share_dir): os.makedirs(share_dir) pub_dir = user_public_base + vgrid_name_without_last_fragment if not os.path.isdir(pub_dir): os.makedirs(pub_dir) priv_dir = user_private_base + vgrid_name_without_last_fragment if not os.path.isdir(priv_dir): os.makedirs(priv_dir) except Exception as 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, share_dir)) status = returnvalues.SYSTEM_ERROR continue # create symlink from users home directory to vgrid file directory # unless member of parent vgrid so that it is included already link_src = os.path.abspath(configuration.vgrid_files_home + os.sep + vgrid_name) + os.sep link_dst = user_dir + vgrid_name if not inherit_vgrid_member and \ not make_symlink(link_src, link_dst, logger): output_objects.append({ 'object_type': 'error_text', 'text': 'Could not create link to %s share!' % label }) logger.error('Could not create link to %s files (%s -> %s)' % (label, link_src, link_dst)) status = returnvalues.SYSTEM_ERROR continue public_base_dst = user_public_base + vgrid_name # create symlink for public_base files if not make_symlink(public_base_dir, public_base_dst, logger): output_objects.append({ 'object_type': 'error_text', 'text': 'Could not create link to public_base dir!' }) logger.error( 'Could not create link to public_base dir (%s -> %s)' % (public_base_dir, public_base_dst)) status = returnvalues.SYSTEM_ERROR continue private_base_dst = user_private_base + vgrid_name # create symlink for private_base files if not make_symlink(private_base_dir, private_base_dst, logger): output_objects.append({ 'object_type': 'error_text', 'text': 'Could not create link to private_base dir!' }) status = returnvalues.SYSTEM_ERROR continue 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 add_tracker_admin(configuration, cert_id, vgrid_name, tracker_dir, output_objects): status = returnvalues.SYSTEM_ERROR continue cert_id_added.append(cert_id) 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 owner 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 cert_id_added: output_objects.append({ 'object_type': 'html_form', 'text': 'New owner(s)<br />%s<br />successfully added to %s %s!' '' % ('<br />'.join(cert_id_added), vgrid_name, label) }) cert_id_fields = '' for cert_id in cert_id_added: cert_id_fields += """<input type=hidden name=cert_id value='%s' /> """ % cert_id form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'vgrid_name': vgrid_name, 'cert_id': cert_id, 'protocol': any_protocol, 'short_title': configuration.short_title, 'vgrid_label': label, 'cert_id_fields': cert_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' /> %(cert_id_fields)s <input type=hidden name=protocol value='%(protocol)s' /> <table> <tr> <td class='title'>Custom message to user(s)</td> </tr><tr> <td><textarea name=request_text cols=72 rows=10> We have granted you ownership access to our %(vgrid_name)s %(vgrid_label)s. You can access the %(vgrid_label)s administration page from the %(vgrid_label)ss page on %(short_title)s. Regards, the %(vgrid_name)s %(vgrid_label)s owners </textarea></td> </tr> <tr> <td><input type='submit' value='Inform user(s)' /></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, 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 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) 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, # NOTE: path cannot use wildcards here typecheck_overrides={}, ) if not validate_status: WARNING_MSG = str(accepted) output_objects.append({'object_type': 'warning', 'text': WARNING_MSG}) return (accepted, returnvalues.CLIENT_ERROR) # Convert accepted values to string and filter out NON-set values accepted_joined_values = { key: ''.join(value) for (key, value) in accepted.iteritems() if len(value) > 0 } action = accepted_joined_values['action'] flags = accepted_joined_values['flags'] path = accepted_joined_values['path'] extension = accepted['extension'][-1].strip() logger.debug('%s from %s: %s' % (op_name, client_id, accepted)) if not action in valid_actions: output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid action "%s" (supported: %s)' % (action, ', '.join(valid_actions)) }) return (output_objects, returnvalues.CLIENT_ERROR) if action in post_actions: if not safe_handler( configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted, ): logger.info('checkpoint2') output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) 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.user_home, client_dir)) + os.sep abs_path = os.path.join(base_dir, path) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'IMAGEPREVIEW Management' output_objects.append({ 'object_type': 'header', 'text': 'IMAGEPREVIEW Management' }) status = returnvalues.ERROR vgrid_name = in_vgrid_share(configuration, abs_path) vgrid_owner = vgrid_is_owner(vgrid_name, client_id, configuration) status = returnvalues.OK if vgrid_name is None: status = returnvalues.ERROR ERROR_MSG = "No vgrid found for path: '%s'" % path output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG}) if status == returnvalues.OK: if action == 'list_settings': status = list_settings(configuration, abs_path, path, output_objects) logger.debug('list exit status: %s' % str(status)) elif action == 'remove_setting': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = remove_setting(configuration, abs_path, path, extension, output_objects) logger.debug('remove_setting exit status: %s' % str(status)) elif action == 'get_setting': status = get_setting(configuration, abs_path, path, extension, output_objects) logger.debug('get_setting exit status: %s' % str(status)) elif action == 'update_setting': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = update_setting( configuration, base_dir, abs_path, path, extension, accepted_joined_values, output_objects, ) logger.debug('update_setting exit status: %s' % str(status)) elif action == 'create_setting': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = create_setting( configuration, client_id, base_dir, abs_path, path, extension, accepted_joined_values, output_objects, ) status = returnvalues.OK logger.debug('create_setting exit status: %s' % str(status)) elif action == 'reset_setting': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = reset_settings(configuration, abs_path, path, output_objects, extension) logger.debug('reset exit status: %s' % str(status)) elif action == 'get': status = get(configuration, base_dir, path, output_objects) logger.debug('get exit status: %s' % str(status)) elif action == 'remove': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = remove(configuration, base_dir, abs_path, path, output_objects) logger.debug('remove exit status: %s' % str(status)) elif action == 'clean': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = clean(configuration, base_dir, abs_path, path, output_objects) logger.debug('clean exit status: %s' % str(status)) elif action == 'cleanrecursive': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = clean( configuration, base_dir, abs_path, path, output_objects, recursive=True, ) logger.debug('cleanrecursive exit status: %s' % str(status)) elif action == 'refresh': if vgrid_owner == False: status = returnvalues.ERROR ERROR_MSG = \ "Ownership of vgrid: '%s' required to change imagepreview settings" \ % vgrid_name output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) else: status = refresh( configuration, client_id, base_dir, abs_path, path, output_objects, ) logger.debug('refresh exit status: %s' % str(status)) else: ERROR_MSG = "action: '%s' _NOT_ implemented yet" \ % str(action) output_objects.append({ 'object_type': 'error_text', 'text': ERROR_MSG }) logger.debug('output_objects: %s' % str(output_objects)) logger.debug('status: %s' % str(status)) 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'] = "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 as exc: # ouch, not good. Email admin? pass if os.path.exists(dst): output_objects.append({ 'object_type': 'error_text', 'text': 'Could not remove link to %s files!' % label }) logger.error('Removed member might still have access to %s files! %s' % (label, dst)) return (output_objects, returnvalues.SYSTEM_ERROR) vgrid_name_parts = vgrid_name.split('/') # make sure there are no "" entries in list while True: try: vgrid_name_parts.remove('') vgrid_name_parts.remove('/') except: # no such item break is_subvgrid = len(vgrid_name_parts) >= 2 if is_subvgrid: # remove placeholder dirs (empty dirs created to hold subvgrid) # reverse list to remove files and directories of subdirs first list_range = range(len(vgrid_name_parts)) list_range.reverse() reverse_list = list_range # remove first entry in reversed list (SUBVGRID in VGRID/SUBVGRID since # we know it was the symbolic link and is not a dir) reverse_list = reverse_list[1:] # remove empty placeholder dirs in home dir, private_base and # public_base dirs base_dirs = [user_dir] for base_dir in base_dirs: for loop_count in reverse_list: # note that loop_count is decreasing! current_vgrid_path = \ '/'.join(vgrid_name_parts[0:loop_count + 1]) current_path = base_dir + current_vgrid_path if not os.path.isdir(current_path): output_objects.append({ 'object_type': 'error_text', 'text': '''Error removing %s placeholder dirs: %s is not a directory, not going to remove.''' % (label, current_vgrid_path) }) continue if os.listdir(current_path): output_objects.append({ 'object_type': 'error_text', 'text': '''Could not remove %s placeholder dirs: %s is not an empty directory (not critical)''' % (label, current_vgrid_path) }) else: # remove empty directory try: os.rmdir(current_path) except Exception as exc: output_objects.append({ 'object_type': 'error_text', 'text': '''Error removing %s placeholder dirs: exception removing empty directory %s''' % (label, exc) }) return (output_objects, returnvalues.SYSTEM_ERROR) # remove from list (rm_status, rm_msg) = vgrid_remove_members(configuration, vgrid_name, [cert_id]) if not rm_status: output_objects.append({ 'object_type': 'error_text', 'text': '%s of member of %s' % (rm_msg, vgrid_name) }) output_objects.append({ 'object_type': 'error_text', 'text': '''(If %(vgrid_label)s %(vgrid_name)s has sub-%(vgrid_label)ss then removal must be performed from the most significant %(vgrid_label)s possible.)''' % { 'vgrid_name': vgrid_name, 'vgrid_label': label } }) return (output_objects, returnvalues.SYSTEM_ERROR) unmap_inheritance(configuration, vgrid_name, cert_id) output_objects.append({ 'object_type': 'text', 'text': '%s successfully removed as member of %s %s!' % (cert_id, 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)