Restrict Postgres to version 10
[pharos-tools.git] / dashboard / src / workflow / forms.py
1 ##############################################################################
2 # Copyright (c) 2018 Sawyer Bergeron, Parker Berberian, and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 import django.forms as forms
12 from django.forms import widgets
13 from django.contrib.auth.models import User
14 from django.utils.safestring import mark_safe
15 from django.template.loader import render_to_string
16 from django.core import serializers
17 from django.forms.widgets import NumberInput
18 from django.db.models import F
19
20 import json
21
22 from resource_inventory.models import *
23 from account.models import Lab
24 from account.models import UserProfile
25
26
27 class SearchableSelectMultipleWidget(widgets.SelectMultiple):
28     template_name = 'dashboard/searchable_select_multiple.html'
29
30     def __init__(self, attrs=None):
31         self.items = attrs['set']
32         self.show_from_noentry = attrs['show_from_noentry']
33         self.show_x_results = attrs['show_x_results']
34         self.results_scrollable = attrs['scrollable']
35         self.selectable_limit = attrs['selectable_limit']
36         self.placeholder = attrs['placeholder']
37         self.name = attrs['name']
38         self.initial = attrs.get("initial", "")
39         self.default_entry = attrs.get("default_entry", "")
40         self.edit = attrs.get("edit", False)
41         self.wf_type = attrs.get("wf_type")
42
43         super(SearchableSelectMultipleWidget, self).__init__(attrs)
44
45     def render(self, name, value, attrs=None, renderer=None):
46
47         context = self.get_context(attrs)
48         return mark_safe(render_to_string(self.template_name, context))
49
50     def get_context(self,attrs):
51         return {'items':self.items,
52         'name':self.name,
53         'show_from_noentry':self.show_from_noentry,
54         'show_x_results':self.show_x_results,
55         'results_scrollable':self.results_scrollable,
56         'selectable_limit':self.selectable_limit,
57         'placeholder':self.placeholder,
58         'initial':self.initial,
59         'default_entry':self.default_entry,
60         'edit': self.edit,
61         'wf_type': self.wf_type
62         }
63
64 class ResourceSelectorForm(forms.Form):
65
66     def __init__(self, data=None, **kwargs):
67         chosen_resource = ""
68         bundle = None
69         edit = False
70         if "chosen_resource" in kwargs:
71             chosen_resource = kwargs.pop("chosen_resource")
72         if "bundle" in kwargs:
73             bundle = kwargs.pop("bundle")
74         if "edit" in kwargs:
75             edit = kwargs.pop("edit")
76         super(ResourceSelectorForm, self).__init__(data=data,**kwargs)
77         queryset = GenericResourceBundle.objects.select_related("owner").all()
78         if data and 'user' in data:
79             queryset = queryset.filter(owner=data['user'])
80
81         attrs = self.build_search_widget_attrs(chosen_resource, bundle, edit, queryset)
82
83         self.fields['generic_resource_bundle'] = forms.CharField(
84                 widget=SearchableSelectMultipleWidget(attrs=attrs)
85                 )
86
87     def build_search_widget_attrs(self, chosen_resource, bundle, edit, queryset):
88         resources = {}
89         for res in queryset:
90             displayable = {}
91             displayable['small_name'] = res.name
92             if res.owner:
93                 displayable['expanded_name'] = res.owner.username
94             else:
95                 displayable['expanded_name'] = ""
96             displayable['string'] = res.description
97             displayable['id'] = res.id
98             resources[res.id] = displayable
99
100             if bundle:
101                 displayable = {}
102                 displayable['small_name'] = bundle.name
103                 displayable['expanded_name'] = "Current bundle"
104                 displayable['string'] = bundle.description
105                 displayable['id'] = "repo bundle"
106                 resources["repo bundle"] = displayable
107         attrs={
108             'set': resources,
109             'show_from_noentry': "true",
110             'show_x_results': -1,
111             'scrollable': "true",
112             'selectable_limit': 1,
113             'name': "generic_resource_bundle",
114             'placeholder': "resource",
115             'initial': chosen_resource,
116             'edit': edit,
117             'wf_type': 1
118         }
119         return attrs
120
121 class SWConfigSelectorForm(forms.Form):
122
123     def __init__(self, *args, **kwargs):
124         chosen_software = ""
125         bundle = None
126         edit = False
127         resource = None
128         if "chosen_software" in kwargs:
129             chosen_software = kwargs.pop("chosen_software")
130
131         if "bundle" in kwargs:
132             bundle = kwargs.pop("bundle")
133         if "edit" in kwargs:
134             edit = kwargs.pop("edit")
135         if "resource" in kwargs:
136             resource = kwargs.pop("resource")
137         super(SWConfigSelectorForm, self).__init__(*args,**kwargs)
138         attrs = self.build_search_widget_attrs(chosen_software,bundle, edit, resource)
139         self.fields['software_bundle'] = forms.CharField(
140                 widget=SearchableSelectMultipleWidget(attrs=attrs)
141                 )
142
143     def build_search_widget_attrs(self, chosen, bundle, edit, resource):
144         configs = {}
145         queryset = ConfigBundle.objects.select_related('owner').all()
146         if resource:
147             queryset = queryset.filter(bundle=resource)
148
149         for config in queryset:
150             displayable = {}
151             displayable['small_name'] = config.name
152             displayable['expanded_name'] = config.owner.username
153             displayable['string'] = config.description
154             displayable['id'] = config.id
155             configs[config.id] = displayable
156
157         if bundle:
158             displayable = {}
159             displayable['small_name'] = bundle.name
160             displayable['expanded_name'] = "Current configuration"
161             displayable['string'] = bundle.description
162             displayable['id'] = "repo bundle"
163             configs['repo bundle'] = displayable
164
165         attrs={
166             'set': configs,
167             'show_from_noentry': "true",
168             'show_x_results': -1,
169             'scrollable': "true",
170             'selectable_limit': 1,
171             'name': "software_bundle",
172             'placeholder': "config",
173             'initial': chosen,
174             'edit': edit,
175             'wf_type': 2
176         }
177         return attrs
178
179 class BookingMetaForm(forms.Form):
180
181     length = forms.IntegerField(widget=NumberInput(attrs={'type':'range', 'min':"0", "max":"21", "value":"0"}))
182     purpose = forms.CharField(max_length=1000)
183     project = forms.CharField(max_length=400)
184     info_file = forms.CharField(max_length=1000, required=False)
185
186     def __init__(self, data=None, *args, **kwargs):
187         chosen_users = []
188         if "default_user" in kwargs:
189             default_user = kwargs.pop("default_user")
190         else:
191             default_user = "you"
192         if "chosen_users" in kwargs:
193             chosen_users = kwargs.pop("chosen_users")
194         elif data and "users" in data:
195             chosen_users = data.getlist("users")
196         else:
197             pass
198
199         super(BookingMetaForm, self).__init__(data=data, **kwargs)
200
201         self.fields['users'] = forms.CharField(
202             widget=SearchableSelectMultipleWidget(
203                 attrs=self.build_search_widget_attrs(chosen_users, default_user=default_user)
204                 ),
205             required=False
206             )
207
208     def build_user_list(self):
209         """
210         returns a mapping of UserProfile ids to displayable objects expected by
211         searchable multiple select widget
212         """
213         try:
214             users = {}
215             d_qset = UserProfile.objects.select_related('user').all();
216             for userprofile in d_qset:
217                 user = {
218                     'id':userprofile.user.id,
219                     'expanded_name':userprofile.full_name,
220                     'small_name':userprofile.user.username,
221                     'string':userprofile.email_addr
222                     }
223
224                 users[userprofile.user.id] = user
225
226             return users
227         except Exception as e:
228             pass
229
230     def build_search_widget_attrs(self, chosen_users, default_user="you"):
231
232         attrs={
233             'set': self.build_user_list(),
234             'show_from_noentry': "false",
235             'show_x_results': 10,
236             'scrollable': "false",
237             'selectable_limit': -1,
238             'name': "users",
239             'placeholder': "username",
240             'default_entry': default_user,
241             'initial': chosen_users,
242             'edit': False
243         }
244         return attrs
245
246 class MultipleSelectFilterWidget(forms.Widget):
247     def __init__(self, attrs=None):
248         super(MultipleSelectFilterWidget, self).__init__(attrs)
249         self.attrs = attrs
250         self.template_name="dashboard/multiple_select_filter_widget.html"
251
252     def render(self, name, value, attrs=None, renderer=None):
253         attrs = self.attrs
254         self.context = self.get_context(name, value, attrs)
255         html = render_to_string(self.template_name, context=self.context)
256         return mark_safe(html)
257
258     def get_context(self, name, value, attrs):
259         return attrs
260
261 class MultipleSelectFilterField(forms.Field):
262     def __init__(   self, required=True, widget=None, label=None, initial=None,
263                     help_text='', error_messages=None, show_hidden_initial=False,
264                     validators=(), localize=False, disabled=False, label_suffix=None):
265         """from the documentation:
266         # required -- Boolean that specifies whether the field is required.
267         #             True by default.
268         # widget -- A Widget class, or instance of a Widget class, that should
269         #           be used for this Field when displaying it. Each Field has a
270         #           default Widget that it'll use if you don't specify this. In
271         #           most cases, the default widget is TextInput.
272         # label -- A verbose name for this field, for use in displaying this
273         #          field in a form. By default, Django will use a "pretty"
274         #          version of the form field name, if the Field is part of a
275         #          Form.
276         # initial -- A value to use in this Field's initial display. This value
277         #            is *not* used as a fallback if data isn't given.
278         # help_text -- An optional string to use as "help text" for this Field.
279         # error_messages -- An optional dictionary to override the default
280         #                   messages that the field will raise.
281         # show_hidden_initial -- Boolean that specifies if it is needed to render a
282         #                        hidden widget with initial value after widget.
283         # validators -- List of additional validators to use
284         # localize -- Boolean that specifies if the field should be localized.
285         # disabled -- Boolean that specifies whether the field is disabled, that
286         #             is its widget is shown in the form but not editable.
287         # label_suffix -- Suffix to be added to the label. Overrides
288         #                 form's label_suffix.
289         """
290         #this is bad, but django forms are annoying
291         self.widget=widget
292         if self.widget is None:
293             self.widget = MultipleSelectFilterWidget()
294         super(MultipleSelectFilterField, self).__init__(
295             required=required,
296             widget=self.widget,
297             label=label,
298             initial=None,
299             help_text=help_text,
300             error_messages=error_messages,
301             show_hidden_initial=show_hidden_initial,
302             validators=validators,
303             localize=localize,
304             disabled=disabled,
305             label_suffix=label_suffix
306         )
307
308         def clean(data):
309             """
310             This method will raise a django.forms.ValidationError or return clean data
311             """
312             return data
313
314 class FormUtils:
315     @staticmethod
316     def getLabData():
317         """
318         Gets all labs and thier host profiles and returns a serialized version the form can understand.
319         Should be rewritten with a related query to make it faster
320         Should be moved outside of global scope
321         """
322         labs = {}
323         hosts = {}
324         items = {}
325         mapping = {}
326         for lab in Lab.objects.all():
327             slab = {}
328             slab['id'] = "lab_" + str(lab.lab_user.id)
329             slab['name'] = lab.name
330             slab['description'] = lab.description
331             slab['selected'] = 0
332             slab['selectable'] = 1
333             slab['follow'] = 1
334             slab['multiple'] = 0
335             items[slab['id']] = slab
336             mapping[slab['id']] = []
337             labs[slab['id']] = slab
338             for host in lab.hostprofiles.all():
339                 shost = {}
340                 shost['forms'] = [{"name": "host_name", "type": "text", "placeholder": "hostname"}]
341                 shost['id'] = "host_" + str(host.id)
342                 shost['name'] = host.name
343                 shost['description'] = host.description
344                 shost['selected'] = 0
345                 shost['selectable'] = 1
346                 shost['follow'] = 0
347                 shost['multiple'] = 1
348                 items[shost['id']] = shost
349                 mapping[slab['id']].append(shost['id'])
350                 if shost['id'] not in mapping:
351                     mapping[shost['id']] = []
352                 mapping[shost['id']].append(slab['id'])
353                 hosts[shost['id']] = shost
354
355         filter_objects = [("labs", labs.values()), ("hosts", hosts.values())]
356
357         context = {
358                 'filter_objects': filter_objects,
359                 'mapping': mapping,
360                 'items': items
361                 }
362         return context
363
364 class HardwareDefinitionForm(forms.Form):
365
366     def __init__(self, *args, **kwargs):
367         selection_data = kwargs.pop("selection_data", False)
368         super(HardwareDefinitionForm, self).__init__(*args, **kwargs)
369         attrs = FormUtils.getLabData()
370         attrs['selection_data'] = selection_data
371         self.fields['filter_field'] = MultipleSelectFilterField(
372                 widget=MultipleSelectFilterWidget(
373                     attrs=attrs
374                     )
375                 )
376
377 class PodDefinitionForm(forms.Form):
378
379     fields = [ "xml" ]
380     xml = forms.CharField()
381
382 class ResourceMetaForm(forms.Form):
383
384     bundle_name = forms.CharField(label="POD Name")
385     bundle_description = forms.CharField(label="POD Description", widget=forms.Textarea)
386
387 class GenericHostMetaForm(forms.Form):
388
389     host_profile = forms.CharField(label="Host Type", disabled=True, required=False)
390     host_name = forms.CharField(label="Host Name")
391
392 class NetworkDefinitionForm(forms.Form):
393     def __init__(self, *args, **kwargs):
394         fields = []
395
396         super(NetworkDefinitionForm, self).__init__(**kwargs)
397
398 class NetworkConfigurationForm(forms.Form):
399     def __init__(self, *args, **kwargs):
400         fields = []
401
402         super(NetworkConfigurationForm).__init__(**kwargs)
403
404 class HostSoftwareDefinitionForm(forms.Form):
405     fields = ["host_name", "role", "image"]
406
407     host_name = forms.CharField(max_length=200, disabled=True, required=False)
408     role = forms.ModelChoiceField(queryset=OPNFVRole.objects.all())
409     image = forms.ModelChoiceField(queryset=Image.objects.all())
410
411 class SoftwareConfigurationForm(forms.Form):
412
413     name = forms.CharField(max_length=200)
414     description = forms.CharField(widget=forms.Textarea)
415     opnfv = forms.BooleanField(disabled=True, required=False)
416     installer = forms.ModelChoiceField(queryset=Installer.objects.all(), disabled=True, required=False)
417     scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), disabled=True, required=False)
418
419 class WorkflowSelectionForm(forms.Form):
420     fields = ['workflow']
421
422     empty_permitted = False
423
424     workflow = forms.ChoiceField( choices=(
425         (0, 'Booking'),
426         (1, 'Resource Bundle'),
427         (2, 'Software Configuration')
428         ),
429         label="Choose Workflow",
430         initial='booking',
431         required=True)
432
433 class SnapshotHostSelectForm(forms.Form):
434     host = forms.CharField()
435
436 class SnapshotMetaForm(forms.Form):
437     name = forms.CharField()
438     description = forms.CharField()
439
440 class ConfirmationForm(forms.Form):
441     fields = ['confirm']
442
443     confirm = forms.ChoiceField( choices=(
444         (True, "Confirm"),
445         (False, "Cancel"))
446         )