From 7103c523800faa3fa5bcf03f4b970f2992c4f266 Mon Sep 17 00:00:00 2001
From: Real-Gecko <alexandrbezenkov@gmail.com>
Date: Fri, 29 May 2020 19:25:36 +0600
Subject: [PATCH] Reworked some computes forms and views

---
 computes/forms.py                             | 160 +++------------
 .../migrations/0002_auto_20200529_1320.py     |  18 ++
 computes/models.py                            |   2 +-
 computes/templates/computes/form.html         |  29 +++
 computes/templates/create_comp_block.html     | 192 +-----------------
 computes/urls.py                              |   5 +
 computes/validators.py                        |  24 +++
 computes/views.py                             |  86 ++------
 8 files changed, 136 insertions(+), 380 deletions(-)
 create mode 100644 computes/migrations/0002_auto_20200529_1320.py
 create mode 100644 computes/templates/computes/form.html
 create mode 100644 computes/validators.py

diff --git a/computes/forms.py b/computes/forms.py
index bbde4d4..3a27a39 100644
--- a/computes/forms.py
+++ b/computes/forms.py
@@ -2,131 +2,51 @@ import re
 from django import forms
 from django.utils.translation import ugettext_lazy as _
 from computes.models import Compute
+from vrtManager.connection import CONN_TCP, CONN_SSH, CONN_TLS, CONN_SOCKET
+from .validators import validate_hostname
 
 
-class ComputeAddTcpForm(forms.Form):
-    name = forms.CharField(error_messages={'required': _('No hostname has been entered')},
-                           max_length=64)
-    hostname = forms.CharField(error_messages={'required': _('No IP / Domain name has been entered')},
-                               max_length=100)
-    login = forms.CharField(error_messages={'required': _('No login has been entered')},
-                            max_length=100)
-    password = forms.CharField(error_messages={'required': _('No password has been entered')},
-                               max_length=100)
-    details = forms.CharField(max_length=50, required=False)
+class TcpComputeForm(forms.ModelForm):
+    hostname = forms.CharField(validators=[validate_hostname])
+    type = forms.IntegerField(widget=forms.HiddenInput, initial=CONN_TCP)
 
-    def clean_name(self):
-        name = self.cleaned_data['name']
-        have_symbol = re.match('[^a-zA-Z0-9._-]+', name)
-        if have_symbol:
-            raise forms.ValidationError(_('The host name must not contain any special characters'))
-        elif len(name) > 20:
-            raise forms.ValidationError(_('The host name must not exceed 20 characters'))
-        try:
-            Compute.objects.get(name=name)
-        except Compute.DoesNotExist:
-            return name
-        raise forms.ValidationError(_('This host is already connected'))
-
-    def clean_hostname(self):
-        hostname = self.cleaned_data['hostname']
-        have_symbol = re.match('[^a-z0-9.-]+', hostname)
-        wrong_ip = re.match('^0.|^255.', hostname)
-        if have_symbol:
-            raise forms.ValidationError(_('Hostname must contain only numbers, or the domain name separated by "."'))
-        elif wrong_ip:
-            raise forms.ValidationError(_('Wrong IP address'))
-        try:
-            Compute.objects.get(hostname=hostname)
-        except Compute.DoesNotExist:
-            return hostname
-        raise forms.ValidationError(_('This host is already connected'))
+    class Meta:
+        model = Compute
+        fields = '__all__'
 
 
-class ComputeAddSshForm(forms.Form):
-    name = forms.CharField(error_messages={'required': _('No hostname has been entered')},
-                           max_length=64)
-    hostname = forms.CharField(error_messages={'required': _('No IP / Domain name has been entered')},
-                               max_length=100)
-    login = forms.CharField(error_messages={'required': _('No login has been entered')},
-                            max_length=20)
-    details = forms.CharField(max_length=50, required=False)
+class SshComputeForm(forms.ModelForm):
+    hostname = forms.CharField(validators=[validate_hostname], label=_("FQDN/IP"))
+    type = forms.IntegerField(widget=forms.HiddenInput, initial=CONN_SSH)
 
