fixes for updated api
authorMaciej Tronowski <mtro@man.poznan.pl>
Thu, 5 Mar 2015 19:51:35 +0000 (20:51 +0100)
committerMaciej Tronowski <mtro@man.poznan.pl>
Thu, 5 Mar 2015 19:51:35 +0000 (20:51 +0100)
qcg/forms.py
qcg/templates/qcg/job_new.html
qcg/views.py

index a3524d5..3450783 100644 (file)
@@ -9,7 +9,7 @@ from qcg.models import Task, Allocation
 
 
 date_range_validator = RegexValidator(r'[0-9]{2}\.[0-9]{2}\.[0-9]{4} - [0-9]{2}\.[0-9]{2}\.[0-9]{4}')
-nodes_validator = RegexValidator(r'^[0-9]{1,3}(:[0-9]{1,2}){0,2}$')
+nodes_validator = RegexValidator(r'^[0-9]{1,3}:[0-9]{1,2}(:[0-9]{1,2})?$')
 env_name_validator = RegexValidator(r'^[a-zA-Z_][a-zA-Z0-9_]*$')
 
 CHOICES_PLACEHOLDER = (None, '')
@@ -81,6 +81,18 @@ class JobDescriptionForm(forms.Form):
             (REEF, u'Reef'),
             (ZEUS, u'Zeus'),
         )
+
+    class Process(object):
+        NONE = ''
+        CMD = 'c'
+        SCRIPT = 's'
+
+        CHOICES = (
+            (NONE, u'Brak'),
+            (CMD, u'Polecenie'),
+            (SCRIPT, u'Skrypt'),
+        )
+
     APPLICATION_CHOICES = (
         CHOICES_PLACEHOLDER,
         ('bash', 'BASH'),
@@ -98,15 +110,10 @@ class JobDescriptionForm(forms.Form):
         ('plgrid/apps/python', 'plgrid/apps/python'),
         ('plgrid/apps/matlab', 'plgrid/apps/matlab'),
     )
