diff --git a/accounts/templates/profile.html b/accounts/templates/profile.html
index 9d7de4c..8269eb4 100644
--- a/accounts/templates/profile.html
+++ b/accounts/templates/profile.html
@@ -112,44 +112,7 @@
- {% if request.user.is_superuser %}
-
-
- {% endif %}
{% endblock %}
-{% block script %}
-
-{% endblock %}
+
diff --git a/appsettings/__init__.py b/appsettings/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/appsettings/admin.py b/appsettings/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/appsettings/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/appsettings/apps.py b/appsettings/apps.py
new file mode 100644
index 0000000..2e5909e
--- /dev/null
+++ b/appsettings/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class AppsettingsConfig(AppConfig):
+ name = 'appsettings'
diff --git a/appsettings/migrations/0001_initial.py b/appsettings/migrations/0001_initial.py
new file mode 100644
index 0000000..32bf9cd
--- /dev/null
+++ b/appsettings/migrations/0001_initial.py
@@ -0,0 +1,24 @@
+# Generated by Django 2.2.12 on 2020-05-23 15:53
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AppSettings',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=25)),
+ ('key', models.CharField(max_length=50, unique=True)),
+ ('value', models.CharField(max_length=25)),
+ ('description', models.CharField(max_length=100, null=True)),
+ ],
+ ),
+ ]
diff --git a/appsettings/migrations/0002_auto_20200523_1553.py b/appsettings/migrations/0002_auto_20200523_1553.py
new file mode 100644
index 0000000..2ef86eb
--- /dev/null
+++ b/appsettings/migrations/0002_auto_20200523_1553.py
@@ -0,0 +1,80 @@
+# Generated by Django 2.2.12 on 2020-05-23 12:05
+
+from django.db import migrations
+
+def add_default_settings(apps, schema_editor):
+
+ setting = apps.get_model("appsettings", "AppSettings")
+ db_alias = schema_editor.connection.alias
+ setting.objects.using(db_alias).bulk_create([
+ setting(1, "Console Type", "QEMU_CONSOLE_DEFAULT_TYPE", "vnc", "Default console type"),
+ setting(2, "Libvirt K.alive Intrval", "LIBVIRT_KEEPALIVE_INTERVAL", "5", "libvirt keepalive interval"),
+ setting(3, "Libvirt K.alive Count", "LIBVIRT_KEEPALIVE_COUNT", "5", "libvirt keepalive count"),
+ setting(4, "Multiple Owner for VM ", "ALLOW_INSTANCE_MULTIPLE_OWNER", "True"),
+ setting(5, "VM Clone Name Prefix", "CLONE_INSTANCE_DEFAULT_PREFIX", "instance"),
+ setting(6, "VM Clone Auto Name", "CLONE_INSTANCE_AUTO_NAME", "False"),
+ setting(7, "VM Clone Auto Migrate", "CLONE_INSTANCE_AUTO_MIGRATE", "False"),
+ setting(8, "Logs per Page", "LOGS_PER_PAGE", "100"),
+ setting(9, "Quota Debug", "QUOTA_DEBUG", "True"),
+ setting(10, "Empty Password", "ALLOW_EMPTY_PASSWORD", "True"),
+ setting(11, "Account View Style", "VIEW_ACCOUNTS_STYLE", "grid", "available: default (grid), list"),
+ setting(12, "Instance List View", "VIEW_INSTANCES_LIST_STYLE", "grouped", "available instance list style: default (grouped), nongrouped"),
+ setting(13, "Show Bottom Bar", "VIEW_INSTANCE_DETAIL_BOTTOM_BAR", "True", "available options: True, False"),
+ setting(14, "Disk Format", "INSTANCE_VOLUME_DEFAULT_FORMAT", "qcow2", "available volume format: raw, qcow2, qcow"),
+ setting(15, "Disk Bus", "INSTANCE_VOLUME_DEFAULT_BUS", "virtio", "available bus types: virtio, scsi, ide, usb, sata"),
+ setting(16, "Disk SCSI Controller", "INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER", "virtio-scsi", "SCSI Types: virtio-scsi, lsilogic"),
+ setting(17, "Disk Cache", "INSTANCE_VOLUME_DEFAULT_CACHE", "directsync", " Volume cache: default, directsync, none, unsafe, writeback, writethrough"),
+ setting(18, "Disk IO Type", "INSTANCE_VOLUME_DEFAULT_IO", "default", "Volume io mode: default, native, threads"),
+ setting(19, "Disk Detect Zeroes", "INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES", "default", "Volume detect zeroes mode: default, on, off, unmap"),
+ setting(20, "Disk Discard", "INSTANCE_VOLUME_DEFAULT_DISCARD", "default", "Volume discard mode: default, unmap, ignore"),
+ setting(21, "Disk Owner UID", "INSTANCE_VOLUME_DEFAULT_OWNER_UID", "0", "up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)"),
+ setting(22, "Disk Owner GID", "INSTANCE_VOLUME_DEFAULT_OWNER_GID", "0", "up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)"),
+ setting(23, "CPU Mode", "INSTANCE_CPU_DEFAULT_MODE", "host-model", "Cpu modes: no-model, host-model, host-passthrough, custom"),
+ setting(24, "Machine Type", "INSTANCE_MACHINE_DEFAULT_TYPE", "q35", "Chipset/Machine: pc or q35 for x86_64"),
+ setting(25, "Firmware Type", "INSTANCE_FIRMWARE_DEFAULT_TYPE", "BIOS", "Firmware: BIOS or UEFI for x86_64"),
+ setting(26, "Architecture Type", "INSTANCE_ARCH_DEFAULT_TYPE", "x86_64", "Architecture: x86_64, i686, etc"),
+ setting(27, "Theme", "BOOTSTRAP_THEME", "", "Bootstrap CSS & Bootswatch"),
+ setting(28, "Sass Path", "SASS_DIR", "", "Bootstrap SASS & Bootswatch SASS "),
+ ])
+
+def del_default_settings(apps, schema_editor):
+ setting = apps.get_model("appsettings", "AppSettings")
+ db_alias = schema_editor.connection.alias
+ setting.objects.using(db_alias).filter(id=1, key="QEMU_CONSOLE_DEFAULT_TYPE").delete()
+ setting.objects.using(db_alias).filter(id=2, key="LIBVIRT_KEEPALIVE_INTERVAL").delete()
+ setting.objects.using(db_alias).filter(id=3, key="LIBVIRT_KEEPALIVE_COUNT").delete()
+ setting.objects.using(db_alias).filter(id=4, key="ALLOW_INSTANCE_MULTIPLE_OWNER").delete()
+ setting.objects.using(db_alias).filter(id=5, key="CLONE_INSTANCE_DEFAULT_PREFIX").delete()
+ setting.objects.using(db_alias).filter(id=6, key="CLONE_INSTANCE_AUTO_NAME").delete()
+ setting.objects.using(db_alias).filter(id=7, key="CLONE_INSTANCE_AUTO_MIGRATE").delete()
+ setting.objects.using(db_alias).filter(id=8, key="LOGS_PER_PAGE").delete()
+ setting.objects.using(db_alias).filter(id=9, key="QUOTA_DEBUG").delete()
+ setting.objects.using(db_alias).filter(id=10, key="ALLOW_EMPTY_PASSWORD").delete()
+ setting.objects.using(db_alias).filter(id=11, key="VIEW_ACCOUNTS_STYLE").delete()
+ setting.objects.using(db_alias).filter(id=12, key="VIEW_INSTANCES_LIST_STYLE").delete()
+ setting.objects.using(db_alias).filter(id=13, key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").delete()
+ setting.objects.using(db_alias).filter(id=14, key="INSTANCE_VOLUME_DEFAULT_FORMAT").delete()
+ setting.objects.using(db_alias).filter(id=15, key="INSTANCE_VOLUME_DEFAULT_BUS").delete()
+ setting.objects.using(db_alias).filter(id=16, key="INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER").delete()
+ setting.objects.using(db_alias).filter(id=17, key="INSTANCE_VOLUME_DEFAULT_CACHE").delete()
+ setting.objects.using(db_alias).filter(id=18, key="INSTANCE_VOLUME_DEFAULT_IO").delete()
+ setting.objects.using(db_alias).filter(id=19, key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").delete()
+ setting.objects.using(db_alias).filter(id=20, key="INSTANCE_VOLUME_DEFAULT_DISCARD").delete()
+ setting.objects.using(db_alias).filter(id=21, key="INSTANCE_VOLUME_DEFAULT_OWNER_UID").delete()
+ setting.objects.using(db_alias).filter(id=22, key="INSTANCE_VOLUME_DEFAULT_OWNER_GID").delete()
+ setting.objects.using(db_alias).filter(id=23, key="INSTANCE_CPU_DEFAULT_MODE").delete()
+ setting.objects.using(db_alias).filter(id=24, key="INSTANCE_MACHINE_DEFAULT_TYPE").delete()
+ setting.objects.using(db_alias).filter(id=25, key="INSTANCE_FIRMWARE_DEFAULT_TYPE").delete()
+ setting.objects.using(db_alias).filter(id=26, key="INSTANCE_ARCH_DEFAULT_TYPE").delete()
+ setting.objects.using(db_alias).filter(id=27, key="BOOTSTRAP_THEME").delete()
+ setting.objects.using(db_alias).filter(id=28, key="SASS_DIR").delete()
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('appsettings', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RunPython(add_default_settings, del_default_settings),
+ ]
diff --git a/appsettings/migrations/__init__.py b/appsettings/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/appsettings/models.py b/appsettings/models.py
new file mode 100644
index 0000000..30d1e9d
--- /dev/null
+++ b/appsettings/models.py
@@ -0,0 +1,8 @@
+from django.db import models
+
+
+class AppSettings(models.Model):
+ name = models.CharField(max_length=25, null=False)
+ key = models.CharField(max_length=50, unique=True)
+ value = models.CharField(max_length=25)
+ description=models.CharField(max_length=100, null=True)
diff --git a/appsettings/templates/appsettings.html b/appsettings/templates/appsettings.html
new file mode 100644
index 0000000..c5008f5
--- /dev/null
+++ b/appsettings/templates/appsettings.html
@@ -0,0 +1,72 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% block title %}{% trans "Edit Settings" %}{% endblock %}
+{% block content %}
+
+
+
+
+ {% include 'errors_block.html' %}
+
+
+
+
+
+ {% if request.user.is_superuser %}
+
+
+ {% endif %}
+
+
+
+{% endblock %}
diff --git a/appsettings/tests.py b/appsettings/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/appsettings/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/appsettings/views.py b/appsettings/views.py
new file mode 100644
index 0000000..13bdd58
--- /dev/null
+++ b/appsettings/views.py
@@ -0,0 +1,57 @@
+from django.shortcuts import render
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+from django.utils.translation import ugettext_lazy as _
+from django.contrib.auth.decorators import login_required
+from django.conf import settings
+from appsettings.models import AppSettings
+
+import sass
+import os
+
+@login_required
+def appsettings(request):
+ """
+ :param request:
+ :return:
+ """
+ error_messages = []
+
+
+ show_inst_bottom_bar = AppSettings.objects.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR")
+ bootstrap_theme = AppSettings.objects.get(key="BOOTSTRAP_THEME")
+ sass_dir = AppSettings.objects.get(key="SASS_DIR")
+
+ themes_list = os.listdir(sass_dir.value + "/wvc-theme")
+
+ if request.method == 'POST':
+ if 'BOOTSTRAP_THEME' in request.POST:
+ theme = request.POST.get("BOOTSTRAP_THEME", "")
+ scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
+ scss_bootswatch = f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';"
+ scss_boot = f"@import '{sass_dir.value}/bootstrap-overrides.scss';"
+
+ with open(sass_dir.value + "/wvc-main.scss", "w") as main:
+ main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch)
+
+ css_compressed = sass.compile(string=scss_var + "\n"+ scss_boot + "\n" + scss_bootswatch, output_style='compressed')
+ with open("static/" + "css/wvc-main.min.css", "w") as css:
+ css.write(css_compressed)
+
+ bootstrap_theme.value = theme
+ bootstrap_theme.save()
+ return HttpResponseRedirect(request.get_full_path())
+
+ if 'SASS_DIR' in request.POST:
+ sass_dir.value = request.POST.get("SASS_DIR", "")
+ sass_dir.save()
+ return HttpResponseRedirect(request.get_full_path())
+
+ if 'VIEW_INSTANCE_DETAIL_BOTTOM_BAR' in request.POST:
+ show_inst_bottom_bar.value = request.POST.get("VIEW_INSTANCE_DETAIL_BOTTOM_BAR", "")
+ show_inst_bottom_bar.save()
+ return HttpResponseRedirect(request.get_full_path())
+
+
+ return render(request, 'appsettings.html', locals())
+
diff --git a/instances/views.py b/instances/views.py
index f950761..be7a2fb 100644
--- a/instances/views.py
+++ b/instances/views.py
@@ -15,6 +15,7 @@ from computes.models import Compute
from instances.models import Instance
from django.contrib.auth.models import User
from accounts.models import UserInstance, UserSSHKey
+from appsettings.models import AppSettings
from vrtManager.hostdetails import wvmHostDetails
from vrtManager.instance import wvmInstance, wvmInstances
from vrtManager.connection import connection_manager
@@ -113,7 +114,7 @@ def instance(request, compute_id, vname):
keymaps = settings.QEMU_KEYMAPS
console_types = settings.QEMU_CONSOLE_TYPES
console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES
- bottom_bar = settings.VIEW_INSTANCE_DETAIL_BOTTOM_BAR
+ bottom_bar = AppSettings.objects.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").value
try:
userinstance = UserInstance.objects.get(instance__compute_id=compute_id,
instance__name=vname,
diff --git a/storages/templates/storage.html b/storages/templates/storage.html
index c089f60..bacc16d 100644
--- a/storages/templates/storage.html
+++ b/storages/templates/storage.html
@@ -82,7 +82,6 @@
-
{% if state %}
diff --git a/templates/navbar.html b/templates/navbar.html
index 4fc8387..a9714ea 100644
--- a/templates/navbar.html
+++ b/templates/navbar.html
@@ -14,22 +14,25 @@
{% trans "Instances" %}
{% if request.user.is_superuser %}
-
- {% trans "Computes" %}
-
-
-
- {% trans "Administration" %}
-
-
-
+
+ {% trans "Computes" %}
+
{% endif %}
-
+
+ {% if request.user.is_superuser %}
+ -
+
+ {% icon 'wrench' %}
+
+
+
+ {% endif %}
-
{{ request.user.username }}
diff --git a/webvirtcloud/settings.py.template b/webvirtcloud/settings.py.template
index a0edd40..efaeceb 100644
--- a/webvirtcloud/settings.py.template
+++ b/webvirtcloud/settings.py.template
@@ -35,6 +35,7 @@ INSTALLED_APPS = [
'nwfilters',
'storages',
'secrets',
+ 'appsettings',
'logs',
]
@@ -186,9 +187,6 @@ SHOW_ACCESS_SSH_KEYS = False
# available list style: default (grouped), nongrouped
VIEW_INSTANCES_LIST_STYLE = 'grouped'
-# available options: True, False
-VIEW_INSTANCE_DETAIL_BOTTOM_BAR = True
-
# available volume format: raw, qcow2, qcow
INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2'
diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py
index 05d2608..b32eb36 100644
--- a/webvirtcloud/urls.py
+++ b/webvirtcloud/urls.py
@@ -2,14 +2,17 @@ from django.urls import include, path
from instances.views import index
from console.views import console
+from appsettings.views import appsettings
urlpatterns = [
path('', index, name='index'),
path('admin/', include(('admin.urls', 'admin'), namespace='admin')),
- path('instances/', include('instances.urls')),
path('accounts/', include('accounts.urls')),
+ path('appsettings/', appsettings, name='appsettings'),
path('computes/', include('computes.urls')),
- path('logs/', include('logs.urls')),
- path('datasource/', include('datasource.urls')),
path('console/', console, name='console'),
+ path('datasource/', include('datasource.urls')),
+ path('instances/', include('instances.urls')),
+ path('i18n/', include('django.conf.urls.i18n')),
+ path('logs/', include('logs.urls')),
]