-    def clean_name(self):
-        name = self.cleaned_data['name']
-        have_symbol = re.match('[^a-zA-Z0-9._-]+', name)
-        if have_symbol:
-            raise forms.ValidationError(_('The name of the host must not contain any special characters'))
-        elif len(name) > 20:
-            raise forms.ValidationError(_('The name of the host must not exceed 20 characters'))
-        try:
-            Compute.objects.get(name=name)
-        except Compute.DoesNotExist:
-            return name
-        raise forms.ValidationError(_('This host is already connected'))
-
-    def clean_hostname(self):
-        hostname = self.cleaned_data['hostname']
-        have_symbol = re.match('[^a-zA-Z0-9._-]+', hostname)
-        wrong_ip = re.match('^0.|^255.', hostname)
-        if have_symbol:
-            raise forms.ValidationError(_('Hostname must contain only numbers, or the domain name separated by "."'))
-        elif wrong_ip:
-            raise forms.ValidationError(_('Wrong IP address'))
-        try:
-            Compute.objects.get(hostname=hostname)
-        except Compute.DoesNotExist:
-            return hostname
-        raise forms.ValidationError(_('This host is already connected'))
+    class Meta:
+        model = Compute
+        exclude = ['password']
 
 
-class ComputeAddTlsForm(forms.Form):
-    name = forms.CharField(error_messages={'required': _('No hostname has been entered')},
-                           max_length=64)
-    hostname = forms.CharField(error_messages={'required': _('No IP / Domain name has been entered')},
-                               max_length=100)
-    login = forms.CharField(error_messages={'required': _('No login has been entered')},
-                            max_length=100)
-    password = forms.CharField(error_messages={'required': _('No password has been entered')},
-                               max_length=100)
-    details = forms.CharField(max_length=50, required=False)
+class TlsComputeForm(forms.ModelForm):
+    hostname = forms.CharField(validators=[validate_hostname])
+    type = forms.IntegerField(widget=forms.HiddenInput, initial=CONN_TLS)
 
-    def clean_name(self):
-        name = self.cleaned_data['name']
-        have_symbol = re.match('[^a-zA-Z0-9._-]+', name)
-        if have_symbol:
-            raise forms.ValidationError(_('The host name must not contain any special characters'))
-        elif len(name) > 20:
-            raise forms.ValidationError(_('The host name must not exceed 20 characters'))
-        try:
-            Compute.objects.get(name=name)
-        except Compute.DoesNotExist:
-            return name
-        raise forms.ValidationError(_('This host is already connected'))
+    class Meta:
+        model = Compute
+        fields = '__all__'
 
-    def clean_hostname(self):
-        hostname = self.cleaned_data['hostname']
-        have_symbol = re.match('[^a-z0-9.-]+', hostname)
-        wrong_ip = re.match('^0.|^255.', hostname)
-        if have_symbol:
-            raise forms.ValidationError(_('Hostname must contain only numbers, or the domain name separated by "."'))
-        elif wrong_ip:
-            raise forms.ValidationError(_('Wrong IP address'))
-        try:
-            Compute.objects.get(hostname=hostname)
-        except Compute.DoesNotExist:
-            return hostname
-        raise forms.ValidationError(_('This host is already connected'))
+
+class SocketComputeForm(forms.ModelForm):
+    hostname = forms.CharField(widget=forms.HiddenInput, initial='localhost')
+    type = forms.IntegerField(widget=forms.HiddenInput, initial=CONN_SOCKET)
+
+    class Meta:
+        model = Compute
+        fields = ['name', 'details', 'hostname', 'type']
 
 
 class ComputeEditHostForm(forms.Form):
     host_id = forms.CharField()
-    name = forms.CharField(error_messages={'required': _('No hostname has been entered')},
-                           max_length=64)
-    hostname = forms.CharField(error_messages={'required': _('No IP / Domain name has been entered')},
-                               max_length=100)
-    login = forms.CharField(error_messages={'required': _('No login has been entered')},
-                            max_length=100)
+    name = forms.CharField(error_messages={'required': _('No hostname has been entered')}, max_length=64)
+    hostname = forms.CharField(error_messages={'required': _('No IP / Domain name has been entered')}, max_length=100)
+    login = forms.CharField(error_messages={'required': _('No login has been entered')}, max_length=100)
     password = forms.CharField(max_length=100)
     details = forms.CharField(max_length=50, required=False)
 
