aboutsummaryrefslogtreecommitdiffstats
path: root/src/workflow/forms.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/workflow/forms.py')
-rw-r--r--src/workflow/forms.py448
1 files changed, 448 insertions, 0 deletions
diff --git a/src/workflow/forms.py b/src/workflow/forms.py
new file mode 100644
index 0000000..ee44ecd
--- /dev/null
+++ b/src/workflow/forms.py
@@ -0,0 +1,448 @@
+##############################################################################
+# Copyright (c) 2018 Sawyer Bergeron, Parker Berberian, and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+import django.forms as forms
+from django.forms import widgets, ValidationError
+from django.utils.safestring import mark_safe
+from django.template.loader import render_to_string
+from django.forms.widgets import NumberInput
+
+import json
+
+from account.models import Lab
+from account.models import UserProfile
+from resource_inventory.models import (
+ OPNFVRole,
+ Installer,
+ Scenario,
+)
+from booking.lib import get_user_items, get_user_field_opts
+
+
+class SearchableSelectMultipleWidget(widgets.SelectMultiple):
+ template_name = 'dashboard/searchable_select_multiple.html'
+
+ def __init__(self, attrs=None):
+ self.items = attrs['items']
+ self.show_from_noentry = attrs['show_from_noentry']
+ self.show_x_results = attrs['show_x_results']
+ self.results_scrollable = attrs['results_scrollable']
+ self.selectable_limit = attrs['selectable_limit']
+ self.placeholder = attrs['placeholder']
+ self.name = attrs['name']
+ self.initial = attrs.get("initial", [])
+
+ super(SearchableSelectMultipleWidget, self).__init__()
+
+ def render(self, name, value, attrs=None, renderer=None):
+
+ context = self.get_context(attrs)
+ return mark_safe(render_to_string(self.template_name, context))
+
+ def get_context(self, attrs):
+ return {
+ 'items': self.items,
+ 'name': self.name,
+ 'show_from_noentry': self.show_from_noentry,
+ 'show_x_results': self.show_x_results,
+ 'results_scrollable': self.results_scrollable,
+ 'selectable_limit': self.selectable_limit,
+ 'placeholder': self.placeholder,
+ 'initial': self.initial,
+ }
+
+
+class SearchableSelectMultipleField(forms.Field):
+ def __init__(self, *args, required=True, widget=None, label=None, disabled=False,
+ items=None, queryset=None, show_from_noentry=True, show_x_results=-1,
+ results_scrollable=False, selectable_limit=-1, placeholder="search here",
+ name="searchable_select", initial=[], **kwargs):
+ """from the documentation:
+ # required -- Boolean that specifies whether the field is required.
+ # True by default.
+ # widget -- A Widget class, or instance of a Widget class, that should
+ # be used for this Field when displaying it. Each Field has a
+ # default Widget that it'll use if you don't specify this. In
+ # most cases, the default widget is TextInput.
+ # label -- A verbose name for this field, for use in displaying this
+ # field in a form. By default, Django will use a "pretty"
+ # version of the form field name, if the Field is part of a
+ # Form.
+ # initial -- A value to use in this Field's initial display. This value
+ # is *not* used as a fallback if data isn't given.
+ # help_text -- An optional string to use as "help text" for this Field.
+ # error_messages -- An optional dictionary to override the default
+ # messages that the field will raise.
+ # show_hidden_initial -- Boolean that specifies if it is needed to render a
+ # hidden widget with initial value after widget.
+ # validators -- List of additional validators to use
+ # localize -- Boolean that specifies if the field should be localized.
+ # disabled -- Boolean that specifies whether the field is disabled, that
+ # is its widget is shown in the form but not editable.
+ # label_suffix -- Suffix to be added to the label. Overrides
+ # form's label_suffix.
+ """
+
+ self.widget = widget
+ if self.widget is None:
+ self.widget = SearchableSelectMultipleWidget(
+ attrs={
+ 'items': items,
+ 'initial': [obj.id for obj in initial],
+ 'show_from_noentry': show_from_noentry,
+ 'show_x_results': show_x_results,
+ 'results_scrollable': results_scrollable,
+ 'selectable_limit': selectable_limit,
+ 'placeholder': placeholder,
+ 'name': name,
+ 'disabled': disabled
+ }
+ )
+ self.disabled = disabled
+ self.queryset = queryset
+ self.selectable_limit = selectable_limit
+
+ super().__init__(disabled=disabled, **kwargs)
+
+ self.required = required
+
+ def clean(self, data):
+ data = data[0]
+ if not data:
+ if self.required:
+ raise ValidationError("Nothing was selected")
+ else:
+ return []
+ data_as_list = json.loads(data)
+ if self.selectable_limit != -1:
+ if len(data_as_list) > self.selectable_limit:
+ raise ValidationError("Too many items were selected")
+
+ items = []
+ for elem in data_as_list:
+ items.append(self.queryset.get(id=elem))
+
+ return items
+
+
+class SearchableSelectAbstractForm(forms.Form):
+ def __init__(self, *args, queryset=None, initial=[], **kwargs):
+ self.queryset = queryset
+ items = self.generate_items(self.queryset)
+ options = self.generate_options()
+
+ super(SearchableSelectAbstractForm, self).__init__(*args, **kwargs)
+ self.fields['searchable_select'] = SearchableSelectMultipleField(
+ initial=initial,
+ items=items,
+ queryset=self.queryset,
+ **options
+ )
+
+ def get_validated_bundle(self):
+ bundles = self.cleaned_data['searchable_select']
+ if len(bundles) < 1: # don't need to check for >1, as field does that for us
+ raise ValidationError("No bundle was selected")
+ return bundles[0]
+
+ def generate_items(self, queryset):
+ raise Exception("SearchableSelectAbstractForm does not implement concrete generate_items()")
+
+ def generate_options(self, disabled=False):
+ return {
+ 'show_from_noentry': True,
+ 'show_x_results': -1,
+ 'results_scrollable': True,
+ 'selectable_limit': 1,
+ 'placeholder': 'Search for a Bundle',
+ 'name': 'searchable_select',
+ 'disabled': False
+ }
+
+
+class SWConfigSelectorForm(SearchableSelectAbstractForm):
+ def generate_items(self, queryset):
+ items = {}
+
+ for bundle in queryset:
+ items[bundle.id] = {
+ 'expanded_name': bundle.name,
+ 'small_name': bundle.owner.username,
+ 'string': bundle.description,
+ 'id': bundle.id
+ }
+
+ return items
+
+
+class OPNFVSelectForm(SearchableSelectAbstractForm):
+ def generate_items(self, queryset):
+ items = {}
+
+ for config in queryset:
+ items[config.id] = {
+ 'expanded_name': config.name,
+ 'small_name': config.bundle.owner.username,
+ 'string': config.description,
+ 'id': config.id
+ }
+
+ return items
+
+
+class ResourceSelectorForm(SearchableSelectAbstractForm):
+ def generate_items(self, queryset):
+ items = {}
+
+ for bundle in queryset:
+ items[bundle.id] = {
+ 'expanded_name': bundle.name,
+ 'small_name': bundle.owner.username,
+ 'string': bundle.description,
+ 'id': bundle.id
+ }
+
+ return items
+
+
+class BookingMetaForm(forms.Form):
+
+ length = forms.IntegerField(
+ widget=NumberInput(
+ attrs={
+ "type": "range",
+ 'min': "1",
+ "max": "21",
+ "value": "1"
+ }
+ )
+ )
+ purpose = forms.CharField(max_length=1000)
+ project = forms.CharField(max_length=400)
+ info_file = forms.CharField(max_length=1000, required=False)
+ deploy_opnfv = forms.BooleanField(required=False)
+
+ def __init__(self, *args, user_initial=[], owner=None, **kwargs):
+ super(BookingMetaForm, self).__init__(**kwargs)
+
+ self.fields['users'] = SearchableSelectMultipleField(
+ queryset=UserProfile.objects.select_related('user').exclude(user=owner),
+ initial=user_initial,
+ items=get_user_items(exclude=owner),
+ required=False,
+ **get_user_field_opts()
+ )
+
+
+class MultipleSelectFilterWidget(forms.Widget):
+ def __init__(self, *args, display_objects=None, filter_items=None, neighbors=None, **kwargs):
+ super(MultipleSelectFilterWidget, self).__init__(*args, **kwargs)
+ self.display_objects = display_objects
+ self.filter_items = filter_items
+ self.neighbors = neighbors
+ self.template_name = "dashboard/multiple_select_filter_widget.html"
+
+ def render(self, name, value, attrs=None, renderer=None):
+ context = self.get_context(name, value, attrs)
+ html = render_to_string(self.template_name, context=context)
+ return mark_safe(html)
+
+ def get_context(self, name, value, attrs):
+ return {
+ 'display_objects': self.display_objects,
+ 'neighbors': self.neighbors,
+ 'filter_items': self.filter_items,
+ 'initial_value': value
+ }
+
+
+class MultipleSelectFilterField(forms.Field):
+
+ def __init__(self, **kwargs):
+ self.initial = kwargs.get("initial")
+ super().__init__(**kwargs)
+
+ def to_python(self, value):
+ return json.loads(value)
+
+
+class FormUtils:
+ @staticmethod
+ def getLabData(multiple_hosts=False):
+ """
+ Gets all labs and thier host profiles and returns a serialized version the form can understand.
+ Should be rewritten with a related query to make it faster
+ """
+ # javascript truthy variables
+ true = 1
+ false = 0
+ if multiple_hosts:
+ multiple_hosts = true
+ else:
+ multiple_hosts = false
+ labs = {}
+ hosts = {}
+ items = {}
+ neighbors = {}
+ for lab in Lab.objects.all():
+ lab_node = {
+ 'id': "lab_" + str(lab.lab_user.id),
+ 'model_id': lab.lab_user.id,
+ 'name': lab.name,
+ 'description': lab.description,
+ 'selected': false,
+ 'selectable': true,
+ 'follow': false,
+ 'multiple': false,
+ 'class': 'lab'
+ }
+ if multiple_hosts:
+ # "follow" this lab node to discover more hosts if allowed
+ lab_node['follow'] = true
+ items[lab_node['id']] = lab_node
+ neighbors[lab_node['id']] = []
+ labs[lab_node['id']] = lab_node
+
+ for host in lab.hostprofiles.all():
+ host_node = {
+ 'form': {"name": "host_name", "type": "text", "placeholder": "hostname"},
+ 'id': "host_" + str(host.id),
+ 'model_id': host.id,
+ 'name': host.name,
+ 'description': host.description,
+ 'selected': false,
+ 'selectable': true,
+ 'follow': false,
+ 'multiple': multiple_hosts,
+ 'class': 'host'
+ }
+ if multiple_hosts:
+ host_node['values'] = [] # place to store multiple values
+ items[host_node['id']] = host_node
+ neighbors[lab_node['id']].append(host_node['id'])
+ if host_node['id'] not in neighbors:
+ neighbors[host_node['id']] = []
+ neighbors[host_node['id']].append(lab_node['id'])
+ hosts[host_node['id']] = host_node
+
+ display_objects = [("lab", labs.values()), ("host", hosts.values())]
+
+ context = {
+ 'display_objects': display_objects,
+ 'neighbors': neighbors,
+ 'filter_items': items
+ }
+ return context
+
+
+class HardwareDefinitionForm(forms.Form):
+
+ def __init__(self, *args, **kwargs):
+ super(HardwareDefinitionForm, self).__init__(*args, **kwargs)
+ attrs = FormUtils.getLabData(multiple_hosts=True)
+ self.fields['filter_field'] = MultipleSelectFilterField(
+ widget=MultipleSelectFilterWidget(**attrs)
+ )
+
+
+class PodDefinitionForm(forms.Form):
+
+ fields = ["xml"]
+ xml = forms.CharField()
+
+
+class ResourceMetaForm(forms.Form):
+
+ bundle_name = forms.CharField(label="POD Name")
+ bundle_description = forms.CharField(label="POD Description", widget=forms.Textarea)
+
+
+class GenericHostMetaForm(forms.Form):
+
+ host_profile = forms.CharField(label="Host Type", disabled=True, required=False)
+ host_name = forms.CharField(label="Host Name")
+
+
+class NetworkDefinitionForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ super(NetworkDefinitionForm, self).__init__(**kwargs)
+
+
+class NetworkConfigurationForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ super(NetworkConfigurationForm).__init__(**kwargs)
+
+
+class HostSoftwareDefinitionForm(forms.Form):
+
+ host_name = forms.CharField(max_length=200, disabled=True, required=False)
+ headnode = forms.BooleanField(required=False, widget=forms.HiddenInput)
+
+ def __init__(self, *args, **kwargs):
+ imageQS = kwargs.pop("imageQS")
+ super(HostSoftwareDefinitionForm, self).__init__(*args, **kwargs)
+ self.fields['image'] = forms.ModelChoiceField(queryset=imageQS)
+
+
+class WorkflowSelectionForm(forms.Form):
+ fields = ['workflow']
+
+ empty_permitted = False
+
+ workflow = forms.ChoiceField(
+ choices=(
+ (0, 'Booking'),
+ (1, 'Resource Bundle'),
+ (2, 'Software Configuration')
+ ),
+ label="Choose Workflow",
+ initial='booking',
+ required=True
+ )
+
+
+class SnapshotHostSelectForm(forms.Form):
+ host = forms.CharField()
+
+
+class BasicMetaForm(forms.Form):
+ name = forms.CharField()
+ description = forms.CharField(widget=forms.Textarea)
+
+
+class ConfirmationForm(forms.Form):
+ fields = ['confirm']
+
+ confirm = forms.ChoiceField(
+ choices=(
+ (True, "Confirm"),
+ (False, "Cancel")
+ )
+ )
+
+
+class OPNFVSelectionForm(forms.Form):
+ installer = forms.ModelChoiceField(queryset=Installer.objects.all(), required=True)
+ scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=True)
+
+
+class OPNFVNetworkRoleForm(forms.Form):
+ role = forms.CharField(max_length=200, disabled=True, required=False)
+
+ def __init__(self, *args, config_bundle, **kwargs):
+ super(OPNFVNetworkRoleForm, self).__init__(*args, **kwargs)
+ self.fields['network'] = forms.ModelChoiceField(
+ queryset=config_bundle.bundle.networks.all()
+ )
+
+
+class OPNFVHostRoleForm(forms.Form):
+ host_name = forms.CharField(max_length=200, disabled=True, required=False)
+ role = forms.ModelChoiceField(queryset=OPNFVRole.objects.all().order_by("name").distinct("name"))