-    NOTIFY_CHOICES = (
-        (0, u'Brak'),
-        (1, u'E-mail'),
-        (2, u'XMPP'),
-    )
-    PROCESS_CHOICES = (
-        (0, u'Brak'),
-        (1, u'Polecenie'),
-        (2, u'Skrypt'),
+    PROTOCOL_CHOICES = (
+        ('', u'Brak'),
+        ('mailto', u'E-mail'),
+        ('xmpp', u'XMPP'),
     )
 
     application = forms.ChoiceField(choices=APPLICATION_CHOICES, label=u"Aplikacja", required=False)  # TODO choices
@@ -116,7 +123,7 @@ class JobDescriptionForm(forms.Form):
     note = forms.CharField(label=u"Opis", widget=forms.Textarea(attrs={'rows': 2, 'cols': 40}), required=False)
     grant = forms.CharField(label=u"Grant", max_length=100, required=False)
 
-    host = forms.MultipleChoiceField(label=u"Host", choices=Host.CHOICES, required=False)
+    hosts = forms.MultipleChoiceField(label=u"Host", choices=Host.CHOICES, required=False)
     properties = forms.MultipleChoiceField(label=u"Właściwości węzłów", required=False)
     queue = forms.ChoiceField(choices=QUEUE_CHOICES, label=u"Kolejka", required=False)
     procs = forms.IntegerField(label=u"Liczba procesów", min_value=0, required=False)
@@ -133,20 +140,20 @@ class JobDescriptionForm(forms.Form):
     stage_out = forms.CharField(label=u"Stage out", max_length=500, required=False)
 
     monitoring = forms.BooleanField(label=u"Portal QCG-Monitoring", required=False)
-    notify_type = forms.ChoiceField(label=u"Monitorowanie stanu", choices=NOTIFY_CHOICES, required=False, initial=0,
+    notify_type = forms.ChoiceField(label=u"Monitorowanie stanu", choices=PROTOCOL_CHOICES, required=False, initial='',
                                     widget=forms.RadioSelect)
     notify_address = forms.EmailField(label=u"Adres", required=False)
-    watch_output_type = forms.ChoiceField(label=u"Monitorowanie wyjścia", choices=NOTIFY_CHOICES, required=False,
-                                          initial=0, widget=forms.RadioSelect)
+    watch_output_type = forms.ChoiceField(label=u"Monitorowanie wyjścia", choices=PROTOCOL_CHOICES, required=False,
+                                          initial='', widget=forms.RadioSelect)
     watch_output_address = forms.EmailField(label=u"Adres", required=False)
     watch_output_pattern = forms.CharField(label=u"Wzorzec", max_length=500, required=False)
 
-    preprocess_type = forms.ChoiceField(label=u"Preprocessing", choices=PROCESS_CHOICES, required=False, initial=0,
-                                        widget=forms.RadioSelect)
+    preprocess_type = forms.ChoiceField(label=u"Preprocessing", choices=Process.CHOICES, required=False,
+                                        initial=Process.NONE, widget=forms.RadioSelect)
     preprocess_cmd = forms.CharField(label=u"Polecenie", max_length=1000, required=False)
     preprocess_script = forms.CharField(label=u"Skrypt", max_length=500, required=False)  # TODO grid ftp
-    postprocess_type = forms.ChoiceField(label=u"Postprocessing", choices=PROCESS_CHOICES, required=False, initial=0,
-                                         widget=forms.RadioSelect)
+    postprocess_type = forms.ChoiceField(label=u"Postprocessing", choices=Process.CHOICES, required=False,
+                                         initial=Process.CHOICES, widget=forms.RadioSelect)
     postprocess_cmd = forms.CharField(label=u"Polecenie", max_length=1000, required=False)
     postprocess_script = forms.CharField(label=u"Skrypt", max_length=500, required=False)  # TODO grid ftp
     native = forms.MultipleChoiceField(label=u"Opcje systemu kolejkowego", required=False)
@@ -162,6 +169,48 @@ class JobDescriptionForm(forms.Form):
             self.fields['properties'].choices += ((v, v) for v in data.getlist('properties'))
             self.fields['native'].choices += ((v, v) for v in data.getlist('native'))
 
+    def clean(self):
+        data = super(JobDescriptionForm, self).clean()
+
+        notify_type = data.get('notify_type')
+        data['notify'] = u'{}:{}'.format(notify_type, data['notify_address']) if notify_type else ''
+
+        wo_type = data.get('watch_output_type')
+        data['watch_output'] = u'{}:{}'.format(wo_type, data['watch_output_address']) if wo_type else ''
+
+        preprocess_type = data.get('preprocess_type')
+        if preprocess_type == self.Process.CMD:
+            data['preprocess'] = data['preprocess_cmd']
+        elif preprocess_type == self.Process.SCRIPT:
+            data['preprocess'] = data['preprocess_script']
+        else:
+            data['preprocess'] = ''
+
+        postprocess_type = data.get('postprocess_type')
+        if postprocess_type == self.Process.CMD:
+            data['postprocess'] = data['postprocess_cmd']
+        elif postprocess_type == self.Process.SCRIPT:
+            data['postprocess'] = data['postprocess_script']
+        else:
+            data['postprocess'] = ''
+
+    def clean_application(self):
+        value = self.cleaned_data['application']
+
+        if '/' in value:
+            return value.split('/', 1)
+
+        return value, None
+
+    def clean_nodes(self):
+        value = map(int, self.cleaned_data['nodes'].split(':', 2))
+
+        if len(value) == 3:
+            return tuple(value)
+
+        nodes, slots = value
+        return nodes, slots, slots
+
 
 class EnvForm(forms.Form):
     name = forms.CharField(label=u"Nazwa", max_length=100, validators=[env_name_validator],
index 7929749..8cf2bbe 100644 (file)
@@ -29,7 +29,7 @@
                     }
                 }
             });
