Lab as a Service 2.0
[pharos-tools.git] / dashboard / src / workflow / forms.py
diff --git a/dashboard/src/workflow/forms.py b/dashboard/src/workflow/forms.py
new file mode 100644 (file)
index 0000000..c770e38
--- /dev/null
@@ -0,0 +1,446 @@
+##############################################################################
+# 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
+from django.contrib.auth.models import User
+from django.utils.safestring import mark_safe
+from django.template.loader import render_to_string
+from django.core import serializers
+from django.forms.widgets import NumberInput
+from django.db.models import F
+
+import json
+
+from resource_inventory.models import *
+from account.models import Lab
+from account.models import UserProfile
+
+
+class SearchableSelectMultipleWidget(widgets.SelectMultiple):
+    template_name = 'dashboard/searchable_select_multiple.html'
+
+    def __init__(self, attrs=None):
+        self.items = attrs['set']
+        self.show_from_noentry = attrs['show_from_noentry']
+        self.show_x_results = attrs['show_x_results']
+        self.results_scrollable = attrs['scrollable']
+        self.selectable_limit = attrs['selectable_limit']
+        self.placeholder = attrs['placeholder']
+        self.name = attrs['name']
+        self.initial = attrs.get("initial", "")
+        self.default_entry = attrs.get("default_entry", "")
+        self.edit = attrs.get("edit", False)
+        self.wf_type = attrs.get("wf_type")
+
+        super(SearchableSelectMultipleWidget, self).__init__(attrs)
+
+    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,
+        'default_entry':self.default_entry,
+        'edit': self.edit,
+        'wf_type': self.wf_type
+        }
+
+class ResourceSelectorForm(forms.Form):
+
+    def __init__(self, data=None, **kwargs):
+        chosen_resource = ""
+        bundle = None
+        edit = False
+        if "chosen_resource" in kwargs:
+            chosen_resource = kwargs.pop("chosen_resource")
+        if "bundle" in kwargs:
+            bundle = kwargs.pop("bundle")
+        if "edit" in kwargs:
+            edit = kwargs.pop("edit")
+        super(ResourceSelectorForm, self).__init__(data=data,**kwargs)
+        queryset = GenericResourceBundle.objects.select_related("owner").all()
+        if data and 'user' in data:
+            queryset = queryset.filter(owner=data['user'])
+
+        attrs = self.build_search_widget_attrs(chosen_resource, bundle, edit, queryset)
+
+        self.fields['generic_resource_bundle'] = forms.CharField(
+                widget=SearchableSelectMultipleWidget(attrs=attrs)
+                )
+
+    def build_search_widget_attrs(self, chosen_resource, bundle, edit, queryset):
+        resources = {}
+        for res in queryset:
+            displayable = {}
+            displayable['small_name'] = res.name
+            if res.owner:
+                displayable['expanded_name'] = res.owner.username
+            else:
+                displayable['expanded_name'] = ""
+            displayable['string'] = res.description
+            displayable['id'] = res.id
+            resources[res.id] = displayable
+
+            if bundle:
+                displayable = {}
+                displayable['small_name'] = bundle.name
+                displayable['expanded_name'] = "Current bundle"
+                displayable['string'] = bundle.description
+                displayable['id'] = "repo bundle"
+                resources["repo bundle"] = displayable
+        attrs={
+            'set': resources,
+            'show_from_noentry': "true",
+            'show_x_results': -1,
+            'scrollable': "true",
+            'selectable_limit': 1,
+            'name': "generic_resource_bundle",
+            'placeholder': "resource",
+            'initial': chosen_resource,
+            'edit': edit,
+            'wf_type': 1
+        }
+        return attrs
+
+class SWConfigSelectorForm(forms.Form):
+
+    def __init__(self, *args, **kwargs):
+        chosen_software = ""
+        bundle = None
+        edit = False
+        resource = None
+        if "chosen_software" in kwargs:
+            chosen_software = kwargs.pop("chosen_software")
+
+        if "bundle" in kwargs:
+            bundle = kwargs.pop("bundle")
+        if "edit" in kwargs:
+            edit = kwargs.pop("edit")
+        if "resource" in kwargs:
+            resource = kwargs.pop("resource")
+        super(SWConfigSelectorForm, self).__init__(*args,**kwargs)
+        attrs = self.build_search_widget_attrs(chosen_software,bundle, edit, resource)
+        self.fields['software_bundle'] = forms.CharField(
+                widget=SearchableSelectMultipleWidget(attrs=attrs)
+                )
+
+    def build_search_widget_attrs(self, chosen, bundle, edit, resource):
+        configs = {}
+        queryset = ConfigBundle.objects.select_related('owner').all()
+        if resource:
+            queryset = queryset.filter(bundle=resource)
+
+        for config in queryset:
+            displayable = {}
+            displayable['small_name'] = config.name
+            displayable['expanded_name'] = config.owner.username
+            displayable['string'] = config.description
+            displayable['id'] = config.id
+            configs[config.id] = displayable
+
+        if bundle:
+            displayable = {}
+            displayable['small_name'] = bundle.name
+            displayable['expanded_name'] = "Current configuration"
+            displayable['string'] = bundle.description
+            displayable['id'] = "repo bundle"
+            configs['repo bundle'] = displayable
+
+        attrs={
+            'set': configs,
+            'show_from_noentry': "true",
+            'show_x_results': -1,
+            'scrollable': "true",
+            'selectable_limit': 1,
+            'name': "software_bundle",
+            'placeholder': "config",
+            'initial': chosen,
+            'edit': edit,
+            'wf_type': 2
+        }
+        return attrs
+
+class BookingMetaForm(forms.Form):
+
+    length = forms.IntegerField(widget=NumberInput(attrs={'type':'range', 'min':"0", "max":"21", "value":"0"}))
+    purpose = forms.CharField(max_length=1000)
+    project = forms.CharField(max_length=400)
+    info_file = forms.CharField(max_length=1000, required=False)
+
+    def __init__(self, data=None, *args, **kwargs):
+        chosen_users = []
+        if "default_user" in kwargs:
+            default_user = kwargs.pop("default_user")
+        else:
+            default_user = "you"
+        if "chosen_users" in kwargs:
+            chosen_users = kwargs.pop("chosen_users")
+        elif data and "users" in data:
+            chosen_users = data.getlist("users")
+        else:
+            pass
+
+        super(BookingMetaForm, self).__init__(data=data, **kwargs)
+
+        self.fields['users'] = forms.CharField(
+            widget=SearchableSelectMultipleWidget(
+                attrs=self.build_search_widget_attrs(chosen_users, default_user=default_user)
+                ),
+            required=False
+            )
+
+    def build_user_list(self):
+        """
+        returns a mapping of UserProfile ids to displayable objects expected by
+        searchable multiple select widget
+        """
+        try:
+            users = {}
+            d_qset = UserProfile.objects.select_related('user').all();
+            for userprofile in d_qset:
+                user = {
+                    'id':userprofile.user.id,
+                    'expanded_name':userprofile.full_name,
+                    'small_name':userprofile.user.username,
+                    'string':userprofile.email_addr
+                    }
+
+                users[userprofile.user.id] = user
+
+            return users
+        except Exception as e:
+            pass
+
+    def build_search_widget_attrs(self, chosen_users, default_user="you"):
+
+        attrs={
+            'set': self.build_user_list(),
+            'show_from_noentry': "false",
+            'show_x_results': 10,
+            'scrollable': "false",
+            'selectable_limit': -1,
+            'name': "users",
+            'placeholder': "username",
+            'default_entry': default_user,
+            'initial': chosen_users,
+            'edit': False
+        }
+        return attrs
+
+class MultipleSelectFilterWidget(forms.Widget):
+    def __init__(self, attrs=None):
+        super(MultipleSelectFilterWidget, self).__init__(attrs)
+        self.attrs = attrs
+        self.template_name="dashboard/multiple_select_filter_widget.html"
+
+    def render(self, name, value, attrs=None, renderer=None):
+        attrs = self.attrs
+        self.context = self.get_context(name, value, attrs)
+        html = render_to_string(self.template_name, context=self.context)
+        return mark_safe(html)
+
+    def get_context(self, name, value, attrs):
+        return attrs
+
+class MultipleSelectFilterField(forms.Field):
+    def __init__(   self, required=True, widget=None, label=None, initial=None,
+                    help_text='', error_messages=None, show_hidden_initial=False,
+                    validators=(), localize=False, disabled=False, label_suffix=None):
+        """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.
+        """
+        #this is bad, but django forms are annoying
+        self.widget=widget
+        if self.widget is None:
+            self.widget = MultipleSelectFilterWidget()
+        super(MultipleSelectFilterField, self).__init__(
+            required=required,
+            widget=self.widget,
+            label=label,
+            initial=None,
+            help_text=help_text,
+            error_messages=error_messages,
+            show_hidden_initial=show_hidden_initial,
+            validators=validators,
+            localize=localize,
+            disabled=disabled,
+            label_suffix=label_suffix
+        )
+
+        def clean(data):
+            """
+            This method will raise a django.forms.ValidationError or return clean data
+            """
+            return data
+
+class FormUtils:
+    @staticmethod
+    def getLabData():
+        """
+        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
+        Should be moved outside of global scope
+        """
+        labs = {}
+        hosts = {}
+        items = {}
+        mapping = {}
+        for lab in Lab.objects.all():
+            slab = {}
+            slab['id'] = "lab_" + str(lab.lab_user.id)
+            slab['name'] = lab.name
+            slab['description'] = lab.description
+            slab['selected'] = 0
+            slab['selectable'] = 1
+            slab['follow'] = 1
+            slab['multiple'] = 0
+            items[slab['id']] = slab
+            mapping[slab['id']] = []
+            labs[slab['id']] = slab
+            for host in lab.hostprofiles.all():
+                shost = {}
+                shost['forms'] = [{"name": "host_name", "type": "text", "placeholder": "hostname"}]
+                shost['id'] = "host_" + str(host.id)
+                shost['name'] = host.name
+                shost['description'] = host.description
+                shost['selected'] = 0
+                shost['selectable'] = 1
+                shost['follow'] = 0
+                shost['multiple'] = 1
+                items[shost['id']] = shost
+                mapping[slab['id']].append(shost['id'])
+                if shost['id'] not in mapping:
+                    mapping[shost['id']] = []
+                mapping[shost['id']].append(slab['id'])
+                hosts[shost['id']] = shost
+
+        filter_objects = [("labs", labs.values()), ("hosts", hosts.values())]
+
+        context = {
+                'filter_objects': filter_objects,
+                'mapping': mapping,
+                'items': items
+                }
+        return context
+
+class HardwareDefinitionForm(forms.Form):
+
+    def __init__(self, *args, **kwargs):
+        selection_data = kwargs.pop("selection_data", False)
+        super(HardwareDefinitionForm, self).__init__(*args, **kwargs)
+        attrs = FormUtils.getLabData()
+        attrs['selection_data'] = selection_data
+        self.fields['filter_field'] = MultipleSelectFilterField(
+                widget=MultipleSelectFilterWidget(
+                    attrs=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):
+        fields = []
+
+        super(NetworkDefinitionForm, self).__init__(**kwargs)
+
+class NetworkConfigurationForm(forms.Form):
+    def __init__(self, *args, **kwargs):
+        fields = []
+
+        super(NetworkConfigurationForm).__init__(**kwargs)
+
+class HostSoftwareDefinitionForm(forms.Form):
+    fields = ["host_name", "role", "image"]
+
+    host_name = forms.CharField(max_length=200, disabled=True, required=False)
+    role = forms.ModelChoiceField(queryset=OPNFVRole.objects.all())
+    image = forms.ModelChoiceField(queryset=Image.objects.all())
+
+class SoftwareConfigurationForm(forms.Form):
+
+    name = forms.CharField(max_length=200)
+    description = forms.CharField(widget=forms.Textarea)
+    opnfv = forms.BooleanField(disabled=True, required=False)
+    installer = forms.ModelChoiceField(queryset=Installer.objects.all(), disabled=True, required=False)
+    scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), disabled=True, required=False)
+
+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 SnapshotMetaForm(forms.Form):
+    name = forms.CharField()
+    description = forms.CharField()
+
+class ConfirmationForm(forms.Form):
+    fields = ['confirm']
+
+    confirm = forms.ChoiceField( choices=(
+        (True, "Confirm"),
+        (False, "Cancel"))
+        )