@@ -148,21 +68,3 @@ class ComputeEditHostForm(forms.Form):
         elif wrong_ip:
             raise forms.ValidationError(_('Wrong IP address'))
         return hostname
-
-
-class ComputeAddSocketForm(forms.Form):
-    name = forms.CharField(error_messages={'required': _('No hostname has been entered')}, max_length=64)
-    details = forms.CharField(error_messages={'required': _('No details has been entred')}, max_length=50)
-
-    def clean_name(self):
-        name = self.cleaned_data['name']
-        have_symbol = re.match('[^a-zA-Z0-9._-]+', name)
-        if have_symbol:
-            raise forms.ValidationError(_('The host name must not contain any special characters'))
-        elif len(name) > 20:
-            raise forms.ValidationError(_('The host name must not exceed 20 characters'))
-        try:
-            Compute.objects.get(name=name)
-        except Compute.DoesNotExist:
-            return name
-        raise forms.ValidationError(_('This host is already connected'))
diff --git a/computes/migrations/0002_auto_20200529_1320.py b/computes/migrations/0002_auto_20200529_1320.py
new file mode 100644
index 0000000..194d885
--- /dev/null
+++ b/computes/migrations/0002_auto_20200529_1320.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2.12 on 2020-05-29 13:20
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('computes', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='compute',
+            name='name',
+            field=models.CharField(max_length=64, unique=True),
+        ),
+    ]
diff --git a/computes/models.py b/computes/models.py
index db224a3..bda751b 100644
--- a/computes/models.py
+++ b/computes/models.py
@@ -2,7 +2,7 @@ from django.db.models import Model, CharField, IntegerField
 
 
 class Compute(Model):
-    name = CharField(max_length=64)
+    name = CharField(max_length=64, unique=True)
     hostname = CharField(max_length=64)
     login = CharField(max_length=20)
     password = CharField(max_length=14, blank=True, null=True)
