-{% endblock %}
+{% endblock content %}
diff --git a/accounts/templates/accounts/change_password_form.html b/accounts/templates/accounts/change_password_form.html
new file mode 100644
index 0000000..9dfb6a3
--- /dev/null
+++ b/accounts/templates/accounts/change_password_form.html
@@ -0,0 +1,29 @@
+{% extends "base.html" %}
+
+{% load bootstrap4 %}
+{% load i18n %}
+{% load icons %}
+
+{% block title %}{%trans "Change Password" %}{% endblock title %}
+
+{% block content %}
+
+{% endblock content %}
diff --git a/accounts/templates/create_user_inst_block.html b/accounts/templates/create_user_inst_block.html
deleted file mode 100644
index c496c01..0000000
--- a/accounts/templates/create_user_inst_block.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{% load i18n %}
-{% if request.user.is_superuser %}
-
-
-
-
-{% endif %}
\ No newline at end of file
diff --git a/accounts/templates/profile.html b/accounts/templates/profile.html
index 92b0ef6..54a8bd0 100644
--- a/accounts/templates/profile.html
+++ b/accounts/templates/profile.html
@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
+{% load icons %}
{% load tags_fingerprint %}
{% block title %}{% trans "Profile" %}{% endblock %}
{% block content %}
@@ -16,6 +17,9 @@
- {% if perms.accounts.change_password %}
-
-
- {% endif %}
{% if publickeys %}
diff --git a/accounts/tests.py b/accounts/tests.py
index 4d6c01e..fba29bf 100644
--- a/accounts/tests.py
+++ b/accounts/tests.py
@@ -1,4 +1,4 @@
-from django.contrib.auth.models import User
+from django.contrib.auth.models import Permission, User
from django.shortcuts import reverse
from django.test import Client, TestCase
@@ -6,7 +6,9 @@ from django.test import Client, TestCase
class AccountsTestCase(TestCase):
def setUp(self):
self.client.login(username='admin', password='admin')
- User.objects.create_user(username='test', password='test')
+ user = User.objects.create_user(username='test', password='test')
+ permission = Permission.objects.get(codename='change_password')
+ user.user_permissions.add(permission)
def test_profile(self):
response = self.client.get(reverse('profile'))
@@ -26,3 +28,37 @@ class AccountsTestCase(TestCase):
response = client.get(reverse('logout'))
self.assertRedirects(response, reverse('login'))
+
+ def test_password_change(self):
+ client = Client()
+
+ logged_in = client.login(username='test', password='test')
+ self.assertTrue(logged_in)
+
+ response = client.get(reverse('change_password'))
+ self.assertEqual(response.status_code, 200)
+
+ response = client.post(
+ reverse('change_password'),
+ {
+ 'old_password': 'wrongpass',
+ 'new_password1': 'newpw',
+ 'new_password2': 'newpw',
+ },
+ )
+ self.assertEqual(response.status_code, 200)
+
+ response = client.post(
+ reverse('change_password'),
+ {
+ 'old_password': 'test',
+ 'new_password1': 'newpw',
+ 'new_password2': 'newpw',
+ },
+ )
+ self.assertRedirects(response, reverse('profile'))
+
+ client.logout()
+
+ logged_in = client.login(username='test', password='newpw')
+ self.assertTrue(logged_in)
diff --git a/accounts/urls.py b/accounts/urls.py
index e4306df..6e170ae 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -1,5 +1,6 @@
-from django.urls import path
from django.contrib.auth import views as auth_views
+from django.urls import path
+
from . import views
urlpatterns = [
@@ -7,4 +8,8 @@ urlpatterns = [
path('logout/', auth_views.LogoutView.as_view(template_name='logout.html'), name='logout'),
path('profile/', views.profile, name='profile'),
path('profile/
/', views.account, name='account'),
+ path('change_password/', views.change_password, name='change_password'),
+ path('user_instance/create//', views.user_instance_create, name='user_instance_create'),
+ path('user_instance//update/', views.user_instance_update, name='user_instance_update'),
+ path('user_instance//delete/', views.user_instance_delete, name='user_instance_delete'),
]
diff --git a/accounts/views.py b/accounts/views.py
index 9b8d5a1..2bd765c 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -1,25 +1,26 @@
+import os
+
+import sass
+from django.contrib import messages
+from django.contrib.auth import update_session_auth_hash
+from django.contrib.auth.decorators import permission_required
+from django.contrib.auth.forms import PasswordChangeForm
from django.core.validators import ValidationError
from django.http import HttpResponseRedirect
-from django.shortcuts import render
+from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
-from accounts.forms import UserAddForm
+
from accounts.models import *
from admin.decorators import superuser_only
from appsettings.models import AppSettings
from instances.models import Instance
-import sass
-import os
+from . import forms
+
def profile(request):
- """
- :param request:
- :return:
- """
-
error_messages = []
- # user = User.objects.get(id=request.user.id)
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
if request.method == 'POST':
@@ -30,20 +31,6 @@ def profile(request):
user.email = email
request.user.save()
return HttpResponseRedirect(request.get_full_path())
- if 'oldpasswd' in request.POST:
- oldpasswd = request.POST.get('oldpasswd', '')
- password1 = request.POST.get('passwd1', '')
- password2 = request.POST.get('passwd2', '')
- if not password1 or not password2:
- error_messages.append("Passwords didn't enter")
- if password1 and password2 and password1 != password2:
- error_messages.append("Passwords don't match")
- if not request.user.check_password(oldpasswd):
- error_messages.append("Old password is wrong!")
- if not error_messages:
- request.user.set_password(password1)
- request.user.save()
- return HttpResponseRedirect(request.get_full_path())
if 'keyname' in request.POST:
keyname = request.POST.get('keyname', '')
keypublic = request.POST.get('keypublic', '')
@@ -71,49 +58,78 @@ def profile(request):
@superuser_only
def account(request, user_id):
- """
- :param request:
- :param user_id:
- :return:
- """
-
error_messages = []
user = User.objects.get(id=user_id)
user_insts = UserInstance.objects.filter(user_id=user_id)
instances = Instance.objects.all().order_by('name')
publickeys = UserSSHKey.objects.filter(user_id=user_id)
- if request.method == 'POST':
- if 'delete' in request.POST:
- user_inst = request.POST.get('user_inst', '')
- del_user_inst = UserInstance.objects.get(id=user_inst)
- del_user_inst.delete()
- return HttpResponseRedirect(request.get_full_path())
- if 'permission' in request.POST:
- user_inst = request.POST.get('user_inst', '')
- inst_vnc = request.POST.get('inst_vnc', '')
- inst_change = request.POST.get('inst_change', '')
- inst_delete = request.POST.get('inst_delete', '')
- edit_user_inst = UserInstance.objects.get(id=user_inst)
- edit_user_inst.is_change = bool(inst_change)
- edit_user_inst.is_delete = bool(inst_delete)
- edit_user_inst.is_vnc = bool(inst_vnc)
- edit_user_inst.save()
- return HttpResponseRedirect(request.get_full_path())
- if 'add' in request.POST:
- inst_id = request.POST.get('inst_id', '')
-
- if AppSettings.objects.get(key="ALLOW_INSTANCE_MULTIPLE_OWNER").value == 'True':
- check_inst = UserInstance.objects.filter(instance_id=int(inst_id), user_id=int(user_id))
- else:
- check_inst = UserInstance.objects.filter(instance_id=int(inst_id))
-
- if check_inst:
- msg = _("Instance already added")
- error_messages.append(msg)
- else:
- add_user_inst = UserInstance(instance_id=int(inst_id), user_id=int(user_id))
- add_user_inst.save()
- return HttpResponseRedirect(request.get_full_path())
-
return render(request, 'account.html', locals())
+
+
+@permission_required('accounts.change_password', raise_exception=True)
+def change_password(request):
+ if request.method == 'POST':
+ form = PasswordChangeForm(request.user, request.POST)
+ if form.is_valid():
+ user = form.save()
+ update_session_auth_hash(request, user) # Important!
+ messages.success(request, _('Password Changed'))
+ return redirect('profile')
+ else:
+ messages.error(request, _('Wrong Data Provided'))
+ else:
+ form = PasswordChangeForm(request.user)
+ return render(request, 'accounts/change_password_form.html', {'form': form})
+
+
+@superuser_only
+def user_instance_create(request, user_id):
+ user = get_object_or_404(User, pk=user_id)
+
+ form = forms.UserInstanceForm(request.POST or None, initial={'user': user})
+ if form.is_valid():
+ form.save()
+ return redirect(reverse('account', args=[user.id]))
+
+ return render(
+ request,
+ 'common/form.html',
+ {
+ 'form': form,
+ 'title': _('Create User Instance'),
+ },
+ )
+
+
+@superuser_only
+def user_instance_update(request, pk):
+ user_instance = get_object_or_404(UserInstance, pk=pk)
+ form = forms.UserInstanceForm(request.POST or None, instance=user_instance)
+ if form.is_valid():
+ form.save()
+ return redirect(reverse('account', args=[user_instance.user.id]))
+
+ return render(
+ request,
+ 'common/form.html',
+ {
+ 'form': form,
+ 'title': _('Update User Instance'),
+ },
+ )
+
+
+@superuser_only
+def user_instance_delete(request, pk):
+ user_instance = get_object_or_404(UserInstance, pk=pk)
+ if request.method == 'POST':
+ user = user_instance.user
+ user_instance.delete()
+ return redirect(reverse('account', args=[user.id]))
+
+ return render(
+ request,
+ 'common/confirm_delete.html',
+ {'object': user_instance},
+ )
diff --git a/admin/templates/admin/common/list.html b/admin/templates/admin/common/list.html
index 8d76c0b..d267636 100644
--- a/admin/templates/admin/common/list.html
+++ b/admin/templates/admin/common/list.html
@@ -1,5 +1,5 @@
{% extends "base.html" %}
-{% load font_awesome %}
+{% load icons %}
{% load i18n %}
{% block title %}{{ title }}{% endblock %}
diff --git a/admin/templates/admin/group_list.html b/admin/templates/admin/group_list.html
index f58614d..82b8890 100644
--- a/admin/templates/admin/group_list.html
+++ b/admin/templates/admin/group_list.html
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% load i18n %}
{% load static %}
-{% load font_awesome %}
+{% load icons %}
{% block title %}{% trans "Users" %}{% endblock %}
{% block content %}
diff --git a/admin/templates/admin/logs.html b/admin/templates/admin/logs.html
index 0cbdede..c2db0c4 100644
--- a/admin/templates/admin/logs.html
+++ b/admin/templates/admin/logs.html
@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
+{% load bootstrap4 %}
{% block title %}{% trans "Logs" %}{% endblock %}
{% block content %}
@@ -47,7 +48,7 @@
- {% include "paging.html" %}
+ {% bootstrap_pagination logs %}
{% endif %}
diff --git a/admin/templates/admin/user_form.html b/admin/templates/admin/user_form.html
index b6d7919..db77710 100644
--- a/admin/templates/admin/user_form.html
+++ b/admin/templates/admin/user_form.html
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% load bootstrap4 %}
-{% load font_awesome %}
+{% load icons %}
{% load i18n %}
{% block title %}{% trans "User" %}{% endblock %}
diff --git a/admin/templates/admin/user_list.html b/admin/templates/admin/user_list.html
index 03863ef..1e544f1 100644
--- a/admin/templates/admin/user_list.html
+++ b/admin/templates/admin/user_list.html
@@ -2,7 +2,7 @@
{% load i18n %}
{% load static %}
{% load common_tags %}
-{% load font_awesome %}
+{% load icons %}
{% block title %}{% trans "Users" %}{% endblock %}
{% block content %}
diff --git a/admin/views.py b/admin/views.py
index a7fbed9..3a5f72e 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -1,9 +1,10 @@
+from django.conf import settings
from django.contrib.auth.models import Group, User
from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.translation import ugettext_lazy as _
-from accounts.models import UserAttributes
+from accounts.models import UserAttributes, UserInstance, Instance
from appsettings.models import AppSettings
from logs.models import Logs
@@ -32,7 +33,7 @@ def group_create(request):
return render(
request,
- 'admin/common/form.html',
+ 'common/form.html',
{
'form': form,
'title': _('Create Group'),
@@ -50,7 +51,7 @@ def group_update(request, pk):
return render(
request,
- 'admin/common/form.html',
+ 'common/form.html',
{
'form': form,
'title': _('Update Group'),
@@ -67,7 +68,7 @@ def group_delete(request, pk):
return render(
request,
- 'admin/common/confirm_delete.html',
+ 'common/confirm_delete.html',
{'object': group},
)
@@ -97,6 +98,7 @@ def user_create(request):
attributes = attributes_form.save(commit=False)
attributes.user = user
attributes.save()
+ add_default_instances(user)
return redirect('admin:user_list')
return render(
@@ -141,7 +143,7 @@ def user_delete(request, pk):
return render(
request,
- 'admin/common/confirm_delete.html',
+ 'common/confirm_delete.html',
{'object': user},
)
@@ -169,3 +171,15 @@ def logs(request):
page = request.GET.get('page', 1)
logs = paginator.page(page)
return render(request, 'admin/logs.html', {'logs': logs})
+
+
+def add_default_instances(user):
+ """
+ Adds instances listed in NEW_USER_DEFAULT_INSTANCES to user
+ """
+ existing_instances = UserInstance.objects.filter(user=user)
+ if not existing_instances:
+ for instance_name in settings.NEW_USER_DEFAULT_INSTANCES:
+ instance = Instance.objects.get(name=instance_name)
+ user_instance = UserInstance(user=user, instance=instance)
+ user_instance.save()
diff --git a/appsettings/migrations/0003_auto_20200615_0637.py b/appsettings/migrations/0003_auto_20200615_0637.py
new file mode 100644
index 0000000..54cefed
--- /dev/null
+++ b/appsettings/migrations/0003_auto_20200615_0637.py
@@ -0,0 +1,38 @@
+# Generated by Django 2.2.13 on 2020-06-15 06:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('appsettings', '0002_auto_20200527_1603'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='appsettings',
+ name='choices',
+ field=models.CharField(max_length=50, verbose_name='choices'),
+ ),
+ migrations.AlterField(
+ model_name='appsettings',
+ name='description',
+ field=models.CharField(max_length=100, null=True, verbose_name='description'),
+ ),
+ migrations.AlterField(
+ model_name='appsettings',
+ name='key',
+ field=models.CharField(db_index=True, max_length=50, unique=True, verbose_name='key'),
+ ),
+ migrations.AlterField(
+ model_name='appsettings',
+ name='name',
+ field=models.CharField(max_length=25, verbose_name='name'),
+ ),
+ migrations.AlterField(
+ model_name='appsettings',
+ name='value',
+ field=models.CharField(max_length=25, verbose_name='value'),
+ ),
+ ]
diff --git a/computes/forms.py b/computes/forms.py
index 3a27a39..8bf6d07 100644
--- a/computes/forms.py
+++ b/computes/forms.py
@@ -40,31 +40,3 @@ class SocketComputeForm(forms.ModelForm):
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)
- password = forms.CharField(max_length=100)
- details = forms.CharField(max_length=50, required=False)
-
- 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'))
- return name
-
- 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'))
- return hostname
diff --git a/computes/migrations/0003_auto_20200615_0637.py b/computes/migrations/0003_auto_20200615_0637.py
new file mode 100644
index 0000000..34cd59a
--- /dev/null
+++ b/computes/migrations/0003_auto_20200615_0637.py
@@ -0,0 +1,38 @@
+# Generated by Django 2.2.13 on 2020-06-15 06:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('computes', '0002_auto_20200529_1320'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='compute',
+ name='details',
+ field=models.CharField(blank=True, max_length=64, null=True, verbose_name='details'),
+ ),
+ migrations.AlterField(
+ model_name='compute',
+ name='hostname',
+ field=models.CharField(max_length=64, verbose_name='hostname'),
+ ),
+ migrations.AlterField(
+ model_name='compute',
+ name='login',
+ field=models.CharField(max_length=20, verbose_name='login'),
+ ),
+ migrations.AlterField(
+ model_name='compute',
+ name='name',
+ field=models.CharField(max_length=64, unique=True, verbose_name='name'),
+ ),
+ migrations.AlterField(
+ model_name='compute',
+ name='password',
+ field=models.CharField(blank=True, max_length=14, null=True, verbose_name='password'),
+ ),
+ ]
diff --git a/computes/models.py b/computes/models.py
index c2ab052..cfe0317 100644
--- a/computes/models.py
+++ b/computes/models.py
@@ -1,6 +1,10 @@
-from django.db.models import Model, CharField, IntegerField
+from django.db.models import CharField, IntegerField, Model
+from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
+from vrtManager.connection import connection_manager
+
+
class Compute(Model):
name = CharField(_('name'), max_length=64, unique=True)
hostname = CharField(_('hostname'), max_length=64)
@@ -9,5 +13,9 @@ class Compute(Model):
details = CharField(_('details'), max_length=64, null=True, blank=True)
type = IntegerField()
- def __unicode__(self):
- return self.hostname
+ @cached_property
+ def status(self):
+ return connection_manager.host_is_up(self.type, self.hostname)
+
+ def __str__(self):
+ return self.name
diff --git a/computes/templates/computes.html b/computes/templates/computes.html
deleted file mode 100644
index 3e7f98b..0000000
--- a/computes/templates/computes.html
+++ /dev/null
@@ -1,246 +0,0 @@
-{% extends "base.html" %}
-{% load i18n %}
-{% block title %}{% trans "Computes" %}{% endblock %}
-{% block content %}
-
-
-
- {% include 'create_comp_block.html' %}
-
-
-
-
-
- {% include 'errors_block.html' %}
-
-
- {% if computes_info %}
- {% for compute in computes_info %}
-
- {% if compute.status is True %}
-
-
- {% endfor %}
- {% else %}
-
-
-
- {% trans "Warning" %}: {% trans "Hypervisor doesn't have any Computes" %}
-
-
- {% endif %}
-
-{% endblock %}
diff --git a/computes/templates/computes/form.html b/computes/templates/computes/form.html
index 35c5da7..483a3d1 100644
--- a/computes/templates/computes/form.html
+++ b/computes/templates/computes/form.html
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% load bootstrap4 %}
-{% load font_awesome %}
+{% load icons %}
{% load i18n %}
{% block title %}{% trans "Add Compute" %}{% endblock %}
@@ -11,7 +11,6 @@
-{% bootstrap_messages %}