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' if not configuration.site_enable_jobs: output_objects.append({ 'object_type': 'error_text', 'text': '''Job execution is not enabled on this system''' }) return (output_objects, returnvalues.SYSTEM_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 template_path = os.path.join(base_dir, default_mrsl_filename) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Submit Job' user_settings = title_entry.get('user_settings', {}) output_objects.append({'object_type': 'header', 'text': 'Submit Job'}) default_mrsl = get_default_mrsl(template_path) if not user_settings or not user_settings.has_key('SUBMITUI'): logger.info('Settings dict does not have SUBMITUI key - using default') submit_style = configuration.submitui[0] else: submit_style = user_settings['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'] open_button_id = 'open_fancy_upload' form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'dest_dir': '.' + os.sep, 'fancy_open': open_button_id, 'default_mrsl': default_mrsl, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } target_op = 'uploadchunked' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) (add_import, add_init, add_ready) = fancy_upload_js(configuration, csrf_token=csrf_token) add_init += ''' submit_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 < submit_options.length; o++) { if (name == submit_options[o]) { setDisplay(submit_options[o],"block"); } else { setDisplay(submit_options[o],"none"); } } } ''' % submit_options add_ready += ''' switchTo("%s"); setUploadDest("%s"); /* wrap openFancyUpload in function to avoid event data as argument */ $("#%s").click(function() { openFancyUpload(); }); ''' % (submit_style + "_form", fill_helpers['dest_dir'], open_button_id) fancy_dialog = fancy_upload_html(configuration) # TODO: can we update style inline to avoid explicit themed_styles? title_entry['style'] = themed_styles( configuration, base=['jquery.fileupload.css', 'jquery.fileupload-ui.css'], skin=['fileupload-ui.custom.css'], user_settings=user_settings) title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready 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 iconspace' % 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.""" }) fill_helpers.update({'fancy_dialog': fancy_dialog}) target_op = 'submitfields' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': """ <div class='submitjob'> <form method='%(form_method)s' action='%(target_op)s.py'> <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' /> """ % fill_helpers }) 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 vgrid_access = user_vgrid_access(configuration, client_id) + \ [any_vgrid] vgrid_access.sort() configuration.vgrids = vgrid_access (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 # TODO: next call is slow because we walk and reload all pickles user_res = user_allowed_res_exes(configuration, client_id) # Add valid MAXFILL values to automated choice handling configuration.maxfills = [keyword_all] + maxfill_fields # 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 iconspace' 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 class='fillwidth padspace' name='%s' cols='%d' rows='%d'>%s</textarea><br /> """ % (field, area_cols, area_rows, '\n'.join(default)) }) elif field_type == 'int': output_objects.append({ 'object_type': 'html_form', 'text': """ <input type='number' name='%s' size='%d' value='%s' min=0 required pattern='[0-9]+' /><br /> """ % (field, field_size, 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> """ }) target_op = 'textarea' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': """ <!-- 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='%(form_method)s' action='%(target_op)s.py'> <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' /> <table class='submitjob'> <tr><td class='centertext'> <input type=hidden name=jobname_0_0_0 value=' ' /> <textarea class='fillwidth padspace' 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> """ % fill_helpers }) 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' method='%(form_method)s' action='%(target_op)s.py'> <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' /> <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='%(fancy_open)s'>Open Upload dialog</button> </td></tr> </table> </div><!-- files_form--> %(fancy_dialog)s """ % fill_helpers }) 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) # 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 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)