diff --git a/computes/templates/computes/form.html b/computes/templates/computes/form.html
new file mode 100644
index 0000000..7b3489e
--- /dev/null
+++ b/computes/templates/computes/form.html
@@ -0,0 +1,29 @@
+{% extends "base.html" %}
+{% load bootstrap3 %}
+{% load font_awesome %}
+{% load i18n %}
+
+{% block title %}{% trans "Add Compute" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col-lg-12">
+        <h2 class="page-header">{% trans "Create Compute" %}</h2>
+    </div>
+</div>
+{% bootstrap_messages %}
+<div class="row">
+    <div class="thumbnail col-sm-10 col-sm-offset-1">
+        <form id="create-update" action="" method="post" class="form-horizontal">
+            {% csrf_token %}
+            {% bootstrap_form form layout='horizontal' %}
+        </form>
+        <div class="form-group pull-right">
+            <a class="btn btn-primary" href="javascript:history.back()">{% icon 'times' %} {% trans "Cancel" %}</a>
+            <button type="submit" form="create-update" class="btn btn-success">
+                {% icon 'check' %} {% trans "Save" %}
+            </button>
+        </div>
+    </div>
+</div>
+{% endblock content %}
\ No newline at end of file
diff --git a/computes/templates/create_comp_block.html b/computes/templates/create_comp_block.html
index 734e4c1..4bcf7dd 100644
--- a/computes/templates/create_comp_block.html
+++ b/computes/templates/create_comp_block.html
@@ -1,185 +1,9 @@
 {% load i18n %}
-{% if request.user.is_superuser %}
-    <a href="#addHost" type="button" class="btn btn-success pull-right" data-toggle="modal">
-        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
-    </a>
-
-    <!-- Modal -->
-    <div class="modal fade" id="addHost" tabindex="-1" role="dialog" aria-labelledby="addHostLabel" aria-hidden="true">
-        <div class="modal-dialog">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times</button>
-                    <h4 class="modal-title">{% trans "Add Connection" %}</h4>
-                </div>
-                <div class="tabbable">
-                    <ul class="nav nav-tabs">
-                        <li class="active">
-                            <a href="#1" data-toggle="tab">{% trans "TCP Connections" %}</a>
-                        </li>
-                        <li><a href="#2" data-toggle="tab">{% trans "SSH Connections" %}</a></li>
-                        <li><a href="#3" data-toggle="tab">{% trans "TLS Connection" %}</a></li>
-                        <li><a href="#4" data-toggle="tab">{% trans "Local Socket" %}</a></li>
-                    </ul>
-                </div>
-                <div class="tab-content">
-                    <div class="tab-pane active" id="1">
-                        <div class="modal-body">
-                            <form class="form-horizontal" method="post" role="form">{% csrf_token %}
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Label" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="name" class="form-control" placeholder="Label Name" maxlength="20" required pattern="[a-z0-9\.\-_]+">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "FQDN / IP" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="hostname" class="form-control" placeholder="{% trans "FQDN or IP Address" %}" required pattern="[a-z0-9\.\-_]+">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Username" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="login" class="form-control" placeholder="{% trans "Username" %}">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Password" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="password" name="password" class="form-control" placeholder="{% trans "Password" %}">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Details" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="details" class="form-control" placeholder="{% trans "Details" %}">
-                                    </div>
-                                </div>
-                        </div>
-                        <div class="modal-footer">
-                            <button type="button" class="btn btn-default" data-dismiss="modal">
-                                {% trans "Close" %}
-                            </button>
-                            <button type="submit" class="btn btn-primary" name="host_tcp_add">
-                                {% trans "Add" %}
-                            </button>
-                        </div>
-                            </form>
-                    </div>
-                    <div class="tab-pane" id="2">
-                        <div class="modal-body">
-                            <form class="form-horizontal" method="post" role="form">{% csrf_token %}
-                                <p class="modal-body">{% trans "You must create ssh <a href='https://github.com/retspen/webvirtmgr/wiki/Setup-SSH-Authorization'>authorization key</a>. If you have another SSH port on your server, you can add IP:PORT like '192.168.1.1:2222'." %}</p>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Label" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="name" class="form-control" placeholder="Label Name" maxlength="20" required pattern="[a-z0-9\.\-_]+">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "FQDN / IP" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="hostname" class="form-control" placeholder="{% trans "FQDN or IP Address" %}" required pattern="[a-z0-9\:\.\-_]+">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Username" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="login" class="form-control" placeholder="{% trans "Username" %}">
-                                    </div>
-                                </div>
-                                 <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Details" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="details" class="form-control" placeholder="{% trans "Details" %}">
-                                    </div>
-                                </div>
-                        </div>
-                        <div class="modal-footer">
-                            <button type="button" class="btn btn-default" data-dismiss="modal">
-                                {% trans "Close" %}
-                            </button>
-                            <button type="submit" class="btn btn-primary" name="host_ssh_add">
-                                {% trans "Add" %}
-                            </button>
-                        </div>
-                            </form>
-                    </div>
-                    <div class="tab-pane" id="3">
-                        <div class="modal-body">
-                            <form class="form-horizontal" method="post" role="form">{% csrf_token %}
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Label" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="name" class="form-control" placeholder="Label Name" maxlength="20" required pattern="[a-z0-9\.\-_]+">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "FQDN / IP" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="hostname" class="form-control" placeholder="{% trans "FQDN or IP Address" %}" required pattern="[a-z0-9\.\-_]+">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Username" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="login" class="form-control" placeholder="{% trans "Username" %}">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Password" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="password" name="password" class="form-control" placeholder="{% trans "Password" %}">
-                                    </div>
-                                </div>
-                                 <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Details" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="details" class="form-control" placeholder="{% trans "Details" %}">
-                                    </div>
-                                </div>
-                        </div>
-                        <div class="modal-footer">
-                            <button type="button" class="btn btn-default" data-dismiss="modal">
-                                {% trans "Close" %}
-                            </button>
-                            <button type="submit" class="btn btn-primary" name="host_tls_add">
-                                {% trans "Add" %}
-                            </button>
-                        </div>
-                            </form>
-                    </div>
-                    <div class="tab-pane" id="4">
-                        <div class="modal-body">
-                            <form class="form-horizontal" method="post" role="form">{% csrf_token %}
-                                <div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Label" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="name" class="form-control" placeholder="Label Name" maxlength="20" required pattern="[a-z0-9\.\-_]+">
-                                    </div>
-                                </div>
-
-								<div class="form-group">
-                                    <label class="col-sm-4 control-label">{% trans "Details" %}</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" name="details" class="form-control" placeholder="{% trans "Details" %}">
-                                    </div>
-                                </div>
-
-                        </div>
-                        <div class="modal-footer">
-                            <button type="button" class="btn btn-default" data-dismiss="modal">
-                                {% trans "Close" %}
-                            </button>
-                            <button type="submit" class="btn btn-primary" name="host_socket_add">
-                                {% trans "Add" %}
-                            </button>
-                        </div>
-                            </form>
-                    </div>
-                </div> <!-- /.tab-content -->
-            </div> <!-- /.modal-content -->
-        </div> <!-- /.modal-dialog -->
-    </div><!-- /.modal -->
-{% endif %}
+{% load bootstrap3 %}
+<div class"pull-right">{% trans "Add Connection" %}</div>
+<div class="btn-group pull-right">
+    <a href="{% url 'add_tcp_host' %}" class="btn btn-success">{% trans "TCP" %}</a>
+    <a href="{% url 'add_ssh_host' %}" class="btn btn-success">{% trans "SSH" %}</a>
+    <a href="{% url 'add_tls_host' %}" class="btn btn-success">{% trans "TLS" %}</a>
+    <a href="{% url 'add_socket_host' %}" class="btn btn-success">{% trans "Local" %}</a>
+</div>
diff --git a/computes/urls.py b/computes/urls.py
index f4713fd..fa77f79 100644
--- a/computes/urls.py
+++ b/computes/urls.py
@@ -9,9 +9,14 @@ from interfaces.views import interface, interfaces
 from networks.views import network, networks
 from nwfilters.views import nwfilter, nwfilters
 from storages.views import get_volumes, storage, storages
+from . import forms
 
 urlpatterns = [
     path('', views.computes, name='computes'),
+    path('add_tcp_host/', views.add_host, {'FormClass': forms.TcpComputeForm}, name='add_tcp_host'),
+    path('add_ssh_host/', views.add_host, {'FormClass': forms.SshComputeForm}, name='add_ssh_host'),
+    path('add_tls_host/', views.add_host, {'FormClass': forms.TlsComputeForm}, name='add_tls_host'),
+    path('add_socket_host/', views.add_host, {'FormClass': forms.SocketComputeForm}, name='add_socket_host'),
     path('<int:compute_id>/', views.overview, name='overview'),
     path('<int:compute_id>/statistics/', views.compute_graph, name='compute_graph'),
     path('<int:compute_id>/instances/', instances, name='instances'),
diff --git a/computes/validators.py b/computes/validators.py
new file mode 100644
index 0000000..abdc4b8
--- /dev/null
+++ b/computes/validators.py
@@ -0,0 +1,24 @@
+from django.core.exceptions import ValidationError
+
+from django.utils.translation import ugettext_lazy as _
+import re
+
+have_symbol = re.compile('[^a-zA-Z0-9._-]+')
+wrong_ip = re.compile('^0.|^255.')
+wrong_name = re.compile('[^a-zA-Z0-9._-]+')
+
+
+def validate_hostname(value):
+    sym = have_symbol.match(value)
+    wip = wrong_ip.match(value)
+
+    if sym:
+        raise ValidationError(_('Hostname must contain only numbers, or the domain name separated by "."'))
+    elif wip:
+        raise ValidationError(_('Wrong IP address'))
+
+
+def validate_name(value):
+    have_symbol = wrong_name.match('[^a-zA-Z0-9._-]+')
+    if have_symbol:
+        raise ValidationError(_('The host name must not contain any special characters'))
diff --git a/computes/views.py b/computes/views.py
index d6b5c73..6d7a4bd 100644
--- a/computes/views.py
+++ b/computes/views.py
@@ -1,16 +1,19 @@
 import json
-from django.utils import timezone
+
+from django.contrib import messages
 from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import get_object_or_404, redirect, render, reverse
 from django.urls import reverse
-from django.shortcuts import render, get_object_or_404
+from django.utils import timezone
+from libvirt import libvirtError
+
+from accounts.models import UserInstance
+from admin.decorators import superuser_only
+from computes.forms import (ComputeEditHostForm, SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm)
 from computes.models import Compute
 from instances.models import Instance
-from accounts.models import UserInstance
-from computes.forms import ComputeAddTcpForm, ComputeAddSshForm, ComputeEditHostForm, ComputeAddTlsForm, ComputeAddSocketForm
+from vrtManager.connection import (CONN_SOCKET, CONN_SSH, CONN_TCP, CONN_TLS, connection_manager, wvmConnect)
 from vrtManager.hostdetails import wvmHostDetails
-from vrtManager.connection import CONN_SSH, CONN_TCP, CONN_TLS, CONN_SOCKET, connection_manager, wvmConnect
-from libvirt import libvirtError
-from admin.decorators import superuser_only
 
 
 @superuser_only
@@ -55,65 +58,6 @@ def computes(request):
                     del_host = Compute.objects.get(id=compute_id)
                     del_host.delete()
             return HttpResponseRedirect(request.get_full_path())
-        if 'host_tcp_add' in request.POST:
-            form = ComputeAddTcpForm(request.POST)
-            if form.is_valid():
-                data = form.cleaned_data
-                new_tcp_host = Compute(name=data['name'],
-                                       hostname=data['hostname'],
-                                       type=CONN_TCP,
-                                       login=data['login'],
-                                       password=data['password'],
-                                       details=data['details'])
-                new_tcp_host.save()
-                return HttpResponseRedirect(request.get_full_path())
-            else:
-                for msg_err in form.errors.values():
-                    error_messages.append(msg_err.as_text())
-        if 'host_ssh_add' in request.POST:
-            form = ComputeAddSshForm(request.POST)
-            if form.is_valid():
-                data = form.cleaned_data
-                new_ssh_host = Compute(name=data['name'],
-                                       hostname=data['hostname'],
-                                       type=CONN_SSH,
-                                       login=data['login'],
-                                       details=data['details'])
-                new_ssh_host.save()
-                return HttpResponseRedirect(request.get_full_path())
-            else:
-                for msg_err in form.errors.values():
-                    error_messages.append(msg_err.as_text())
-        if 'host_tls_add' in request.POST:
-            form = ComputeAddTlsForm(request.POST)
-            if form.is_valid():
-                data = form.cleaned_data
-                new_tls_host = Compute(name=data['name'],
-                                       hostname=data['hostname'],
-                                       type=CONN_TLS,
-                                       login=data['login'],
-                                       password=data['password'],
-                                       details=data['details'])
-                new_tls_host.save()
-                return HttpResponseRedirect(request.get_full_path())
-            else:
-                for msg_err in form.errors.values():
-                    error_messages.append(msg_err.as_text())
-        if 'host_socket_add' in request.POST:
-            form = ComputeAddSocketForm(request.POST)
-            if form.is_valid():
-                data = form.cleaned_data
-                new_socket_host = Compute(name=data['name'],
-                                          details=data['details'],
-                                          hostname='localhost',
-                                          type=CONN_SOCKET,
-                                          login='',
-                                          password='')
-                new_socket_host.save()
-                return HttpResponseRedirect(request.get_full_path())
-            else:
-                for msg_err in form.errors.values():
-                    error_messages.append(msg_err.as_text())
         if 'host_edit' in request.POST:
             form = ComputeEditHostForm(request.POST)
             if form.is_valid():
@@ -274,3 +218,13 @@ def get_dom_capabilities(request, compute_id, arch, machine):
         pass
 
     return HttpResponse(json.dumps(data))
+
+
+@superuser_only
+def add_host(request, FormClass):
+    form = FormClass(request.POST or None)
+    if form.is_valid():
+        form.save()
+        return redirect(reverse('computes'))
+
+    return render(request, 'computes/form.html', {'form': form})