-            $('#id_modules, #id_host').selectize({
+            $('#id_modules, #id_hosts').selectize({
                 plugins: ['remove_button']
             });
 
 {% block container %}
     <h1 class="page-header">{% block title %}Zleć zadanie{% endblock %}</h1>
 
+    {% if errors %}
+        <div class="alert alert-danger">
+            <strong>Uwaga!</strong> Formularz zawiera błędy.
+            {{ form.non_field_errors }}
+            {{ env_formset.non_field_errors }}
+        </div>
+    {% endif %}
+
     <form action="." method="post" class="form-horizontal">
         {% csrf_token %}
 
             </fieldset>
 
             <fieldset id="resources" class="tab-pane" role="tabpanel">
-                {% bootstrap_field form.host layout="horizontal" %}
+                {% bootstrap_field form.hosts layout="horizontal" %}
                 {% bootstrap_field form.queue layout="horizontal" %}
                 {% bootstrap_field form.properties layout="horizontal" form_group_class="form-group collapse" %}
                 {% bootstrap_field form.modules layout="horizontal" form_group_class="form-group collapse" %}
                                 <label class="btn btn-default">
                                     <input type="radio" autocomplete="off" name="{{ option.name }}" value="{{ option.choice_value }}"
                                             {% if option.is_checked %}checked{% endif %}
-                                            data-target=".notify-type-{{ option.choice_value }}"> {{ option.choice_label }}
+                                            data-target=".notify-type-{{ forloop.counter0 }}"> {{ option.choice_label }}
                                 </label>
                             {% endfor %}
                         </div>
                                     <label class="btn btn-default">
                                         <input type="radio" autocomplete="off" name="{{ option.name }}" value="{{ option.choice_value }}"
                                                 {% if option.is_checked %}checked{% endif %}
-                                                data-target=".watch-output-type-{{ option.choice_value }}"> {{ option.choice_label }}
+                                                data-target=".watch-output-type-{{ forloop.counter0 }}"> {{ option.choice_label }}
                                     </label>
                                 {% endfor %}
                             </div>
                                 <label class="btn btn-default">
                                     <input type="radio" autocomplete="off" name="{{ option.name }}" value="{{ option.choice_value }}"
                                             {% if option.is_checked %}checked{% endif %}
-                                            data-target=".preprocess-type-{{ option.choice_value }}"> {{ option.choice_label }}
+                                            data-target=".preprocess-type-{{ forloop.counter0 }}"> {{ option.choice_label }}
                                 </label>
                             {% endfor %}
                         </div>
                                 <label class="btn btn-default">
                                     <input type="radio" autocomplete="off" name="{{ option.name }}" value="{{ option.choice_value }}"
                                             {% if option.is_checked %}checked{% endif %}
-                                            data-target=".postprocess-type-{{ option.choice_value }}"> {{ option.choice_label }}
+                                            data-target=".postprocess-type-{{ forloop.counter0 }}"> {{ option.choice_label }}
                                 </label>
                             {% endfor %}
                         </div>
index aaa0bdc..0be3d73 100644 (file)
@@ -163,56 +163,35 @@ def job_new(request):
 
             desc = JobDescription(Credential(request.session['proxy']))
 
-            application = form.cleaned_data['application']
-            if '/' in application:
-                app_tuple = application.split('/', 1)
-            else:
-                app_tuple = (application, None)
-            desc.application = app_tuple
+            direct_map = ('application', 'arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs', 'nodes',
+                          'wall_time', 'memory', 'memory_per_slot', 'modules', 'native', 'notify', 'preprocess',
+                          'postprocess', 'persistent')
 
+            for name in direct_map:
+                if form.cleaned_data[name]:
+                    setattr(desc, name, form.cleaned_data[name])
+
+            desc.reservation = ('LOCAL', form.cleaned_data['reservation'])
+            desc.watch_output = (form.cleaned_data['watch_output'], form.cleaned_data['watch_output_pattern'])
+            desc.env_variables += [(env['name'], env['value']) for env in env_formset.cleaned_data if not env['DELETE']]
             # TODO script
             # TODO executable
-            desc.arguments = form.cleaned_data['arguments']
-            desc.note = form.cleaned_data['note']
-            desc.grant = form.cleaned_data['grant']
-            desc.hosts = form.cleaned_data['host']
-            desc.properties = form.cleaned_data['properties']
-            # TODO queue
-            # TODO procs
-            # TODO nodes
-            if form.cleaned_data['wall_time'] is not None:
-                desc.wall_time = form.cleaned_data['wall_time']
-            desc.memory = form.cleaned_data['memory']
-            desc.memory_per_slot = form.cleaned_data['memory_per_slot']
-            desc.env_variables = [(env['name'], env['value']) for env in env_formset.cleaned_data if not env['DELETE']]
-            desc.modules = form.cleaned_data['modules']
-            desc.natives = form.cleaned_data['native']
-            desc.reservation = ("LOCAL", form.cleaned_data['reservation'])
             # TODO input
             # TODO stage_in
             # TODO stage_out
             # TODO monitoring
-            # TODO notify_type
-            # TODO notify_address
-            # TODO watch_output_type
-            # TODO watch_output_address
-            # TODO watch_output_pattern
-            # TODO preprocess_type
-            # TODO preprocess_cmd
-            # TODO preprocess_script
-            # TODO postprocess_type
-            # TODO postprocess_cmd
-            # TODO postprocess_script
-            desc.persistent = form.cleaned_data['persistent']
-
-            for prop in ('application', 'arguments', 'note', 'grant', 'hosts', 'wall_time', 'memory', 'memory_per_slot',
-                         'properties', 'env_variables', 'modules', 'natives', 'persistent', 'reservation'):
+
+            for prop in direct_map + ('env_variables', 'reservation', 'watch_output'):
                 print prop, type(getattr(desc, prop)), repr(getattr(desc, prop))
 
             print desc.xml_description
 
+        print repr(form.errors)
+        print repr(env_formset.errors)
     else:
         form = JobDescriptionForm()
         env_formset = EnvFormSet()
 
-    return render(request, 'qcg/job_new.html', {'form': form, 'env_formset': env_formset})
+    errors = form.errors or (env_formset.is_bound and not env_formset.is_valid)
+
+    return render(request, 'qcg/job_new.html', {'form': form, 'env_formset': env_formset, 'errors': errors})