# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see .
from __future__ import absolute_import
from datetime import timedelta
from django.contrib.auth.forms import (
AuthenticationForm, PasswordResetForm, SetPasswordForm,
PasswordChangeForm,
)
from django.contrib.auth.models import User, Group
from django.core.validators import URLValidator
from django.core.exceptions import PermissionDenied, ValidationError
import autocomplete_light
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (
Layout, Div, BaseInput, Field, HTML, Submit, Fieldset, TEMPLATE_PACK,
)
from crispy_forms.utils import render_field
from django import forms
from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
from django.forms.widgets import TextInput, HiddenInput
from django.template import Context
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from sizefield.widgets import FileSizeWidget
from django.core.urlresolvers import reverse_lazy
from django_sshkey.models import UserKey
from firewall.models import Vlan, Host
from vm.models import (
InstanceTemplate, Lease, InterfaceTemplate, Node, Trait, Instance
)
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Permission
from .models import Profile, GroupProfile
from circle.settings.base import LANGUAGES
from django.utils.translation import string_concat
LANGUAGES_WITH_CODE = ((l[0], string_concat(l[1], " (", l[0], ")"))
for l in LANGUAGES)
class VmSaveForm(forms.Form):
name = forms.CharField(max_length=100, label=_('Name'),
help_text=_('Human readable name of template.'))
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmCustomizeForm(forms.Form):
name = forms.CharField()
cpu_priority = forms.IntegerField()
cpu_count = forms.IntegerField()
ram_size = forms.IntegerField()
amount = forms.IntegerField(min_value=0, initial=1)
disks = forms.ModelMultipleChoiceField(
queryset=None, required=False)
networks = forms.ModelMultipleChoiceField(
queryset=None, required=False)
template = forms.CharField()
customized = forms.CharField() # dummy flag field
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
self.template = kwargs.pop("template", None)
super(VmCustomizeForm, self).__init__(*args, **kwargs)
# set displayed disk and network list
self.fields['disks'].queryset = self.template.disks.all()
self.fields['networks'].queryset = Vlan.get_objects_with_level(
'user', self.user)
# set initial for disk and network list
self.initial['disks'] = self.template.disks.all()
self.initial['networks'] = InterfaceTemplate.objects.filter(
template=self.template).values_list("vlan", flat=True)
# set initial for resources
self.initial['cpu_priority'] = self.template.priority
self.initial['cpu_count'] = self.template.num_cores
self.initial['ram_size'] = self.template.ram_size
# initial name and template pk
self.initial['name'] = self.template.name
self.initial['template'] = self.template.pk
self.initial['customized'] = self.template.pk
# set widget for amount
self.fields['amount'].widget = NumberInput()
self.helper = FormHelper(self)
# don't show labels for the sliders
self.helper.form_show_labels = True
self.fields['cpu_count'].label = ""
self.fields['ram_size'].label = ""
self.fields['cpu_priority'].label = ""
self.helper.layout = Layout(
Field("template", type="hidden"),
Field("customized", type="hidden"),
Div(
Div(
AnyTag( # tip: don't try to use Button class
"button",
AnyTag(
"i",
css_class="fa fa-play"
),
HTML(" Start"),
css_id="vm-create-customized-start",
css_class="btn btn-success",
style="float: right; margin-top: 24px;",
),
Field("name", style="max-width: 350px;"),
css_class="col-sm-12",
),
css_class="row",
),
Div(
Div(
Field("amount", min="1", style="max-width: 60px;"),
css_class="col-sm-10",
),
css_class="row",
),
Div(
Div(
AnyTag(
'h2',
HTML(_("Resources")),
),
css_class="col-sm-12",
),
css_class="row",
),
Div( # cpu priority
Div(
HTML(''),
css_class="col-sm-3"
),
Div(
Field('cpu_priority', id="vm-cpu-priority-slider",
css_class="vm-slider",
data_slider_min="0", data_slider_max="100",
data_slider_step="1",
data_slider_value=self.template.priority,
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # cpu count
Div(
HTML(''),
css_class="col-sm-3"
),
Div(
Field('cpu_count', id="vm-cpu-count-slider",
css_class="vm-slider",
data_slider_min="1", data_slider_max="8",
data_slider_step="1",
data_slider_value=self.template.num_cores,
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # ram size
Div(
HTML(''),
css_class="col-sm-3"
),
Div(
Field('ram_size', id="vm-ram-size-slider",
css_class="vm-slider",
data_slider_min="128", data_slider_max="4096",
data_slider_step="128",
data_slider_value=self.template.ram_size,
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # disks
Div(
AnyTag(
"h2",
HTML("Disks")
),
css_class="col-sm-4",
),
Div(
Div(
Field("disks", css_class="form-control",
id="vm-create-disk-add-form"),
css_class="js-hidden",
style="padding-top: 15px; max-width: 450px;",
),
Div(
AnyTag(
"h3",
HTML(_("No disks are added!")),
css_id="vm-create-disk-list",
),
Div(
HTML(""),
style="clear: both;",
),
# AnyTag(
# "h3",
# Div(
# AnyTag(
# "select",
# css_class="form-control",
# css_id="vm-create-disk-add-select",
# ),
# Div(
# AnyTag(
# "a",
# AnyTag(
# "i",
# css_class="icon-plus-sign",
# ),
# href="#",
# css_id="vm-create-disk-add-button",
# css_class="btn btn-success",
# ),
# css_class="input-group-btn"
# ),
# css_class="input-group",
# style="max-width: 330px;",
# ),
# css_id="vm-create-disk-add",
# ),
css_class="no-js-hidden",
),
css_class="col-sm-8",
style="padding-top: 3px;",
),
css_class="row",
), # end of disks
Div( # network
Div(
AnyTag(
"h2",
HTML(_("Network")),
),
css_class="col-sm-4",
),
Div(
Div( # js-hidden
Field(
"networks",
css_class="form-control",
id="vm-create-network-add-vlan",
),
css_class="js-hidden",
style="padding-top: 15px; max-width: 450px;",
),
Div( # no-js-hidden
AnyTag(
"h3",
HTML(_("Not added to any network!")),
css_id="vm-create-network-list",
),
AnyTag(
"h3",
Div(
AnyTag(
"select",
css_class=("form-control "
"font-awesome-font"),
css_id="vm-create-network-add-select",
),
Div(
AnyTag(
"a",
AnyTag(
"i",
css_class="fa fa-plus-circle",
),
css_id=("vm-create-network-add"
"-button"),
css_class="btn btn-success",
),
css_class="input-group-btn",
),
css_class="input-group",
style="max-width: 330px;",
),
css_class="vm-create-network-add"
),
css_class="no-js-hidden",
),
css_class="col-sm-8",
style="padding-top: 3px;",
),
css_class="row"
), # end of network
)
class GroupCreateForm(forms.ModelForm):
description = forms.CharField(label=_("Description"), required=False,
widget=forms.Textarea(attrs={'rows': 3}))
def __init__(self, *args, **kwargs):
new_groups = kwargs.pop('new_groups', None)
super(GroupCreateForm, self).__init__(*args, **kwargs)
choices = [('', '--')]
if new_groups:
choices += [(g, g) for g in new_groups if len(g) <= 64]
self.fields['org_id'] = forms.ChoiceField(
# TRANSLATORS: directory like in LDAP
choices=choices, required=False, label=_('Directory identifier'))
if not new_groups:
self.fields['org_id'].widget = HiddenInput()
def save(self, commit=True):
if not commit:
raise AttributeError('Committing is mandatory.')
group = super(GroupCreateForm, self).save()
profile = group.profile
# multiple blanks were not be unique unlike NULLs are
profile.org_id = self.cleaned_data['org_id'] or None
profile.description = self.cleaned_data['description']
profile.save()
return group
@property
def helper(self):
helper = FormHelper(self)
helper.add_input(Submit("submit", _("Create")))
helper.form_tag = False
return helper
class Meta:
model = Group
fields = ('name', )
class GroupProfileUpdateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
new_groups = kwargs.pop('new_groups', None)
superuser = kwargs.pop('superuser', False)
super(GroupProfileUpdateForm, self).__init__(*args, **kwargs)
if not superuser:
choices = [('', '--')]
if new_groups:
choices += [(g, g) for g in new_groups if len(g) <= 64]
self.fields['org_id'] = forms.ChoiceField(
choices=choices, required=False,
label=_('Directory identifier'))
if not new_groups:
self.fields['org_id'].widget = HiddenInput()
self.fields['description'].widget = forms.Textarea(attrs={'rows': 3})
@property
def helper(self):
helper = FormHelper(self)
helper.add_input(Submit("submit", _("Save")))
helper.form_tag = False
return helper
def save(self, commit=True):
profile = super(GroupProfileUpdateForm, self).save(commit=False)
profile.org_id = self.cleaned_data['org_id'] or None
if commit:
profile.save()
return profile
class Meta:
model = GroupProfile
fields = ('description', 'org_id')
class HostForm(forms.ModelForm):
def setowner(self, user):
self.instance.owner = user
def __init__(self, *args, **kwargs):
super(HostForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
Div( # host
Div(
AnyTag(
'h3',
HTML(_("Host")),
),
css_class="col-sm-3",
),
css_class="row",
),
Div( # host data
Div( # hostname
HTML(''),
css_class="col-sm-3",
),
Div( # hostname
'hostname',
css_class="col-sm-9",
),
Div( # mac
HTML(''),
css_class="col-sm-3",
),
Div(
'mac',
css_class="col-sm-9",
),
Div( # ip
HTML(''),
css_class="col-sm-3",
),
Div(
'ipv4',
css_class="col-sm-9",
),
Div( # vlan
HTML(''),
css_class="col-sm-3",
),
Div(
'vlan',
css_class="col-sm-9",
),
css_class="row",
),
),
)
class Meta:
model = Host
fields = ['hostname', 'vlan', 'mac', 'ipv4', ]
class NodeForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(NodeForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.layout = Layout(
Div(
Div(
Div(
Div(
AnyTag(
'h3',
HTML(_("Node")),
),
css_class="col-sm-3",
),
css_class="row",
),
Div(
Div( # nodename
HTML(''),
css_class="col-sm-3",
),
Div(
'name',
css_class="col-sm-9",
),
css_class="row",
),
Div(
Div( # priority
HTML(''),
css_class="col-sm-3",
),
Div(
'priority',
css_class="col-sm-9",
),
css_class="row",
),
Div(
Div( # enabled
HTML(''),
css_class="col-sm-3",
),
Div(
'enabled',
css_class="col-sm-9",
),
css_class="row",
),
Div( # nested host
HTML("""{% load crispy_forms_tags %}
{% crispy hostform %}
""")
),
Div(
Div(
AnyTag( # tip: don't try to use Button class
"button",
AnyTag(
"i",
css_class="fa fa-play"
),
HTML("Start"),
css_id="node-create-submit",
css_class="btn btn-success",
),
css_class="col-sm-12 text-right",
),
css_class="row",
),
css_class="col-sm-11",
),
css_class="row",
),
)
class Meta:
model = Node
fields = ['name', 'priority', 'enabled', ]
class TemplateForm(forms.ModelForm):
networks = forms.ModelMultipleChoiceField(
queryset=None, required=False, label=_("Networks"))
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
super(TemplateForm, self).__init__(*args, **kwargs)
self.fields['networks'].queryset = Vlan.get_objects_with_level(
'user', self.user)
data = self.data.copy()
data['owner'] = self.user.pk
self.data = data
if self.instance.pk:
n = self.instance.interface_set.values_list("vlan", flat=True)
self.initial['networks'] = n
if self.instance.pk and not self.instance.has_level(self.user,
'owner'):
self.allowed_fields = ()
else:
self.allowed_fields = (
'name', 'access_method', 'description', 'system', 'tags')
if self.user.has_perm('vm.change_template_resources'):
self.allowed_fields += tuple(set(self.fields.keys()) -
set(['raw_data']))
if self.user.is_superuser:
self.allowed_fields += ('raw_data', )
for name, field in self.fields.items():
if name not in self.allowed_fields:
field.widget.attrs['disabled'] = 'disabled'
if not self.instance.pk and len(self.errors) < 1:
self.instance.priority = 20
self.instance.ram_size = 512
self.instance.num_cores = 2
self.fields["lease"].queryset = Lease.get_objects_with_level(
"operator", self.user)
def clean_owner(self):
if self.instance.pk is not None:
return User.objects.get(pk=self.instance.owner.pk)
return self.user
def _clean_fields(self):
try:
old = InstanceTemplate.objects.get(pk=self.instance.pk)
except InstanceTemplate.DoesNotExist:
old = None
for name, field in self.fields.items():
if name in self.allowed_fields:
value = field.widget.value_from_datadict(
self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, forms.FileField):
initial = self.initial.get(name, field.initial)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self._errors[name] = self.error_class(e.messages)
if name in self.cleaned_data:
del self.cleaned_data[name]
elif old:
if name == 'networks':
self.cleaned_data[name] = [
i.vlan for i in self.instance.interface_set.all()]
else:
self.cleaned_data[name] = getattr(old, name)
def save(self, commit=True):
data = self.cleaned_data
self.instance.max_ram_size = data.get('ram_size')
instance = super(TemplateForm, self).save(commit=False)
if commit:
instance.save()
# create and/or delete InterfaceTemplates
networks = InterfaceTemplate.objects.filter(
template=self.instance).values_list("vlan", flat=True)
for m in data['networks']:
if not m.has_level(self.user, "user"):
raise PermissionDenied()
if m.pk not in networks:
InterfaceTemplate(vlan=m, managed=m.managed,
template=self.instance).save()
InterfaceTemplate.objects.filter(
template=self.instance).exclude(
vlan__in=data['networks']).delete()
return instance
@property
def helper(self):
submit_kwargs = {}
if self.instance.pk and not self.instance.has_level(self.user,
'owner'):
submit_kwargs['disabled'] = None
helper = FormHelper()
helper.layout = Layout(
Field("name"),
Fieldset(
_("Resource configuration"),
Div( # cpu count
Div(
Field('num_cores', id="vm-cpu-count-slider",
css_class="vm-slider",
data_slider_min="1", data_slider_max="8",
data_slider_step="1",
data_slider_value=self.instance.num_cores,
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # cpu priority
Div(
Field('priority', id="vm-cpu-priority-slider",
css_class="vm-slider",
data_slider_min="0", data_slider_max="100",
data_slider_step="1",
data_slider_value=self.instance.priority,
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div(
Div(
Field('ram_size', id="vm-ram-size-slider",
css_class="vm-slider",
data_slider_min="128", data_slider_max="4096",
data_slider_step="128",
data_slider_value=self.instance.ram_size,
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row",
),
Field('max_ram_size', type="hidden", value="0"),
Field('arch'),
),
Fieldset(
_("Virtual machine settings"),
Field('access_method'),
Field('boot_menu'),
Field('raw_data'),
Field('req_traits'),
Field('description'),
Field("parent", type="hidden"),
Field("system"),
),
Fieldset(
_("External resources"),
Field("networks"),
Field("lease"),
Field("tags"),
),
)
helper.add_input(Submit('submit', 'Save changes', **submit_kwargs))
return helper
class Meta:
model = InstanceTemplate
exclude = ('state', 'disks', )
widgets = {
'system': forms.TextInput
}
class LeaseForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(LeaseForm, self).__init__(*args, **kwargs)
self.generate_fields()
# e2ae8b048e7198428f696375b8bdcd89e90002d1/django/utils/timesince.py#L10
def get_intervals(self, delta_seconds):
chunks = (
(60 * 60 * 24 * 30, "months"),
(60 * 60 * 24 * 7, "weeks"),
(60 * 60 * 24, "days"),
(60 * 60, "hours"),
)
for i, (seconds, name) in enumerate(chunks):
count = delta_seconds // seconds
if count != 0:
break
re = {'%s' % name: count}
if i + 1 < len(chunks) and i > 0:
seconds2, name2 = chunks[i + 1]
count2 = (delta_seconds - (seconds * count)) // seconds2
if count2 != 0:
re['%s' % name2] = count2
return re
def generate_fields(self):
intervals = ["hours", "days", "weeks", "months"]
methods = ["suspend", "delete"]
# feels redundant but these lines are so long
s = (self.instance.suspend_interval.total_seconds()
if self.instance.pk else 0)
d = (self.instance.delete_interval.total_seconds()
if self.instance.pk else 0)
seconds = {
'suspend': s,
'delete': d
}
initial = {
'suspend': self.get_intervals(int(seconds['suspend'])),
'delete': self.get_intervals(int(seconds['delete']))
}
for m in methods:
for idx, i in enumerate(intervals):
self.fields["%s_%s" % (m, i)] = forms.IntegerField(
min_value=0, widget=NumberInput,
initial=initial[m].get(i, 0))
def save(self, commit=True):
data = self.cleaned_data
suspend_seconds = timedelta(
hours=data['suspend_hours'],
days=(data['suspend_days'] + data['suspend_months'] % 12 * 30 +
data['suspend_months'] / 12 * 365),
weeks=data['suspend_weeks'],
)
delete_seconds = timedelta(
hours=data['delete_hours'],
days=(data['delete_days'] + data['delete_months'] % 12 * 30 +
data['delete_months'] / 12 * 365),
weeks=data['delete_weeks'],
)
self.instance.delete_interval = delete_seconds
self.instance.suspend_interval = suspend_seconds
instance = super(LeaseForm, self).save(commit=False)
if commit:
instance.save()
return instance
@property
def helper(self):
helper = FormHelper()
helper.layout = Layout(
Field('name'),
Field("suspend_interval_seconds", type="hidden", value="0"),
Field("delete_interval_seconds", type="hidden", value="0"),
Div(
Div(
HTML(_("Suspend in")),
css_class="input-group-addon",
style="width: 100px;",
),
NumberField("suspend_hours", css_class="form-control"),
Div(
HTML(_("hours")),
css_class="input-group-addon",
),
NumberField("suspend_days", css_class="form-control"),
Div(
HTML(_("days")),
css_class="input-group-addon",
),
NumberField("suspend_weeks", css_class="form-control"),
Div(
HTML(_("weeks")),
css_class="input-group-addon",
),
NumberField("suspend_months", css_class="form-control"),
Div(
HTML(_("months")),
css_class="input-group-addon",
),
css_class="input-group interval-input",
),
Div(
Div(
HTML(_("Delete in")),
css_class="input-group-addon",
style="width: 100px;",
),
NumberField("delete_hours", css_class="form-control"),
Div(
HTML(_("hours")),
css_class="input-group-addon",
),
NumberField("delete_days", css_class="form-control"),
Div(
HTML(_("days")),
css_class="input-group-addon",
),
NumberField("delete_weeks", css_class="form-control"),
Div(
HTML(_("weeks")),
css_class="input-group-addon",
),
NumberField("delete_months", css_class="form-control"),
Div(
HTML(_("months")),
css_class="input-group-addon",
),
css_class="input-group interval-input",
)
)
helper.add_input(Submit("submit", "Save changes"))
return helper
class Meta:
model = Lease
class VmRenewForm(forms.Form):
def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices')
default = kwargs.pop('default')
super(VmRenewForm, self).__init__(*args, **kwargs)
self.fields['lease'] = forms.ModelChoiceField(queryset=choices,
initial=default,
required=False,
empty_label=None,
label=_('Length'))
if len(choices) < 2:
self.fields['lease'].widget = HiddenInput()
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmCreateDiskForm(forms.Form):
name = forms.CharField(max_length=100, label=_("Name"))
size = forms.CharField(
widget=FileSizeWidget, initial=(10 << 30), label=_('Size'),
help_text=_('Size of disk to create in bytes or with units '
'like MB or GB.'))
def clean_size(self):
size_in_bytes = self.cleaned_data.get("size")
if not size_in_bytes.isdigit() and len(size_in_bytes) > 0:
raise forms.ValidationError(_("Invalid format, you can use "
" GB or MB!"))
return size_in_bytes
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmDownloadDiskForm(forms.Form):
name = forms.CharField(max_length=100, label=_("Name"))
url = forms.CharField(label=_('URL'), validators=[URLValidator(), ])
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class CircleAuthenticationForm(AuthenticationForm):
# fields: username, password
@property
def helper(self):
helper = FormHelper()
helper.form_show_labels = False
helper.layout = Layout(
AnyTag(
"div",
AnyTag(
"span",
AnyTag(
"i",
css_class="fa fa-user",
),
css_class="input-group-addon",
),
Field("username", placeholder=_("Username"),
css_class="form-control"),
css_class="input-group",
),
AnyTag(
"div",
AnyTag(
"span",
AnyTag(
"i",
css_class="fa fa-lock",
),
css_class="input-group-addon",
),
Field("password", placeholder=_("Password"),
css_class="form-control"),
css_class="input-group",
),
)
helper.add_input(Submit("submit", _("Sign in"),
css_class="btn btn-success"))
return helper
class CirclePasswordResetForm(PasswordResetForm):
# fields: email
@property
def helper(self):
helper = FormHelper()
helper.form_show_labels = False
helper.layout = Layout(
AnyTag(
"div",
AnyTag(
"span",
AnyTag(
"i",
css_class="fa fa-envelope",
),
css_class="input-group-addon",
),
Field("email", placeholder=_("Email address"),
css_class="form-control"),
Div(
AnyTag(
"button",
HTML(_("Reset password")),
css_class="btn btn-success",
),
css_class="input-group-btn",
),
css_class="input-group",
),
)
return helper
class CircleSetPasswordForm(SetPasswordForm):
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Change password"),
css_class="btn btn-success change-password",
css_id="submit-password-button"))
return helper
class LinkButton(BaseInput):
"""
Used to create a link button descriptor for the {% crispy %} template tag::
back = LinkButton('back', 'Back', reverse_lazy('index'))
.. note:: The first argument is also slugified and turned into the id for
the submit button.
"""
template = "bootstrap/layout/linkbutton.html"
field_classes = 'btn btn-default'
def __init__(self, name, text, url, *args, **kwargs):
self.href = url
super(LinkButton, self).__init__(name, text, *args, **kwargs)
class NumberInput(TextInput):
input_type = "number"
class NumberField(Field):
template = "crispy_forms/numberfield.html"
def __init__(self, *args, **kwargs):
kwargs['min'] = 0
super(NumberField, self).__init__(*args, **kwargs)
class AnyTag(Div):
template = "crispy_forms/anytag.html"
def __init__(self, tag, *fields, **kwargs):
self.tag = tag
super(AnyTag, self).__init__(*fields, **kwargs)
def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
fields = ''
for field in self.fields:
fields += render_field(field, form, form_style, context,
template_pack=template_pack)
return render_to_string(self.template, Context({'tag': self,
'fields': fields}))
class WorkingBaseInput(BaseInput):
def __init__(self, name, value, input_type="text", **kwargs):
self.input_type = input_type
self.field_classes = "" # we need this for some reason
super(WorkingBaseInput, self).__init__(name, value, **kwargs)
class TraitForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(TraitForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.layout = Layout(
Div(
Field('name', id="node-details-traits-input",
css_class="input-sm input-traits"),
Div(
HTML('',
),
css_class="input-group-btn",
),
css_class="input-group",
id="node-details-traits-form",
),
)
class Meta:
model = Trait
fields = ['name']
class MyProfileForm(forms.ModelForm):
preferred_language = forms.ChoiceField(LANGUAGES_WITH_CODE)
class Meta:
fields = ('preferred_language', 'email_notifications',
'use_gravatar', )
model = Profile
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Save")))
return helper
def save(self, *args, **kwargs):
value = super(MyProfileForm, self).save(*args, **kwargs)
return value
class UnsubscribeForm(forms.ModelForm):
class Meta:
fields = ('email_notifications', )
model = Profile
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Save")))
return helper
class CirclePasswordChangeForm(PasswordChangeForm):
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Change password"),
css_class="btn btn-primary",
css_id="submit-password-button"))
return helper
class UserCreationForm(OrgUserCreationForm):
class Meta:
model = User
fields = ("username", 'email', 'first_name', 'last_name')
@property
def helper(self):
helper = FormHelper()
helper.layout = Layout('username', 'password1', 'password2', 'email',
'first_name', 'last_name')
helper.add_input(Submit("submit", _("Save")))
return helper
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class AclUserAddForm(forms.Form):
name = forms.CharField(widget=autocomplete_light.TextWidget(
'AclUserAutocomplete', attrs={'class': 'form-control'}))
class UserKeyForm(forms.ModelForm):
name = forms.CharField(required=True, label=_('Name'))
key = forms.CharField(
label=_('Key'), required=True,
help_text=_('For example: ssh-rsa AAAAB3NzaC1yc2ED...'),
widget=forms.Textarea(attrs={'rows': 5}))
class Meta:
fields = ('name', 'key')
model = UserKey
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Save")))
return helper
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
super(UserKeyForm, self).__init__(*args, **kwargs)
def clean(self):
if self.user:
self.instance.user = self.user
return super(UserKeyForm, self).clean()
class TraitsForm(forms.ModelForm):
class Meta:
model = Instance
fields = ('req_traits', )
@property
def helper(self):
helper = FormHelper()
helper.form_show_labels = False
helper.form_action = reverse_lazy("dashboard.views.vm-traits",
kwargs={'pk': self.instance.pk})
helper.add_input(Submit("submit", _("Save"),
css_class="btn btn-success", ))
return helper
class RawDataForm(forms.ModelForm):
class Meta:
model = Instance
fields = ('raw_data', )
@property
def helper(self):
helper = FormHelper()
helper.form_show_labels = False
helper.form_action = reverse_lazy("dashboard.views.vm-raw-data",
kwargs={'pk': self.instance.pk})
helper.add_input(Submit("submit", _("Save"),
css_class="btn btn-success",
css_id="submit-password-button"))
return helper
permissions_filtered = Permission.objects.exclude(
codename__startswith="add_").exclude(
codename__startswith="delete_").exclude(
codename__startswith="change_")
class GroupPermissionForm(forms.ModelForm):
permissions = forms.ModelMultipleChoiceField(
queryset=permissions_filtered,
widget=FilteredSelectMultiple(_("permissions"), is_stacked=False)
)
class Meta:
model = Group
fields = ('permissions', )
@property
def helper(self):
helper = FormHelper()
helper.form_show_labels = False
helper.form_action = reverse_lazy(
"dashboard.views.group-permissions",
kwargs={'group_pk': self.instance.pk})
helper.add_input(Submit("submit", _("Save"),
css_class="btn btn-success", ))
return helper