def get_user_conf(user_id, configuration, include_meta=False): """Return user profile and settings""" conf = {} profile = load_profile(user_id, configuration, include_meta) if profile: conf.update(profile) settings = load_settings(user_id, configuration, include_meta) if settings: conf.update(settings) return conf
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) output_objects.append({"object_type": "header", "text": "%s Virtual Desktop" % configuration.short_title}) 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) title_entry = find_entry(output_objects, "title") title_entry["text"] = "Virtual Machines" if not configuration.site_enable_vmachines: output_objects.append( { "object_type": "text", "text": """Virtual machines are disabled on this site. Please contact the Grid admins %s if you think they should be enabled. """ % configuration.admin_email, } ) return (output_objects, returnvalues.OK) settings_dict = load_settings(client_id, configuration) if not settings_dict or not settings_dict.has_key("VNCDISPLAY"): logger.info("Settings dict does not have VNCDISPLAY key - using default") (vnc_display_width, vnc_display_height) = (1024, 768) else: (vnc_display_width, vnc_display_height) = settings_dict["VNCDISPLAY"] # Make room for vnc control menu vnc_menu_height = 24 vnc_display_height += vnc_menu_height password = vms.vnc_jobid(accepted["job_id"][0]) # Do an "intoN" then map to acsii output_objects.append( { "object_type": "html_form", "text": vms.popup_snippet() + vms.vnc_applet(configuration, vnc_display_width, vnc_display_height, password), } ) return (output_objects, status)
def initialize_main_variables(client_id, op_title=True, op_header=True, op_menu=True): """Script initialization is identical for most scripts in shared/functionalty. This function should be called in most cases. """ configuration = get_configuration_object() logger = configuration.logger output_objects = [] start_entry = make_start_entry() output_objects.append(start_entry) op_name = os.path.basename(requested_page()).replace(".py", "") if op_title: title_object = make_title_entry("%s" % op_name, skipmenu=(not op_menu)) output_objects.append(title_object) if op_header: header_object = make_header_entry("%s" % op_name) output_objects.append(header_object) if client_id: # add the user-defined menu and widgets (if possible) title = find_entry(output_objects, "title") if title: settings = load_settings(client_id, configuration) if settings: base_menu = settings.get("SITE_BASE_MENU", "default") if not base_menu in configuration.site_base_menu: base_menu = "default" if base_menu == "simple" and configuration.site_simple_menu: title["base_menu"] = configuration.site_simple_menu elif base_menu == "advanced" and configuration.site_advanced_menu: title["base_menu"] = configuration.site_advanced_menu else: title["base_menu"] = configuration.site_default_menu user_menu = settings.get("SITE_USER_MENU", None) if configuration.site_user_menu and user_menu: title["user_menu"] = user_menu if settings.get("ENABLE_WIDGETS", True) and configuration.site_script_deps: user_widgets = load_widgets(client_id, configuration) if user_widgets: title["user_widgets"] = user_widgets return (configuration, logger, output_objects, op_name)
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) output_objects.append({ 'object_type': 'header', 'text': '%s Virtual Desktop' % configuration.short_title }) 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) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Virtual Machines' if not configuration.site_enable_vmachines: output_objects.append({ 'object_type': 'text', 'text': '''Virtual machines are disabled on this site. Please contact the site admins %s if you think they should be enabled. ''' % configuration.admin_email }) return (output_objects, returnvalues.OK) settings_dict = load_settings(client_id, configuration) if not settings_dict or not settings_dict.has_key('VNCDISPLAY'): logger.info( 'Settings dict does not have VNCDISPLAY key - using default') (vnc_display_width, vnc_display_height) = (1024, 768) else: (vnc_display_width, vnc_display_height) = settings_dict['VNCDISPLAY'] # Make room for vnc control menu vnc_menu_height = 24 vnc_display_height += vnc_menu_height password = vms.vnc_jobid(accepted['job_id'][0]) mig_cert_base = configuration.migserver_https_mig_cert_url ext_cert_base = configuration.migserver_https_ext_cert_url mig_oid_base = configuration.migserver_https_mig_oid_url ext_oid_base = configuration.migserver_https_ext_oid_url if os.environ['REQUEST_URI'].startswith(mig_cert_base): https_base = mig_cert_base elif os.environ['REQUEST_URI'].startswith(ext_cert_base): https_base = ext_cert_base elif os.environ['REQUEST_URI'].startswith(mig_oid_base): https_base = mig_oid_base elif os.environ['REQUEST_URI'].startswith(ext_oid_base): https_base = ext_oid_base else: logger.warning("unexpected REQUEST_URI: %(REQUEST_URI)s" % os.environ) https_base = mig_cert_base # Do an "intoN" then map to acsii output_objects.append({ 'object_type': 'html_form', 'text': vms.popup_snippet() + vms.vnc_applet( configuration, vnc_display_width, vnc_display_height, password, https_base, ) }) output_objects.append({ 'object_type': 'html_form', 'text': """<p>You can access your virtual machine with the Java applet above if your browser supports it, or by using a stand-alone VNC client and the following connection details:<br /> VNC server: %s<br /> VNC port: %s<br /> VNC password: %s<br/> as an example if you use the xtightvnc client the command line would be <br/> <tt> xtightvncviewer %s::%d </tt> <br/> using the password above when prompted.<br/> VNC does not use encryption so please be careful where you use it from and preferably use an SSH tunnel to at least encrypt the connection if accessing this site over the Internet.<br/> Please refer to the documentation on the <em>-via</em> VNC option for details. </p> """ % (configuration.server_fqdn, configuration.vm_client_port, password, configuration.server_fqdn, configuration.vm_client_port) }) return (output_objects, status)
def notify_user( jobdict, args_list, status, logger, statusfile, configuration, ): """Send notification messages about job to user. User settings are used if notification fields are left empty or set to 'SETTINGS'. Please note that this function may take a long time to deliver notifications, or even block forever if an IM is requested and no IM daemon is running. Thus it should be run in a separate thread or process if blocking is not allowed. Please take a look at notify_user_thread() if that is a requirement. """ # Usage records: quickly hacked in here. # later, we might want a general plugin / hook interface # first of all, write out the usage record (if configured) ur_destination = configuration.usage_record_dir if ur_destination: logger.debug('XML Usage Record directory %s' % ur_destination) usage_record = UsageRecord(configuration, logger) usage_record.fill_from_dict(jobdict) # we use the job_id as a file name (should be unique) usage_record.write_xml(ur_destination + os.sep + jobdict['JOB_ID'] + '.xml') jobid = jobdict['JOB_ID'] email_sender = jobdict.get('EMAIL_SENDER', None) for notify_line in jobdict['NOTIFY']: logger.debug('notify line: %s' % notify_line) (header, message) = create_notify_message(jobdict, args_list, status, statusfile, configuration) supported_protocols = ['jabber', 'msn', 'icq', 'aol', 'yahoo'] notify_line_colon_split = notify_line.split(':', 1) if notify_line_colon_split[0].strip() in supported_protocols: protocol = notify_line_colon_split[0] recipients = notify_line_colon_split[1].strip() all_dest = [] # Empty or if recipients.strip().upper() in ['SETTINGS', '']: # read from personal settings settings_dict = load_settings(jobdict['USER_CERT'], configuration) if not settings_dict\ or not settings_dict.has_key(protocol.upper()): logger.info('Settings dict does not have %s key' % protocol.upper()) continue all_dest = settings_dict[protocol.upper()] else: all_dest.append(recipients) for single_dest in all_dest: logger.debug('notifying %s about %s' % (single_dest, jobid)) # NOTE: Check removed because icq addresses are numbers and not "emails" # if not is_valid_simple_email(single_dest): # not a valid address (IM account names are on standard email format) # continue............................ if send_instant_message( single_dest, protocol, header, message, logger, configuration, ): logger.info('Instant message sent to %s' % single_dest + ' protocol: %s telling that %s %s' % (protocol, jobid, status)) else: logger.error( 'Instant message NOT sent to %s protocol %s jobid: %s' % (single_dest, protocol, jobid)) else: notify_line_first_part = notify_line_colon_split[0].strip() all_dest = [] if notify_line_first_part in email_keyword_list or \ notify_line_first_part == 'SETTINGS': logger.info( "'%s' notify_line_first_part found in email_keyword_list" % notify_line_first_part) recipients = notify_line.replace( '%s:' % notify_line_first_part, '').strip() if recipients.strip().upper() in ['SETTINGS', '']: # read from personal settings settings_dict = load_settings(jobdict['USER_CERT'], configuration) if not settings_dict: logger.info('Could not load settings_dict') continue if not settings_dict.has_key('EMAIL'): logger.info('Settings dict does not have EMAIL key') continue all_dest = settings_dict['EMAIL'] else: all_dest.append(recipients) elif is_valid_simple_email(notify_line): logger.info("fall back to valid plain email %s" % notify_line) all_dest.append(notify_line) else: logger.warning("No valid mail recipient for %s" % notify_line) continue # send mails for single_dest in all_dest: logger.info('email destination %s' % single_dest) # verify specified address is valid if not is_valid_simple_email(single_dest): logger.info('%s is NOT a valid email address!' % single_dest) # not a valid email address continue if send_email(single_dest, header, message, logger, configuration, custom_sender=email_sender): logger.info('email sent to %s telling that %s %s' % (single_dest, jobid, status)) else: logger.error('email NOT sent to %s, jobid: %s' % (single_dest, jobid))
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) # 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 title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Settings' # prepare support for toggling the views (by css/jquery) title_entry['style'] = themed_styles(configuration) title_entry['style']['skin'] += ''' %s ''' % cm_css title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> %s <script type="text/javascript" > var toggleHidden = function(classname) { // classname supposed to have a leading dot $(classname).toggleClass("hidden"); } $(document).ready(function() { } ); </script> ''' % cm_javascript valid_topics = ['general', 'style'] active_menu = extract_menu(configuration, title_entry) if 'submitjob' in active_menu: valid_topics.append('job') if 'people' in active_menu: valid_topics.append('profile') if configuration.site_script_deps: valid_topics.append('widgets') if configuration.arc_clusters: valid_topics.append('arc') if configuration.site_enable_sftp: valid_topics.append('sftp') if configuration.site_enable_davs: valid_topics.append('webdavs') if configuration.site_enable_ftps: valid_topics.append('ftps') topics = accepted['topic'] # Backwards compatibility if topics and topics[0] == 'ssh': topics[0] = 'sftp' topics = [i for i in topics if i in valid_topics] # Default to general if no valid topics given if not topics: topics.append(valid_topics[0]) topic_titles = dict([(i, i.title()) for i in valid_topics]) for (key, val) in [('sftp', 'SFTP'), ('webdavs', 'WebDAVS'), ('ftps', 'FTPS')]: if key in valid_topics: topic_titles[key] = val output_objects.append({'object_type': 'header', 'text' : 'Settings'}) links = [] for name in valid_topics: active_menu = '' if topics[0] == name: active_menu = 'activebutton' links.append({'object_type': 'link', 'destination': "settings.py?topic=%s" % name, 'class': '%ssettingslink settingsbutton %s' % \ (name, active_menu), 'title': 'Switch to %s settings' % topic_titles[name], 'text' : '%s' % topic_titles[name], }) output_objects.append({'object_type': 'multilinkline', 'links': links, 'sep': ' '}) output_objects.append({'object_type': 'text', 'text': ''}) # load current settings current_settings_dict = load_settings(client_id, configuration) if not current_settings_dict: # no current settings found current_settings_dict = {} if not topics: output_objects.append({'object_type': 'error_text', 'text': 'No valid topics!'}) return (output_objects, returnvalues.CLIENT_ERROR) if 'general' in topics: html = \ ''' <div id="settings"> <form method="post" action="settingsaction.py"> <table class="settings fixedlayout"> <tr class="title"><td class="centertext"> Select your %s settings </td></tr> <tr><td> </td></tr> <tr><td> <input type="hidden" name="topic" value="general" /> Please note that if you want to set multiple values (e.g. addresses) in the same field, you must write each value on a separate line but without blank lines. </td></tr> <tr><td> </td></tr> ''' % configuration.short_title settings_entries = get_settings_specs() for (keyword, val) in settings_entries: if 'SUBMITUI' == keyword and \ 'job' not in valid_topics: continue if 'notify' == val['Context'] and \ keyword.lower() not in configuration.notify_protocols: continue entry = \ """ <tr class='title'><td> %s </td></tr> <tr><td> %s </td></tr> <tr><td> """\ % (keyword.replace('_', ' ').title(), val['Description']) if val['Type'] == 'multiplestrings': try: # get valid choices from conf. multiple selections valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = [] if current_settings_dict.has_key(keyword): current_choice = current_settings_dict[keyword] if len(valid_choices) > 0: entry += '<div class="scrollselect">' for choice in valid_choices: selected = '' if choice in current_choice: selected = 'checked' entry += ''' <input type="checkbox" name="%s" %s value="%s">%s<br />''' % \ (keyword, selected, choice, choice) entry += '</div>' else: entry = '' except: # failed on evaluating configuration.%s area = ''' <textarea id="%s" cols=40 rows=1 name="%s">''' % \ (keyword, keyword) if current_settings_dict.has_key(keyword): area += '\n'.join(current_settings_dict[keyword]) area += '</textarea>' entry += wrap_edit_area(keyword, area, general_edit, 'BASIC') elif val['Type'] == 'string': # get valid choices from conf valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = '' if current_settings_dict.has_key(keyword): current_choice = current_settings_dict[keyword] if len(valid_choices) > 0: entry += '<select name="%s">' % keyword for choice in valid_choices: selected = '' if choice == current_choice: selected = 'selected' entry += '<option %s value="%s">%s</option>'\ % (selected, choice, choice) entry += '</select><br />' else: entry = '' elif val['Type'] == 'boolean': current_choice = '' if current_settings_dict.has_key(keyword): current_choice = current_settings_dict[keyword] entry += '<select name="%s">' % keyword for choice in (True, False): selected = '' if choice == current_choice: selected = 'selected' entry += '<option %s value="%s">%s</option>'\ % (selected, choice, choice) entry += '</select><br />' html += """%s </td></tr> """ % entry html += \ """ <tr><td> <input type="submit" value="Save General Settings" /> </td></tr> </table> </form> </div> """ output_objects.append({'object_type': 'html_form', 'text': html}) if 'job' in topics: mrsl_path = os.path.join(base_dir, default_mrsl_filename) default_mrsl = get_default_mrsl(mrsl_path) html = \ ''' <div id="defaultmrsl"> <form method="post" action="editfile.py"> <table class="defaultjob fixedlayout"> <tr class="title"><td class="centertext"> Default job on submit page </td></tr> <tr><td> </td></tr> <tr><td> If you use the same fields and values in many of your jobs, you can save your preferred job description here to always start out with that description on your submit job page. </td></tr> <tr><td> </td></tr> <tr><td> <input type="hidden" name="path" value="%(mrsl_template)s" /> <input type="hidden" name="newline" value="unix" /> ''' keyword = "defaultjob" area = ''' <textarea id="%(keyword)s" cols=82 rows=25 name="editarea"> %(default_mrsl)s </textarea> ''' html += wrap_edit_area(keyword, area, cm_options, 'BASIC') html += ''' </td></tr> <tr><td> <input type="submit" value="Save Job Template" /> </td></tr> </table> </form> </div> ''' html = html % { 'default_mrsl': default_mrsl, 'mrsl_template': default_mrsl_filename, 'site': configuration.short_title, 'keyword': keyword } output_objects.append({'object_type': 'html_form', 'text': html}) if 'style' in topics: css_path = os.path.join(base_dir, default_css_filename) default_css = get_default_css(css_path) html = \ ''' <div id="defaultcss"> <form method="post" action="editfile.py"> <table class="defaultstyle fixedlayout"> <tr class="title"><td class="centertext"> Default CSS (style) for all pages </td></tr> <tr><td> </td></tr> <tr><td> If you want to customize the look and feel of the %(site)s web interfaces you can override default values here. If you leave the style file blank you will just use the default style.<br /> You can copy paste from the available style file links below if you want to override specific parts.<br /> <div class="warningtext">Please note that you can not save an empty style file, but must at least leave a blank line to use defaults. Additionally some errors in your style code may potentially cause severe corruption in your page layouts, so it may be a good idea to keep another browser tab/window ready to (re)move your .default.css file to restore the defaults while experimenting here. </div> </td></tr> <tr><td> <a class="urllink" href="/images/default.css">default</a> , <a class="urllink" href="/images/bluesky.css">bluesky</a> </td></tr> <tr><td> </td></tr> <tr><td> <input type="hidden" name="path" value="%(css_template)s" /> <input type="hidden" name="newline" value="unix" /> ''' keyword = "defaultstyle" area = ''' <textarea id="%(keyword)s" cols=82 rows=25 min_len=1 name="editarea"> %(default_css)s </textarea> ''' html += wrap_edit_area(keyword, area, style_edit) html += ''' </td></tr> <tr><td> <input type="submit" value="Save Style Settings" /> </td></tr> </table> </form> </div> ''' html = html % { 'default_css': default_css, 'css_template': default_css_filename, 'site': configuration.short_title, 'keyword': keyword } output_objects.append({'object_type': 'html_form', 'text': html}) if 'widgets' in topics: # load current widgets current_widgets_dict = load_widgets(client_id, configuration) if not current_widgets_dict: # no current widgets found current_widgets_dict = {} show_widgets = current_settings_dict.get('ENABLE_WIDGETS', True) if show_widgets: edit_widgets = '''You can simply copy/paste from the available widget file links below if you want to reuse existing widgets.<br /> </td></tr> <tr><td> <a class="urllink" href="/images/widgets/hello-grid.app">hello grid</a>, <a class="urllink" href="/images/widgets/simple-calendar.app">simple calendar</a>, <a class="urllink" href="/images/widgets/calendar.app">calendar</a>, <a class="urllink" href="/images/widgets/gcal.app">google calendar</a>, <a class="urllink" href="/images/widgets/calculator.app">calculator</a>, <a class="urllink" href="/images/widgets/localrss.app">local rss reader</a>, <a class="urllink" href="/images/widgets/rss.app">rss reader</a>, <a class="urllink" href="/images/widgets/clock.app">clock</a>, <a class="urllink" href="/images/widgets/weather.app">weather</a>, <a class="urllink" href="/images/widgets/progressbar.app">progress bar</a>, <a class="urllink" href="/images/widgets/simple-move.app">simple-move</a>, <a class="urllink" href="/images/widgets/portlets.app">portlets</a>, <a class="urllink" href="/images/widgets/countdown.app">countdown</a>, <a class="urllink" href="/images/widgets/sparkline.app">mini chart</a>, <a class="urllink" href="/images/widgets/piechart.app">pie chart</a>, <a class="urllink" href="/images/widgets/simple-jobmon.app">simple-jobmon</a>, <a class="urllink" href="/images/widgets/cert-countdown.app">certificate countdown</a>, <a class="urllink" href="/images/widgets/disk-use.app">disk use progress bar</a>, <a class="urllink" href="/images/widgets/jobs-stats.app">jobs stats table</a>, <a class="urllink" href="/images/widgets/jobs-stats-chart.app">jobs stats chart</a>, <a class="urllink" href="/images/widgets/daily-wm-comic.app">Daily WulffMorgenthaler comic</a>, <a class="urllink" href="/images/widgets/kunet-login.app">KUnet login</a> <a class="urllink" href="/images/widgets/tdchotspot-login.app">TDC Hotspot login</a> </td></tr> <tr><td> <div class="warningtext">Please note that the widgets parser is rather grumpy so you may have to avoid blank lines in your widget code below. Additionally any errors in your widgets code may cause severe corruption in your pages, so it may be a good idea to keep another browser tab/window ready for emergency disabling of widgets while experimenting here.</div> </td></tr> <tr><td> <input type="hidden" name="topic" value="widgets" /> </td></tr> <tr><td> ''' html = \ '''<div id="widgets"> <form method="post" action="settingsaction.py"> <table class="widgets fixedlayout"> <tr class="title"><td class="centertext"> Default user defined widgets for all pages </td></tr> <tr><td> </td></tr> <tr><td> If you want to customize the look and feel of the %s web interfaces you can add your own widgets here. If you leave the widgets blank you will just get the default empty widget spaces.<br /> ''' % configuration.short_title widgets_entries = get_widgets_specs() widgets_html = '' for (keyword, val) in widgets_entries: widgets_html += \ """ <tr class=title><td> %s </td></tr> <tr><td> %s </td></tr> <tr><td> """\ % (keyword.replace('_', ' ').title(), val['Description']) if val['Type'] == 'multiplestrings': try: # get valid choices from conf. multiple selections valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = [] if current_widgets_dict.has_key(keyword): current_choice = current_widgets_dict[keyword] if len(valid_choices) > 0: widgets_html += '<div class="scrollselect">' for choice in valid_choices: selected = '' if choice in current_choice: selected = 'checked' widgets_html += ''' <input type="checkbox" name="%s" %s value="%s">%s<br />'''\ % (keyword, selected, choice, choice) widgets_html += '</div>' except: area = \ """<textarea id='%s' cols=78 rows=10 name='%s'>""" % \ (keyword, keyword) if current_widgets_dict.has_key(keyword): area += '\n'.join(current_widgets_dict[keyword]) area += '</textarea>' widgets_html += wrap_edit_area(keyword, area, widgets_edit) if show_widgets: edit_widgets += ''' %s <tr><td> <input type="submit" value="Save Widgets Settings" /> </td></tr> ''' % widgets_html else: edit_widgets = ''' <br/> <div class="warningtext"> Widgets are disabled on your <em>General</em> settings page. Please enable them there first if you want to customize your grid pages. </div> ''' html += \ ''' %s </table> </form> </div> ''' % edit_widgets output_objects.append({'object_type': 'html_form', 'text': html}) if 'profile' in topics: # load current profile current_profile_dict = load_profile(client_id, configuration) if not current_profile_dict: # no current profile found current_profile_dict = {} (got_list, all_vgrids) = vgrid_list_vgrids(configuration) if not got_list: all_vgrids = [] all_vgrids.append(any_vgrid) all_vgrids.sort() configuration.vgrids_allow_email = all_vgrids configuration.vgrids_allow_im = all_vgrids images = [] for path in os.listdir(base_dir): real_path = os.path.join(base_dir, path) if os.path.splitext(path)[1].strip('.') in profile_img_extensions \ and os.path.getsize(real_path) < profile_img_max_kb*1024: images.append(path) configuration.public_image = images html = \ ''' <div id="profile"> <form method="post" action="settingsaction.py"> <table class="profile fixedlayout"> <tr class="title"><td class="centertext"> Public profile information visible to other users. </td></tr> <tr><td> </td></tr> <tr><td> If you want to let other users know more about you can add your own text here. If you leave the text area blank you will just get the default empty profile information.<br /> </td></tr> <tr><td> <div class="warningtext">Please note that the profile parser is rather grumpy so you may have to avoid blank lines in your text below. </div> </td></tr> <tr><td> <input type="hidden" name="topic" value="profile" /> </td></tr> <tr><td> ''' profile_entries = get_profile_specs() for (keyword, val) in profile_entries: # Mask VGrid name if configured mask_title = keyword.replace( 'VGRID', configuration.site_vgrid_label.upper()) mask_desc = val['Description'].replace( 'VGrid', configuration.site_vgrid_label) html += \ """ <tr class=title><td> %s </td></tr> <tr><td> %s </td></tr> <tr><td> """ % (mask_title.replace('_', ' ').title(), html_escape(mask_desc)) if val['Type'] == 'multiplestrings': try: # get valid choices from conf. multiple selections valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = [] if current_profile_dict.has_key(keyword): current_choice = current_profile_dict[keyword] if len(valid_choices) > 0: html += '<div class="scrollselect">' for choice in valid_choices: selected = '' if choice in current_choice: selected = 'checked' html += ''' <input type="checkbox" name="%s" %s value="%s">%s<br />''' % \ (keyword, selected, choice, choice) html += '</div>' except: area = \ """<textarea id='%s' cols=78 rows=10 name='%s'>""" % \ (keyword, keyword) if current_profile_dict.has_key(keyword): area += '\n'.join(current_profile_dict[keyword]) area += '</textarea>' html += wrap_edit_area(keyword, area, profile_edit) elif val['Type'] == 'boolean': valid_choices = [True, False] current_choice = '' if current_profile_dict.has_key(keyword): current_choice = current_profile_dict[keyword] if len(valid_choices) > 0: html += '<select name="%s">' % keyword for choice in valid_choices: selected = '' if choice == current_choice: selected = 'selected' html += '<option %s value="%s">%s</option>'\ % (selected, choice, choice) html += '</select><br />' html += ''' <tr><td> <input type="submit" value="Save Profile Settings" /> </td></tr> </table> </form> </div> ''' output_objects.append({'object_type': 'html_form', 'text': html}) if 'sftp' in topics: # load current ssh/sftp current_ssh_dict = load_ssh(client_id, configuration) if not current_ssh_dict: # no current ssh found current_ssh_dict = {} default_authkeys = current_ssh_dict.get('authkeys', '') default_authpassword = current_ssh_dict.get('authpassword', '') username = client_alias(client_id) if configuration.user_sftp_alias: username = extract_field(client_id, configuration.user_sftp_alias) create_alias_link(username, client_id, configuration.user_home) sftp_server = configuration.user_sftp_show_address sftp_port = configuration.user_sftp_show_port html = \ ''' <div id="sshaccess"> <form method="post" action="settingsaction.py"> <table class="sshsettings fixedlayout"> <tr class="title"><td class="centertext"> SFTP access to your %(site)s account </td></tr> <tr><td> </td></tr> <tr><td> You can configure SFTP login to your %(site)s account for efficient file access. On Linux/UN*X it also allows transparent access through SSHFS. <br/> <h3>Login Details</h3> <ul> <li>Host <em>%(sftp_server)s</em></li> <li>Port <em>%(sftp_port)s</em></li> <li>Username <em>%(username)s</em></li> <li>%(auth_methods)s <em>as you choose below</em></li> </ul> </td></tr> <tr><td> <input type="hidden" name="topic" value="sftp" /> <div class="div-sftp-client-notes hidden"> <a href="javascript:toggleHidden('.div-sftp-client-notes');" class="removeitemlink" title="Toggle view"> Show less SFTP client details...</a> <h3>Graphical SFTP access</h3> The FireFTP plugin for Firefox is known to generally work for graphical access to your %(site)s home over SFTP. Enter the following values in the FireFTP Account Manager: <pre> Host %(sftp_server)s Login %(username)s Password YOUR_PASSWORD_HERE (passphrase if you configured public key access) Security SFTP Port %(sftp_port)s Private Key ~/.mig/key.pem (if you configured public key access) </pre> other graphical clients may work as well. <h3>Command line SFTP/SSHFS access on Linux/UN*X</h3> Save something like the following lines in your local ~/.ssh/config to avoid typing the full login details every time:<br /> <pre> Host %(sftp_server)s Hostname %(sftp_server)s User %(username)s Port %(sftp_port)s IdentityFile ~/.mig/key.pem </pre> From then on you can use sftp and sshfs to access your %(site)s home: <pre> sftp %(sftp_server)s </pre> <pre> sshfs %(sftp_server)s: mig-home -o uid=$(id -u) -o gid=$(id -g) </pre> You can also integrate with ordinary mounts by adding a line like: <pre> sshfs#%(username)s@%(sftp_server)s: /home/USER/mig-home fuse noauto,user,port=%(sftp_port)d 0 0 </pre> to your /etc/fstab . </div> <div class="div-sftp-client-notes"> <a href="javascript:toggleHidden('.div-sftp-client-notes');" class="additemlink" title="Toggle view">Show more SFTP client details... </a> </div> ''' keyword_keys = "authkeys" if 'publickey' in configuration.user_sftp_auth: html += ''' </td></tr> <tr><td> <h3>Authorized Public Keys</h3> You can use any existing RSA key, or create a new one. If you signed up with a x509 user certificate, you should also have received such a key.pem along with your user certificate. In any case you need to save the contents of the corresponding public key (X.pub) in the text area below, to be able to connect with username and key as described in the Login Details. <br/> ''' area = ''' <textarea id="%(keyword_keys)s" cols=82 rows=5 name="publickeys"> %(default_authkeys)s </textarea> ''' html += wrap_edit_area(keyword_keys, area, ssh_edit, 'BASIC') html += ''' (leave empty to disable sftp access with public keys) </td></tr> ''' keyword_password = "******" if 'password' in configuration.user_sftp_auth: # We only want a single password and a masked input field html += ''' <tr><td> <h3>Authorized Password</h3> Please enter and save your desired password in the text field below, to be able to connect with username and password as described in the Login Details. <br/> <input type=password id="%(keyword_password)s" size=40 name="password" value="%(default_authpassword)s" /> (leave empty to disable sftp access with password) </td></tr> ''' html += ''' <tr><td> <input type="submit" value="Save SFTP Settings" /> </td></tr> ''' html += ''' </table> </form> </div> ''' html = html % { 'default_authkeys': default_authkeys, 'default_authpassword': default_authpassword, 'site': configuration.short_title, 'keyword_keys': keyword_keys, 'keyword_password': keyword_password, 'username': username, 'sftp_server': sftp_server, 'sftp_port': sftp_port, 'auth_methods': ' / '.join(configuration.user_sftp_auth).title(), } output_objects.append({'object_type': 'html_form', 'text': html}) if 'webdavs' in topics: # load current davs current_davs_dict = load_davs(client_id, configuration) if not current_davs_dict: # no current davs found current_davs_dict = {} default_authkeys = current_davs_dict.get('authkeys', '') default_authpassword = current_davs_dict.get('authpassword', '') username = client_alias(client_id) if configuration.user_davs_alias: username = extract_field(client_id, configuration.user_davs_alias) create_alias_link(username, client_id, configuration.user_home) davs_server = configuration.user_davs_show_address davs_port = configuration.user_davs_show_port html = \ ''' <div id="davsaccess"> <form method="post" action="settingsaction.py"> <table class="davssettings fixedlayout"> <tr class="title"><td class="centertext"> WebDAVS access to your %(site)s account </td></tr> <tr><td> </td></tr> <tr><td> You can configure WebDAVS login to your %(site)s account for transparent file access from your PC or workstation.<br/> <h3>Login Details</h3> <ul> <li>Host <em>%(davs_server)s</em></li> <li>Port <em>%(davs_port)s</em></li> <li>Username <em>%(username)s</em></li> <li>%(auth_methods)s <em>as you choose below</em></li> </ul> </td></tr> <tr><td> <input type="hidden" name="topic" value="webdavs" /> <div class="div-webdavs-client-notes hidden"> <a href="javascript:toggleHidden('.div-webdavs-client-notes');" class="removeitemlink" title="Toggle view"> Show less WebDAVS client details...</a> <h3>Graphical WebDAVS access</h3> Several native file browsers and web browsers are known to generally work for graphical access to your %(site)s home over WebDAVS. <br /> Enter the address https://%(davs_server)s:%(davs_port)s and when fill in the login details: <pre> Username %(username)s Password YOUR_PASSWORD_HERE </pre> other graphical clients should work as well. <h3>Command line WebDAVS access on Linux/UN*X</h3> Save something like the following lines in your local ~/.netrc to avoid typing the full login details every time:<br /> <pre> machine %(davs_server)s login %(username)s password YOUR_PASSWORD_HERE </pre> From then on you can use e.g. cadaver or fusedav to access your %(site)s home: <pre> cadaver https://%(davs_server)s:%(davs_port)s </pre> <pre> fusedav https://%(davs_server)s:%(davs_port)s mig-home -o uid=$(id -u) -o gid=$(id -g) </pre> </div> <div class="div-webdavs-client-notes"> <a href="javascript:toggleHidden('.div-webdavs-client-notes');" class="additemlink" title="Toggle view"> Show more WebDAVS client details...</a> </div> ''' keyword_keys = "authkeys" if 'publickey' in configuration.user_davs_auth: html += ''' </td></tr> <tr><td> <h3>Authorized Public Keys</h3> You can use any existing RSA key, including the key.pem you received along with your user certificate, or create a new one. In any case you need to save the contents of the corresponding public key (X.pub) in the text area below, to be able to connect with username and key as described in the Login Details. <br/>''' area = ''' <textarea id="%(keyword_keys)s" cols=82 rows=5 name="publickeys"> %(default_authkeys)s </textarea> ''' html += wrap_edit_area(keyword_keys, area, davs_edit, 'BASIC') html += ''' (leave empty to disable davs access with public keys) </td></tr> ''' keyword_password = "******" if 'password' in configuration.user_davs_auth: # We only want a single password and a masked input field html += ''' <tr><td> <h3>Authorized Password</h3> Please enter and save your desired password in the text field below, to be able to connect with username and password as described in the Login Details. <br/> <input type=password id="%(keyword_password)s" size=40 name="password" value="%(default_authpassword)s" /> (leave empty to disable davs access with password) </td></tr> ''' html += ''' <tr><td> <input type="submit" value="Save WebDAVS Settings" /> </td></tr> ''' html += ''' </table> </form> </div> ''' html = html % { 'default_authkeys': default_authkeys, 'default_authpassword': default_authpassword, 'site': configuration.short_title, 'keyword_keys': keyword_keys, 'keyword_password': keyword_password, 'username': username, 'davs_server': davs_server, 'davs_port': davs_port, 'auth_methods': ' / '.join(configuration.user_davs_auth).title(), } output_objects.append({'object_type': 'html_form', 'text': html}) if 'ftps' in topics: # load current ftps current_ftps_dict = load_ftps(client_id, configuration) if not current_ftps_dict: # no current ftps found current_ftps_dict = {} default_authkeys = current_ftps_dict.get('authkeys', '') default_authpassword = current_ftps_dict.get('authpassword', '') username = client_alias(client_id) if configuration.user_ftps_alias: username = extract_field(client_id, configuration.user_ftps_alias) create_alias_link(username, client_id, configuration.user_home) ftps_server = configuration.user_ftps_show_address ftps_ctrl_port = configuration.user_ftps_show_ctrl_port html = \ ''' <div id="ftpsaccess"> <form method="post" action="settingsaction.py"> <table class="ftpssettings fixedlayout"> <tr class="title"><td class="centertext"> FTPS access to your %(site)s account </td></tr> <tr><td> </td></tr> <tr><td> You can configure FTPS login to your %(site)s account for efficient file access.<br/> <h3>Login Details</h3> <ul> <li>Host <em>%(ftps_server)s</em></li> <li>Port <em>%(ftps_ctrl_port)s</em></li> <li>Username <em>%(username)s</em></li> <li>%(auth_methods)s <em>as you choose below</em></li> </ul> </td></tr> <tr><td> <input type="hidden" name="topic" value="ftps" /> <div class="div-ftps-client-notes hidden"> <a href="javascript:toggleHidden('.div-ftps-client-notes');" class="removeitemlink" title="Toggle view"> Show less FTPS client details...</a> <h3>Graphical FTPS access</h3> The FireFTP plugin for Firefox is known to generally work for graphical access to your %(site)s home over FTPS. Enter the following values in the FireFTP Account Manager: <pre> Host %(ftps_server)s Login %(username)s Password YOUR_PASSWORD_HERE Security FTPS Port %(ftps_ctrl_port)s </pre> Other FTP clients and web browsers may work as well if you enter the address ftps://%(ftps_server)s:%(ftps_ctrl_port)s and fill in the login details when prompted: <pre> Username %(username)s Password YOUR_PASSWORD_HERE </pre> <h3>Command line FTPS access on Linux/UN*X</h3> Save something like the following lines in your local ~/.netrc to avoid typing the full login details every time:<br /> <pre> machine %(ftps_server)s login %(username)s password YOUR_PASSWORD_HERE </pre> From then on you can use e.g. lftp or CurlFtpFS to access your %(site)s home: <!-- TODO: we need to provide the intermediate cert for server cert check like this set ssl:ca-file sub.class1.server.ca.pem --> <pre> lftp -e "set ssl:verify-certificate no; set ftp:ssl-protect-data on" \\ -p %(ftps_ctrl_port)s %(ftps_server)s </pre> <pre> curlftpfs -o ssl %(ftps_server)s:%(ftps_ctrl_port)s mig-home \\ -o user=%(username)s -ouid=$(id -u) -o gid=$(id -g) -o no_verify_peer </pre> </div> <div class="div-ftps-client-notes"> <a href="javascript:toggleHidden('.div-ftps-client-notes');" class="additemlink" title="Toggle view">Show more FTPS client details... </a> </div> ''' keyword_keys = "authkeys" if 'publickey' in configuration.user_ftps_auth: html += ''' </td></tr> <tr><td> <h3>Authorized Public Keys</h3> You can use any existing RSA key, including the key.pem you received along with your user certificate, or create a new one. In any case you need to save the contents of the corresponding public key (X.pub) in the text area below, to be able to connect with username and key as described in the Login Details. <br/> ''' area = ''' <textarea id="%(keyword_keys)s" cols=82 rows=5 name="publickeys"> %(default_authkeys)s </textarea> ''' html += wrap_edit_area(keyword_keys, area, ftps_edit, 'BASIC') html += ''' (leave empty to disable ftps access with public keys) </td></tr> ''' keyword_password = "******" if 'password' in configuration.user_ftps_auth: # We only want a single password and a masked input field html += ''' <tr><td> <h3>Authorized Password</h3> Please enter and save your desired password in the text field below, to be able to connect with username and password as described in the Login Details. <br/> <input type=password id="%(keyword_password)s" size=40 name="password" value="%(default_authpassword)s" /> (leave empty to disable ftps access with password) </td></tr> ''' html += ''' <tr><td> <input type="submit" value="Save FTPS Settings" /> </td></tr> ''' html += ''' </table> </form> </div> ''' html = html % { 'default_authkeys': default_authkeys, 'default_authpassword': default_authpassword, 'site': configuration.short_title, 'keyword_keys': keyword_keys, 'keyword_password': keyword_password, 'username': username, 'ftps_server': ftps_server, 'ftps_ctrl_port': ftps_ctrl_port, 'auth_methods': ' / '.join(configuration.user_ftps_auth).title(), } output_objects.append({'object_type': 'html_form', 'text': html}) # if ARC-enabled server: if 'arc' in topics: # provide information about the available proxy, offer upload try: home_dir = os.path.normpath(base_dir) session_Ui = arc.Ui(home_dir, require_user_proxy=True) proxy = session_Ui.getProxy() if proxy.IsExpired(): # can rarely happen, constructor will throw exception output_objects.append({'object_type': 'text', 'text': 'Proxy certificate is expired.'}) else: output_objects.append({'object_type': 'text', 'text': 'Proxy for %s' \ % proxy.GetIdentitySN()}) output_objects.append( {'object_type': 'text', 'text': 'Proxy certificate will expire on %s (in %s sec.)' % (proxy.Expires(), proxy.getTimeleft()) }) except arc.NoProxyError, err: output_objects.append({'object_type':'warning', 'text': 'No proxy certificate to load: %s' \ % err.what()}) output_objects = output_objects + arc.askProxy()
def html_tmpl(configuration, client_id, title_entry, csrf_map={}, chroot=''): """HTML page base: some upload and menu entries depend on configuration""" active_menu = extract_menu(configuration, title_entry) user_settings = title_entry.get('user_settings', {}) legacy_ui = legacy_user_interface(configuration, user_settings) fill_helpers = {'short_title': configuration.short_title} html = ''' <!-- CONTENT --> <div class="container"> <div id="app-nav-container" class="row"> <h1>Welcome to %(short_title)s!</h1> <div class="home-page__header col-12"> <p class="sub-title">Tools from %(short_title)s helps you with storage, sharing and archiving of data. %(short_title)s delivers centralised storage space for personal and shared files.</p> </div> ''' % fill_helpers html += render_apps(configuration, title_entry, active_menu) html += ''' <div class="col-lg-12 vertical-spacer"></div> </div> </div> ''' # Dynamic app selection form_method = 'post' csrf_limit = get_csrf_limit(configuration) target_op = 'settingsaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) settings_specs = get_keywords_dict() current_settings_dict = load_settings(client_id, configuration) if not current_settings_dict: # no current settings found current_settings_dict = {} fill_helpers['form_prefix'] = ''' <form class="save_settings save_apps" action="settingsaction.py" method="%s"> <input type="hidden" name="%s" value="%s"> ''' % (form_method, csrf_field, csrf_token) fill_helpers['form_suffix'] = ''' %s <input type="submit" value="Save"> </form> ''' % save_settings_html(configuration) apps_field = 'SITE_USER_MENU' # NOTE: build list of all default and user selectable apps in that order app_list = [app_id for app_id in configuration.site_default_menu] app_list += [ app_id for app_id in configuration.site_user_menu if not app_id in app_list ] mandatory_apps = [] for app_name in configuration.site_default_menu: mandatory_apps.append(menu_items[app_name]['title']) fill_helpers['mandatory_apps'] = ', '.join(mandatory_apps) html += ''' <!-- APP POP-UP --> <div id="add-app__window" class="app-container hidden"> <span class="add-app__close far fa-times-circle" onclick="closeAddApp()"></span> <div class="container"> <div class="row"> <div class="app-page__header col-12"> <h1>Your apps & app-setup</h1> <p class="sub-title-white">Here you can select which apps you want to use in your %(short_title)s system. Only %(mandatory_apps)s are mandatory.</p> </div> <div class="app-page__header col-12"> <h2>Select your apps</h2> %(form_prefix)s ''' % fill_helpers # The backend form requires all user settings even if we only want to edit # the user apps subset here - just fill as hidden values. # TODO: consider a save version with only relevant values. for (key, val) in current_settings_dict.items(): if key == apps_field: continue spec = settings_specs[key] if spec['Type'] == 'multiplestrings': html += ''' <textarea class="hidden" name="%s">%s</textarea> ''' % (key, '\n'.join(val)) elif spec['Type'] == 'string': html += ''' <input type="hidden" name="%s" value="%s"> ''' % (key, val) elif spec['Type'] == 'boolean': html += ''' <input type="hidden" name="%s" value="%s"> ''' % (key, val) html += ''' <div class="app-grid row"> ''' for app_id in app_list: app = menu_items[app_id] app_name = app['title'] if not legacy_ui and app.get('legacy_only', False): continue if app_id == 'vgrids': app_name = '%ss' % configuration.site_vgrid_label mandatory = (app_id in configuration.site_default_menu) app_btn_classes = 'app__btn col-12 ' if mandatory: app_btn_classes += "mandatory" else: app_btn_classes += "optional" app_icon_classes = app['class'] check_field = '' if not mandatory: checked, checkmark = "", "checkmark" if app_id in current_settings_dict.get(apps_field, []): checked = "checked='checked'" checkmark = "checkmark" check_field = ''' <input type="checkbox" name="SITE_USER_MENU" %s value="%s"> <span class="%s"></span> ''' % (checked, app_id, checkmark) html += ''' <div class="col-lg-2"> <div class="%s"> <label class="app-content"> %s <div class="background-app"> <span class="%s"></span><h3>%s</h3> </div> </label> </div> </div> ''' % (app_btn_classes, check_field, app_icon_classes, app_name) html += ''' </div> <br /> %(form_suffix)s </div> </div> </div> <div class="col-lg-12 vertical-spacer"></div> </div> ''' % fill_helpers return html
def initialize_main_variables(client_id, op_title=True, op_header=True, op_menu=True): """Script initialization is identical for most scripts in shared/functionalty. This function should be called in most cases. """ configuration = get_configuration_object() logger = configuration.logger output_objects = [] start_entry = make_start_entry() output_objects.append(start_entry) op_name = os.path.splitext(os.path.basename(requested_page()))[0] if op_title: skipwidgets = not configuration.site_enable_widgets or not client_id skipuserstyle = not configuration.site_enable_styling or not client_id title_object = make_title_entry('%s' % op_name, skipmenu=(not op_menu), skipwidgets=skipwidgets, skipuserstyle=skipuserstyle, skipuserprofile=(not client_id)) # Make sure base_menu is always set for extract_menu # Typicall overriden based on client_id cases below title_object['base_menu'] = configuration.site_default_menu output_objects.append(title_object) if op_header: header_object = make_header_entry('%s' % op_name) output_objects.append(header_object) if client_id: # add the user-defined menu and widgets (if possible) title = find_entry(output_objects, 'title') if title: settings = load_settings(client_id, configuration) # NOTE: loaded settings may be False rather than dict here if not settings: settings = {} title['style'] = themed_styles(configuration, user_settings=settings) title['script'] = themed_scripts(configuration, user_settings=settings) if settings: title['user_settings'] = settings base_menu = settings.get('SITE_BASE_MENU', 'default') if not base_menu in configuration.site_base_menu: base_menu = 'default' if base_menu == 'simple' and configuration.site_simple_menu: title['base_menu'] = configuration.site_simple_menu elif base_menu == 'advanced' and \ configuration.site_advanced_menu: title['base_menu'] = configuration.site_advanced_menu else: title['base_menu'] = configuration.site_default_menu user_menu = settings.get('SITE_USER_MENU', None) if configuration.site_user_menu and user_menu: title['user_menu'] = user_menu if settings.get('ENABLE_WIDGETS', True) and \ configuration.site_script_deps: user_widgets = load_widgets(client_id, configuration) if user_widgets: title['user_widgets'] = user_widgets user_profile = load_profile(client_id, configuration) if user_profile: # These data are used for display in own profile view only profile_image_list = user_profile.get('PUBLIC_IMAGE', []) if profile_image_list: # TODO: copy profile image to /public/avatars/X and use it profile_image = os.path.join( configuration.site_user_redirect, profile_image_list[-1]) else: profile_image = '' user_profile['profile_image'] = profile_image else: user_profile = {} # Always set full name for use in personal user menu full_name = extract_field(client_id, 'full_name') user_profile['full_name'] = full_name title['user_profile'] = user_profile logger.debug('setting user profile: %s' % user_profile) else: # No user so we just enforce default site style and scripts title = find_entry(output_objects, 'title') if title: title['style'] = themed_styles(configuration) title['script'] = themed_scripts(configuration, logged_in=False) return (configuration, logger, output_objects, op_name)
def notify_user( jobdict, args_list, status, logger, statusfile, configuration, ): """Send notification messages about job to user. User settings are used if notification fields are left empty or set to 'SETTINGS'. Please note that this function may take a long time to deliver notifications, or even block forever if an IM is requested and no IM daemon is running. Thus it should be run in a separate thread or process if blocking is not allowed. Please take a look at notify_user_thread() if that is a requirement. """ # Usage records: quickly hacked in here. # later, we might want a general plugin / hook interface # first of all, write out the usage record (if configured) ur_destination = configuration.usage_record_dir if ur_destination: logger.debug('XML Usage Record directory %s' % ur_destination) usage_record = UsageRecord(configuration, logger) usage_record.fill_from_dict(jobdict) # we use the job_id as a file name (should be unique) usage_record.write_xml(ur_destination + os.sep + jobdict['JOB_ID'] + '.xml') jobid = jobdict['JOB_ID'] for notify_line in jobdict['NOTIFY']: logger.debug('notify line: %s' % notify_line) (header, message) = create_notify_message(jobdict, args_list, status, statusfile, configuration) supported_protocols = ['jabber', 'msn', 'icq', 'aol', 'yahoo'] notify_line_colon_split = notify_line.split(':', 1) if notify_line_colon_split[0].strip() in supported_protocols: protocol = notify_line_colon_split[0] recipients = notify_line_colon_split[1].strip() all_dest = [] # Empty or if recipients.strip().upper() in ['SETTINGS', '']: # read from personal settings settings_dict = load_settings(jobdict['USER_CERT'], configuration) if not settings_dict\ or not settings_dict.has_key(protocol.upper()): logger.info('Settings dict does not have %s key' % protocol.upper()) continue all_dest = settings_dict[protocol.upper()] else: all_dest.append(recipients) for single_dest in all_dest: logger.debug('notifying %s about %s' % (single_dest, jobid)) # NOTE: Check removed because icq addresses are numbers and not "emails" # if not is_valid_email_address(single_dest, logger): # not a valid address (IM account names are on standard email format) # continue............................ if send_instant_message( single_dest, protocol, header, message, logger, configuration, ): logger.info('Instant message sent to %s protocol: %s telling that %s %s' % (single_dest, protocol, jobid, status)) else: logger.error('Instant message NOT sent to %s protocol %s jobid: %s' % (single_dest, protocol, jobid)) else: notify_line_first_part = notify_line_colon_split[0].strip() all_dest = [] if notify_line_first_part in email_keyword_list: logger.info("'%s' notify_line_first_part found in email_keyword_list" % notify_line_first_part) recipients = notify_line.replace('%s: ' % notify_line_first_part, '').strip() if recipients.strip().upper() in ['SETTINGS', '']: # read from personal settings settings_dict = load_settings(jobdict['USER_CERT'], configuration) if not settings_dict: logger.info('Could not load settings_dict') continue if not settings_dict.has_key('EMAIL'): logger.info('Settings dict does not have EMAIL key' ) continue all_dest = settings_dict['EMAIL'] else: all_dest.append(recipients) elif is_valid_email_address(notify_line, logger): all_dest.append(notify_line) # send mails for single_dest in all_dest: logger.info('email destination %s' % single_dest) # verify specified address is valid if not is_valid_email_address(single_dest, logger): logger.info('%s is NOT a valid email address!' % single_dest) # not a valid email address continue if send_email(single_dest, header, message, logger, configuration): logger.info('email sent to %s telling that %s %s' % (single_dest, jobid, status)) else: logger.error('email NOT sent to %s, jobid: %s' % (single_dest, jobid))
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) client_dir = client_id_dir(client_id) 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) show_description = accepted['description'][-1].lower() == 'true' # 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 template_path = os.path.join(base_dir, default_mrsl_filename) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Submit Job' output_objects.append({'object_type': 'header', 'text' : 'Submit Job'}) default_mrsl = get_default_mrsl(template_path) settings_dict = load_settings(client_id, configuration) if not settings_dict or not settings_dict.has_key('SUBMITUI'): logger.info('Settings dict does not have SUBMITUI key - using default' ) submit_style = configuration.submitui[0] else: submit_style = settings_dict['SUBMITUI'] # We generate all 3 variants of job submission (fields, textarea, files), # initially hide them and allow to switch between them using js. # could instead extract valid prefixes as in settings.py # (means: by "eval" from configuration). We stick to hard-coding. submit_options = ['fields_form', 'textarea_form', 'files_form'] css_helpers = {'css_base': os.path.join(configuration.site_images, 'css'), 'skin_base': configuration.site_skin_base} title_entry['style'] = themed_styles(configuration, base=['jquery.fileupload.css', 'jquery.fileupload-ui.css'], skin=['fileupload-ui.custom.css']) title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <!-- Filemanager is only needed for fancy upload init wrapper --> <script type="text/javascript" src="/images/js/jquery.form.js"></script> <script type="text/javascript" src="/images/js/jquery.filemanager.js"></script> <!-- Fancy file uploader and dependencies --> <!-- The Templates plugin is included to render the upload/download listings --> <script type="text/javascript" src="/images/js/tmpl.min.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> <script type="text/javascript" src="/images/js/load-image.min.js"></script> <!-- The Iframe Transport is required for browsers without support for XHR file uploads --> <script type="text/javascript" src="/images/js/jquery.iframe-transport.js"></script> <!-- The basic File Upload plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload.js"></script> <!-- The File Upload processing plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-process.js"></script> <!-- The File Upload image preview & resize plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-image.js"></script> <!-- The File Upload validation plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-validate.js"></script> <!-- The File Upload user interface plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-ui.js"></script> <!-- The File Upload jQuery UI plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-jquery-ui.js"></script> <script type="text/javascript" > options = %s; function setDisplay(this_id, new_d) { //console.log("setDisplay with: "+this_id); el = document.getElementById(this_id) if ( el == undefined || el.style == undefined ) { console.log("failed to locate display element: "+this_id); return; // avoid js null ref errors } el.style.display=new_d; } function switchTo(name) { //console.log("switchTo: "+name); for (o=0; o < options.length; o++) { if (name == options[o]) { setDisplay(options[o],"block"); } else { setDisplay(options[o],"none"); } } } function openFancyUpload() { var open_dialog = mig_fancyuploadchunked_init("fancyuploadchunked_dialog"); var remote_path = "."; open_dialog("Upload Files", function() { return false; }, remote_path, false); } $(document).ready( function() { //console.log("document ready handler"); switchTo("%s"); $("#fancydialog").click(openFancyUpload); }); </script> ''' % (submit_options, submit_style + "_form") output_objects.append({'object_type': 'text', 'text': 'This page is used to submit jobs to the grid.'}) output_objects.append({'object_type': 'verbatim', 'text': ''' There are %s interface styles available that you can choose among:''' % \ len(submit_options)}) links = [] for opt in submit_options: name = opt.split('_', 2)[0] links.append({'object_type': 'link', 'destination': "javascript:switchTo('%s')" % opt, 'class': 'submit%slink' % name, 'title': 'Switch to %s submit interface' % name, 'text' : '%s style' % name, }) output_objects.append({'object_type': 'multilinkline', 'links': links}) output_objects.append({'object_type': 'text', 'text': ''' Please note that changes to the job description are *not* automatically transferred if you switch style.'''}) output_objects.append({'object_type': 'html_form', 'text': '<div id="fields_form" style="display:none;">\n'}) # Fields output_objects.append({'object_type': 'sectionheader', 'text' : 'Please fill in your job description in the fields' ' below:' }) output_objects.append({'object_type': 'text', 'text' : """ Please fill in one or more fields below to define your job before hitting Submit Job at the bottom of the page. Empty fields will simply result in the default value being used and each field is accompanied by a help link providing further details about the field."""}) output_objects.append({'object_type': 'html_form', 'text' : """ <div class="submitjob"> <form method="post" action="submitfields.py"> """ }) show_fields = get_job_specs(configuration) try: parsed_mrsl = dict(parse_lines(default_mrsl)) except: parsed_mrsl = {} # Find allowed VGrids and Runtimeenvironments and add them to # configuration object for automated choice handling allowed_vgrids = user_allowed_vgrids(configuration, client_id) + \ [any_vgrid] allowed_vgrids.sort() configuration.vgrids = allowed_vgrids (re_status, allowed_run_envs) = list_runtime_environments(configuration) if not re_status: logger.error('Failed to extract allowed runtime envs: %s' % \ allowed_run_envs) allowed_run_envs = [] allowed_run_envs.sort() configuration.runtimeenvironments = allowed_run_envs user_res = user_allowed_res_exes(configuration, client_id) # Allow any exe unit on all allowed resources allowed_resources = ['%s_*' % res for res in user_res.keys()] allowed_resources.sort() configuration.resources = allowed_resources field_size = 30 area_cols = 80 area_rows = 5 for (field, spec) in show_fields: title = spec['Title'] if show_description: description = '%s<br />' % spec['Description'] else: description = '' field_type = spec['Type'] # Use saved value and fall back to default if it is missing saved = parsed_mrsl.get('::%s::' % field, None) if saved: if not spec['Type'].startswith('multiple'): default = saved[0] else: default = saved else: default = spec['Value'] # Hide sandbox field if sandboxes are disabled if field == 'SANDBOX' and not configuration.site_enable_sandboxes: continue if 'invisible' == spec['Editor']: continue if 'custom' == spec['Editor']: continue output_objects.append({'object_type': 'html_form', 'text' : """ <b>%s:</b> <a class='infolink' href='docs.py?show=job#%s'>help</a><br /> %s""" % (title, field, description) }) if 'input' == spec['Editor']: if field_type.startswith('multiple'): output_objects.append({'object_type': 'html_form', 'text' : """ <textarea name='%s' cols='%d' rows='%d'>%s</textarea><br /> """ % (field, area_cols, area_rows, '\n'.join(default)) }) else: output_objects.append({'object_type': 'html_form', 'text' : """ <input type='text' name='%s' size='%d' value='%s' /><br /> """ % (field, field_size, default) }) elif 'select' == spec['Editor']: choices = available_choices(configuration, client_id, field, spec) res_value = default value_select = '' if field_type.startswith('multiple'): value_select += '<div class="scrollselect">' for name in choices: # Blank default value does not make sense here if not str(name): continue selected = '' if str(name) in res_value: selected = 'checked' value_select += ''' <input type="checkbox" name="%s" %s value=%s>%s<br /> ''' % (field, selected, name, name) value_select += '</div>\n' else: value_select += "<select name='%s'>\n" % field for name in choices: selected = '' if str(res_value) == str(name): selected = 'selected' display = "%s" % name if display == '': display = ' ' value_select += """<option %s value='%s'>%s</option>\n""" \ % (selected, name, display) value_select += """</select><br />\n""" output_objects.append({'object_type': 'html_form', 'text' : value_select }) output_objects.append({'object_type': 'html_form', 'text': "<br />"}) output_objects.append({'object_type': 'html_form', 'text' : """ <br /> <table class='centertext'> <tr><td><input type='submit' value='Submit Job' /> <input type='checkbox' name='save_as_default'> Save as default job template </td></tr> </table> <br /> </form> </div> """ }) output_objects.append({'object_type': 'html_form', 'text': ''' </div><!-- fields_form--> <div id="textarea_form" style="display:none;"> '''}) # Textarea output_objects.append({'object_type': 'sectionheader', 'text' : 'Please enter your mRSL job description below:' }) output_objects.append({'object_type': 'html_form', 'text' : """ <div class='smallcontent'> Job descriptions can use a wide range of keywords to specify job requirements and actions.<br /> Each keyword accepts one or more values of a particular type.<br /> The full list of keywords with their default values and format is available in the on-demand <a href='docs.py?show=job'>mRSL Documentation</a>. <p> Actual examples for inspiration: <a href=/public/cpuinfo.mRSL>CPU Info</a>, <a href=/public/basic-io.mRSL>Basic I/O</a>, <a href=/public/notification.mRSL>Job Notification</a>, <a href=/public/povray.mRSL>Povray</a> and <a href=/public/vcr.mRSL>VCR</a> </div> """}) output_objects.append({'object_type': 'html_form', 'text' : """ <!-- Please note that textarea.py chokes if no nonempty KEYWORD_X_Y_Z fields are supplied: thus we simply send a bogus jobname which does nothing --> <form method="post" action="textarea.py"> <table class="submitjob"> <tr><td class="centertext"> <input type=hidden name=jobname_0_0_0 value=" " /> <textarea cols="82" rows="25" name="mrsltextarea_0"> %(default_mrsl)s </textarea> </td></tr> <tr><td class='centertext'> <input type="submit" value="Submit Job" /> <input type="checkbox" name="save_as_default" >Save as default job template </td></tr> </table> </form> """ % {'default_mrsl': default_mrsl}}) output_objects.append({'object_type': 'html_form', 'text': ''' </div><!-- textarea_form--> <div id="files_form" style="display:none;"> '''}) # Upload form output_objects.append({'object_type': 'sectionheader', 'text' : 'Please upload your job file or packaged job files' ' below:' }) output_objects.append({'object_type': 'html_form', 'text' : """ <form enctype='multipart/form-data' action='textarea.py' method='post'> <table class='files'> <tr class='title'><td class='centertext' colspan=4> Upload job files </td></tr> <tr><td colspan=3> Upload file to current directory (%(dest_dir)s) </td><td><br /></td></tr> <tr><td colspan=2> Extract package files (.zip, .tar.gz, .tar.bz2) </td><td colspan=2> <input type=checkbox name='extract_0' /> </td></tr> <tr><td colspan=2> Submit mRSL files (also .mRSL files included in packages) </td><td colspan=2> <input type=checkbox name='submitmrsl_0' checked /> </td></tr> <tr><td> File to upload </td><td class='righttext' colspan=3> <input name='fileupload_0_0_0' type='file'/> </td></tr> <tr><td> Optional remote filename (extra useful in windows) </td><td class='righttext' colspan=3> <input name='default_remotefilename_0' type='hidden' value='%(dest_dir)s'/> <input name='remotefilename_0' type='text' size='50' value='%(dest_dir)s'/> <input type='submit' value='Upload' name='sendfile'/> </td></tr> </table> </form> <table class='files'> <tr class='title'><td class='centertext'> Upload other files efficiently (using chunking). </td></tr> <tr><td class='centertext'> <button id='fancydialog'>Open Upload dialog</button> </td></tr> </table> </div><!-- files_form--> <div id='fancyuploadchunked_dialog' title='Upload File' style='display: none;'> <!-- The file upload form used as target for the file upload widget --> <form id='fancyfileupload' action='uploadchunked.py?output_format=json;action=put' method='POST' enctype='multipart/form-data'> <fieldset id='fancyfileuploaddestbox'> <label id='fancyfileuploaddestlabel' for='fancyfileuploaddest'> Optional final destination dir: </label> <input id='fancyfileuploaddest' type='text' size=60 value=''> </fieldset> <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload --> <div class='fileupload-buttonbar'> <div class='fileupload-buttons'> <!-- The fileinput-button span is used to style the file input field as button --> <span class='fileinput-button'> <span>Add files...</span> <input type='file' name='files[]' multiple> </span> <button type='submit' class='start'>Start upload</button> <button type='reset' class='cancel'>Cancel upload</button> <button type='button' class='delete'>Delete</button> <input type='checkbox' class='toggle'> <!-- The global file processing state --> <span class='fileupload-process'></span> </div> <!-- The global progress state --> <div class='fileupload-progress fade' style='display:none'> <!-- The global progress bar --> <div class='progress' role='progressbar' aria-valuemin='0' aria-valuemax='100'></div> <!-- The extended global progress state --> <div class='progress-extended'> </div> </div> </div> <!-- The table listing the files available for upload/download --> <table role='presentation' class='table table-striped'><tbody class='uploadfileslist'></tbody></table> </form> <!-- For status and error output messages --> <div id='fancyuploadchunked_output'></div> </div> """ % {'dest_dir': '.' + os.sep}}) output_objects.append({'object_type': 'html_form', 'text': ''' <!-- The template to display files available for upload --> <script id="template-upload" type="text/x-tmpl"> {% console.log("using upload template"); %} {% console.log("... with upload files: "+$.fn.dump(o)); %} {% var dest_dir = "./" + $("#fancyfileuploaddest").val(); %} {% console.log("using upload dest: "+dest_dir); %} {% for (var i=0, file; file=o.files[i]; i++) { %} {% var rel_path = $.fn.normalizePath(dest_dir+"/"+file.name); %} {% console.log("using upload rel_path: "+rel_path); %} <tr class="template-upload fade"> <td> <span class="preview"></span> </td> <td> <p class="name">{%=rel_path%}</p> <strong class="error"></strong> </td> <td> <div class="size pending">Processing...</div> <div class="progress"></div> </td> <td> {% if (!i && !o.options.autoUpload) { %} <button class="start" disabled>Start</button> {% } %} {% if (!i) { %} <button class="cancel">Cancel</button> {% } %} </td> </tr> {% } %} </script> <!-- The template to display files available for download --> <script id="template-download" type="text/x-tmpl"> {% console.log("using download template"); %} {% console.log("... with download files: "+$.fn.dump(o)); %} {% for (var i=0, file; file=o.files[i]; i++) { %} {% var rel_path = $.fn.normalizePath("./"+file.name); %} {% console.log("using download rel_path: "+rel_path); %} <tr class="template-download fade"> <td> <span class="preview"> {% if (file.thumbnailUrl) { %} <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a> {% } %} </span> </td> <td> <p class="name"> <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?\'data-gallery\':\'\'%}>{%=rel_path%}</a> </p> {% if (file.error) { %} <div><span class="error">Error</span> {%=file.error%}</div> {% } %} </td> <td> <div class="size">{%=o.formatFileSize(file.size)%}</div> </td> <td> <button class="delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields=\'{"withCredentials":true}\'{% } %}>{% if (file.deleteUrl) { %}Delete{% } else { %}Dismiss{% } %}</button> <input type="checkbox" name="delete" value="1" class="toggle"> </td> </tr> {% } %} </script> '''}) 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) 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) flags = ''.join(accepted['flags']) pattern_list = accepted['path'] show_dest = accepted['with_dest'][0].lower() == 'true' listing = [] # 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 status = returnvalues.OK settings_dict = load_settings(client_id, configuration) javascript = '%s\n%s' % (select_all_javascript(), selected_file_actions_javascript()) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s Files' % configuration.short_title title_entry['javascript'] = javascript output_objects.append({'object_type': 'header', 'text': '%s Files' % configuration.short_title }) location_pre_html = \ """ <div class='files'> <table class='files'> <tr class='title'><td class='centertext'> Working directory: </td></tr> <tr><td class='centertext'> """ output_objects.append({'object_type': 'html_form', 'text' : location_pre_html}) for pattern in pattern_list: links = [] links.append({'object_type': 'link', 'text': '%s HOME' % configuration.short_title, 'destination': 'ls.py?path=.'}) prefix = '' parts = pattern.split(os.sep) for i in parts: prefix = os.path.join(prefix, i) links.append({'object_type': 'link', 'text': i, 'destination': 'ls.py?path=%s' % prefix}) output_objects.append({'object_type': 'multilinkline', 'links' : links}) location_post_html = """ </td></tr> </table> </div> <br /> """ output_objects.append({'object_type': 'html_form', 'text' : location_post_html}) more_html = \ """ <div class='files'> <form method='post' name='fileform' onSubmit='return selectedFilesAction();'> <table class='files'> <tr class='title'><td class='centertext' colspan=2> Advanced file actions </td></tr> <tr><td> Action on paths selected below (please hold mouse cursor over button for a description): </td> <td class='centertext'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='v' /> <input type='submit' title='Show concatenated contents (cat)' onClick='document.pressed=this.value' value='cat' /> <input type='submit' onClick='document.pressed=this.value' value='head' title='Show first lines (head)' /> <input type='submit' onClick='document.pressed=this.value' value='tail' title='Show last lines (tail)' /> <input type='submit' onClick='document.pressed=this.value' value='wc' title='Count lines/words/chars (wc)' /> <input type='submit' onClick='document.pressed=this.value' value='stat' title='Show details (stat)' /> <input type='submit' onClick='document.pressed=this.value' value='touch' title='Update timestamp (touch)' /> <input type='submit' onClick='document.pressed=this.value' value='truncate' title='truncate! (truncate)' /> <input type='submit' onClick='document.pressed=this.value' value='rm' title='delete! (rm)' /> <input type='submit' onClick='document.pressed=this.value' value='rmdir' title='Remove directory (rmdir)' /> <input type='submit' onClick='document.pressed=this.value' value='submit' title='Submit file (submit)' /> </td></tr> </table> </form> </div> """ output_objects.append({'object_type': 'html_form', 'text' : more_html}) dir_listings = [] output_objects.append({ 'object_type': 'dir_listings', 'dir_listings': dir_listings, 'flags': flags, 'show_dest': show_dest, }) first_match = None for pattern in pattern_list: # Check directory traversal attempts before actual handling to avoid # leaking information about file system layout while allowing # consistent error messages unfiltered_match = glob.glob(base_dir + pattern) match = [] for server_path in unfiltered_match: real_path = os.path.abspath(server_path) if not valid_user_path(real_path, base_dir, True): logger.warning('%s tried to %s restricted path %s! (%s)' % (client_id, op_name, real_path, pattern)) continue match.append(real_path) if not first_match: first_match = real_path # Now actually treat list of allowed matchings and notify if no # (allowed) match if not match: output_objects.append({'object_type': 'file_not_found', 'name': pattern}) status = returnvalues.FILE_NOT_FOUND for real_path in match: if real_path + os.sep == base_dir: relative_path = '.' else: relative_path = real_path.replace(base_dir, '') entries = [] dir_listing = { 'object_type': 'dir_listing', 'relative_path': relative_path, 'entries': entries, 'flags': flags, } dest = '' if show_dest: if os.path.isfile(real_path): dest = os.path.basename(real_path) elif recursive(flags): # references to '.' or similar are stripped by abspath if real_path + os.sep == base_dir: dest = '' else: # dest = os.path.dirname(real_path).replace(base_dir, "") dest = os.path.basename(real_path) + os.sep handle_expand( output_objects, entries, base_dir, real_path, flags, dest, 0, show_dest, ) dir_listings.append(dir_listing) output_objects.append({'object_type': 'html_form', 'text' : """ <div class='files'> <table class='files'> <tr class='title'><td class='centertext'> Filter paths (wildcards like * and ? are allowed) <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' /> <input type='text' name='path' value='' /> <input type='submit' value='Filter' /> </form> </td></tr> </table> </div> """ % flags}) # Short/long format buttons htmlform = \ """<table class='files'> <tr class='title'><td class='centertext' colspan=4> File view options </td></tr> <tr><td colspan=4><br /></td></tr> <tr class='title'><td>Parameter</td><td>Setting</td><td>Enable</td><td>Disable</td></tr> <tr><td>Long format</td><td> %s</td><td>"""\ % long_list(flags)\ + """ <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' />"""\ % (flags + 'l') for entry in pattern_list: htmlform += "<input type='hidden' name='path' value='%s' />"\ % entry htmlform += \ """ <input type='submit' value='On' /><br /> </form> </td><td> <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' />"""\ % flags.replace('l', '') for entry in pattern_list: htmlform += "<input type='hidden' name='path' value='%s' />"\ % entry htmlform += \ """ <input type='submit' value='Off' /><br /> </form> </td></tr> """ # Recursive output htmlform += \ """ <!-- Non-/recursive list buttons --> <tr><td>Recursion</td><td> %s</td><td>"""\ % recursive(flags) htmlform += \ """ <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' />"""\ % (flags + 'r') for entry in pattern_list: htmlform += " <input type='hidden' name='path' value='%s' />"\ % entry htmlform += \ """ <input type='submit' value='On' /><br /> </form> </td><td> <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' />"""\ % flags.replace('r', '') for entry in pattern_list: htmlform += "<input type='hidden' name='path' value='%s' />"\ % entry htmlform += \ """ <input type='submit' value='Off' /><br /> </form> </td></tr> """ htmlform += \ """ <!-- Show dot files buttons --> <tr><td>Show hidden files</td><td> %s</td><td>"""\ % all(flags) htmlform += \ """ <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' />"""\ % (flags + 'a') for entry in pattern_list: htmlform += "<input type='hidden' name='path' value='%s' />"\ % entry htmlform += \ """ <input type='submit' value='On' /><br /> </form> </td><td> <form method='post' action='ls.py'> <input type='hidden' name='output_format' value='html' /> <input type='hidden' name='flags' value='%s' />"""\ % flags.replace('a', '') for entry in pattern_list: htmlform += "<input type='hidden' name='path' value='%s' />"\ % entry htmlform += \ """ <input type='submit' value='Off' /><br /> </form> </td></tr> </table> """ # show flag buttons after contents to avoid output_objects.append({'object_type': 'html_form', 'text' : htmlform}) # create upload file form if first_match: # use first match for current directory # Note that base_dir contains an ending slash if os.path.isdir(first_match): dir_path = first_match else: dir_path = os.path.dirname(first_match) if dir_path + os.sep == base_dir: relative_dir = '.' else: relative_dir = dir_path.replace(base_dir, '') output_objects.append({'object_type': 'html_form', 'text' : """ <br /> <table class='files'> <tr class='title'><td class='centertext' colspan=2> Edit file </td><td><br /></td></tr> <tr><td> Fill in the path of a file to edit and press 'edit' to open that file in the<br /> online file editor. Alternatively a file can be selected for editing through<br /> the listing of personal files. </td><td colspan=2 class='righttext'> <form name='editor' method='post' action='editor.py'> <input type='hidden' name='output_format' value='html' /> <input name='current_dir' type='hidden' value='%(dest_dir)s' /> <input type='text' name='path' size=50 value='' /> <input type='submit' value='edit' /> </form> </td></tr> </table> <br /> <table class='files'> <tr class='title'><td class='centertext' colspan=4> Create directory </td></tr> <tr><td> Name of new directory to be created in current directory (%(dest_dir)s) </td><td class='righttext' colspan=3> <form action='mkdir.py' method=post> <input name='path' size=50 /> <input name='current_dir' type='hidden' value='%(dest_dir)s' /> <input type='submit' value='Create' name='mkdirbutton' /> </form> </td></tr> </table> <br /> <form enctype='multipart/form-data' action='textarea.py' method='post'> <table class='files'> <tr class='title'><td class='centertext' colspan=4> Upload file </td></tr> <tr><td colspan=4> Upload file to current directory (%(dest_dir)s) </td></tr> <tr><td colspan=2> Extract package files (.zip, .tar.gz, .tar.bz2) </td><td colspan=2> <input type='checkbox' name='extract_0' /> </td></tr> <tr><td colspan=2> Submit mRSL files (also .mRSL files included in packages) </td><td colspan=2> <input type='checkbox' name='submitmrsl_0' checked /> </td></tr> <tr><td> File to upload </td><td class='righttext' colspan=3> <input name='fileupload_0_0_0' type='file' /> </td></tr> <tr><td> Optional remote filename (extra useful in windows) </td><td class='righttext' colspan=3> <input name='default_remotefilename_0' type='hidden' value='%(dest_dir)s' /> <input name='remotefilename_0' type='text' size='50' value='%(dest_dir)s' /> <input type='submit' value='Upload' name='sendfile' /> </td></tr> </table> </form> """ % {'dest_dir': relative_dir + os.sep}}) 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) 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: WARNING_MSG = str(accepted) output_objects.append({'object_type': 'warning', 'text': WARNING_MSG}) return (accepted, returnvalues.CLIENT_ERROR) action = ''.join(accepted['action']) flags = ''.join(accepted['flags']) path = ''.join(accepted['path']) extension = ''.join(accepted['extension']) # 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) settings_dict = load_settings(client_id, configuration) javascript = None title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'FILEMETAIO Management' title_entry['javascript'] = javascript output_objects.append({'object_type': 'header', 'text': 'FILEMETAIO Management'}) status = returnvalues.ERROR if flags == 'i': if action == 'list': image_meta = get_image_file_settings(logger, abs_path) if image_meta is not None: extension_list = [] settings_status_list = [] settings_progress_list = [] image_count_list = [] for entry in image_meta: extension_list.append(entry['extension']) settings_status_list.append(entry['settings_status' ]) settings_progress_list.append(entry['settings_update_progress' ]) image_count_list.append(get_image_file_count(logger, abs_path, entry['extension'])) output_objects.append({ 'object_type': 'image_settings_list', 'extension_list': extension_list, 'settings_status_list': settings_status_list, 'settings_progress_list': settings_progress_list, 'image_count_list': image_count_list, }) status = returnvalues.OK else: status = returnvalues.ERROR ERROR_MSG = "No image settings found for path: '%s'" \ % path output_objects.append({'object_type': 'text', 'text': ERROR_MSG}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) elif action == 'remove_dir': remove_ext = None vgrid_name = path.split('/')[0] if extension != '': remove_ext = extension try: (result, removed_ext_list) = \ remove_image_file_settings(logger, abs_path, remove_ext) except Exception, ex: logger.debug(str(traceback.format_exc())) if result is not None: result = returnvalues.OK else: result = returnvalues.ERROR ERROR_MSG = \ 'Unable to remove image settings for path: %s' \ % path output_objects.append({'object_type': 'text', 'text': ERROR_MSG}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) for removed_ext in removed_ext_list: abs_last_modified_filepath = \ __get_image_settings_trigger_last_modified_filepath(logger, abs_path, removed_ext) # Remove trigger if delete_file(abs_last_modified_filepath, logger): # FYSIKER HACK: Sleep 1 to prevent trigger rule/event race # TODO: Modify events handler to accept trigger action + delete time.sleep(1) # Remove old vgrid submit trigger for files rule_id = __get_image_file_trigger_rule_id(logger, path, removed_ext) status = __remove_image_file_trigger( configuration, vgrid_name, path, extension, rule_id, output_objects, ) if status != returnvalues.OK: result = status # Remove old vgrid submit trigger for settings rule_id = \ __get_image_settings_trigger_rule_id(logger, path, removed_ext) status = __remove_image_settings_trigger( configuration, vgrid_name, path, extension, rule_id, output_objects, ) if status != returnvalues.OK: result = status else: result = returnvalues.ERROR ERROR_MSG = 'Unable to remove file: %s ' \ % abs_last_modified_filepath output_objects.append({'object_type': 'text', 'text': ERROR_MSG}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) elif action == 'get_dir': image_count = get_image_file_count(logger, abs_path, extension) image_meta = get_image_file_setting(logger, abs_path, extension) if image_meta is not None: extension = str(image_meta['extension']) settings_status = str(image_meta['settings_status']) settings_update_progress = \ str(image_meta['settings_update_progress']) settings_recursive = str(image_meta['settings_recursive' ]) image_count = str(image_count) image_type = str(image_meta['image_type']) offset = str(image_meta['offset']) x_dimension = str(image_meta['x_dimension']) y_dimension = str(image_meta['y_dimension']) preview_image_extension = \ str(image_meta['preview_image_extension']) preview_x_dimension = \ str(image_meta['preview_x_dimension']) preview_y_dimension = \ str(image_meta['preview_y_dimension']) preview_cutoff_min = str(image_meta['preview_cutoff_min' ]) preview_cutoff_max = str(image_meta['preview_cutoff_max' ]) data_type = str(image_meta['data_type']) output_objects.append({ 'object_type': 'image_setting', 'path': path, 'extension': extension, 'settings_status': settings_status, 'settings_update_progress': settings_update_progress, 'settings_recursive': settings_recursive, 'image_count': image_count, 'image_type': image_type, 'offset': offset, 'x_dimension': x_dimension, 'y_dimension': y_dimension, 'preview_image_extension': preview_image_extension, 'preview_x_dimension': preview_x_dimension, 'preview_y_dimension': preview_y_dimension, 'preview_cutoff_min': preview_cutoff_min, 'preview_cutoff_max': preview_cutoff_max, 'data_type': data_type, }) status = returnvalues.OK else: status = returnvalues.ERROR ERROR_MSG = \ "No image setting information for path: '%s', extension: '%s'" \ % (path, extension) output_objects.append({'object_type': 'text', 'text': ERROR_MSG}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) elif action == 'put_dir': settings_status = ''.join(accepted['settings_status']) if ''.join(accepted['settings_recursive']) == 'True': settings_recursive = True else: settings_recursive = False image_type = ''.join(accepted['image_type']) data_type = ''.join(accepted['data_type']) offset = int(''.join(accepted['offset'])) x_dimension = int(''.join(accepted['x_dimension'])) y_dimension = int(''.join(accepted['y_dimension'])) preview_image_extension = \ ''.join(accepted['preview_image_extension']) preview_x_dimension = \ int(''.join(accepted['preview_x_dimension'])) preview_y_dimension = \ int(''.join(accepted['preview_y_dimension'])) preview_cutoff_min = \ float(''.join(accepted['preview_cutoff_min'])) preview_cutoff_max = \ float(''.join(accepted['preview_cutoff_max'])) path_array = path.split('/') vgrid_name = path_array[0] vgrid_data_path = '/'.join(path_array[1:]) vgrid_meta_path = os.path.join(vgrid_data_path, __metapath) vgrid_image_meta_path = os.path.join(vgrid_data_path, __image_metapath) OK_MSG = \ "Created/updated settings for image extension: '%s' for path '%s'" \ % (extension, path) ERROR_MSG = \ "Failed to change settings for image extension: '%s' for path: '%s'" \ % (extension, path) (is_valid, is_valid_msg) = __is_valid_image_settings_update( configuration, base_dir, vgrid_name, vgrid_data_path, extension, settings_recursive, ) if is_valid: status = returnvalues.OK else: status = returnvalues.ERROR output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG}) output_objects.append({'object_type': 'error_text', 'text': is_valid_msg}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) logger.error('filemetaio.py: %s -> %s' % (action, is_valid_msg)) # Ensure meta path existence if status == returnvalues.OK: makedirs_rec(os.path.join(base_dir, os.path.join(vgrid_name, vgrid_meta_path)), configuration) # Ensure image meta path existence makedirs_rec(os.path.join(base_dir, os.path.join(vgrid_name, vgrid_image_meta_path)), configuration) try: add_status = add_image_file_setting( logger, abs_path, extension, settings_status, None, settings_recursive, image_type, data_type, offset, x_dimension, y_dimension, preview_image_extension, preview_x_dimension, preview_y_dimension, preview_cutoff_min, preview_cutoff_max, overwrite=True, ) except Exception, ex: add_status = False logger.debug(str(traceback.format_exc())) if add_status: status = returnvalues.OK output_objects.append({'object_type': 'text', 'text': OK_MSG}) else: status = returnvalues.ERROR output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) if status == returnvalues.OK: # Generate vgrid trigger for files if settings_recursive: vgrid_trigger_path = os.path.join(vgrid_data_path, '*/*.%s' % extension) else: vgrid_trigger_path = os.path.join(vgrid_data_path, '*.%s' % extension) rule_id = __get_image_file_trigger_rule_id(logger, path, extension) rule_dict = { 'rule_id': rule_id, 'vgrid_name': vgrid_name, 'path': vgrid_trigger_path, 'changes': ['created', 'modified', 'deleted', 'moved'], 'run_as': client_id, 'action': 'submit', 'arguments': 'template_from_filemetaio.py', 'templates': [__get_image_update_preview_mrsl_template(path)], 'settle_time': '60s', 'rate_limit': '', } # Remove old vgrid submit trigger for files status = __remove_image_file_trigger( configuration, vgrid_name, path, extension, rule_id, output_objects, ) if status == returnvalues.OK: # Add generated vgrid submit trigger for files (add_status, add_msg) = \ vgrid_add_triggers(configuration, vgrid_name, [rule_dict]) if add_status: status = returnvalues.OK OK_MSG = \ "Created/updated image file trigger for extension: '%s', path '%s'" \ % (extension, path) output_objects.append({'object_type': 'text', 'text': OK_MSG}) else: status = returnvalues.ERROR ERROR_MSG = \ "Failed change image file trigger for extension: '%s', path '%s'" \ % (extension, path) ERROR_MSG2 = "Makes sure '%s' is a VGrid" \ % vgrid_name output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG}) output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG2}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG2)) if status == returnvalues.OK: # Generate vgrid trigger for settings vgrid_path = '/'.join(path.split('/')[1:]) vgrid_trigger_filepath = \ __get_image_settings_trigger_last_modified_filepath(logger, vgrid_path, extension) rule_id = __get_image_settings_trigger_rule_id(logger, path, extension) rule_dict = { 'rule_id': rule_id, 'vgrid_name': vgrid_name, 'path': vgrid_trigger_filepath, 'changes': ['modified', 'deleted'], 'run_as': client_id, 'action': 'submit', 'arguments': 'template_from_filemetaio.py', 'templates': [__get_image_create_previews_mrsl_template(path, extension)], 'settle_time': '1s', 'rate_limit': '', } # Remove old vgrid submit trigger for settings status = __remove_image_settings_trigger( configuration, vgrid_name, path, extension, rule_id, output_objects, ) if status == returnvalues.OK: # Add generated vgrid submit trigger for settings (add_status, add_msg) = \ vgrid_add_triggers(configuration, vgrid_name, [rule_dict]) if add_status: status = returnvalues.OK OK_MSG = \ "Created/updated old image setting trigger for extension: '%s', path '%s'" \ % (extension, path) output_objects.append({'object_type': 'text', 'text': OK_MSG}) else: status = returnvalues.ERROR ERROR_MSG = \ "Failed change old image setting trigger for extension: '%s', path '%s'" \ % (extension, path) ERROR_MSG2 = "Makes sure '%s' is a VGrid" \ % vgrid_name output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG}) output_objects.append({'object_type': 'error_text', 'text': ERROR_MSG2}) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG)) logger.error('filemetaio.py: %s -> %s' % (action, ERROR_MSG2)) if status == returnvalues.OK: # Trigger Trigger (Trigger Happty) abs_vgrid_trigger_filepath = os.path.join(base_dir, os.path.join(vgrid_name, vgrid_trigger_filepath)) # FYSIKER HACK: Sleep 1 to prevent trigger rule/event race # TODO: Modify events handler to accept add+trigger action time.sleep(1) timestamp = time.time() touch(abs_vgrid_trigger_filepath, timestamp)