diff --git a/accounts/forms.py b/accounts/forms.py
new file mode 100644
index 0000000..8c05b75
--- /dev/null
+++ b/accounts/forms.py
@@ -0,0 +1,30 @@
+from django.forms import ModelForm, ValidationError
+from django.utils.translation import ugettext_lazy as _
+
+from appsettings.models import AppSettings
+
+from .models import UserInstance
+
+
+class UserInstanceForm(ModelForm):
+ def __init__(self, *args, **kwargs):
+ super(UserInstanceForm, self).__init__(*args, **kwargs)
+
+ # Make user and instance fields not editable after creation
+ instance = getattr(self, 'instance', None)
+ if instance and instance.id is not None:
+ self.fields['user'].disabled = True
+ self.fields['instance'].disabled = True
+
+ def clean_instance(self):
+ instance = self.cleaned_data['instance']
+ if AppSettings.objects.get(key="ALLOW_INSTANCE_MULTIPLE_OWNER").value == 'False':
+ exists = UserInstance.objects.filter(instance=instance)
+ if exists:
+ raise ValidationError(_('Instance owned by another user'))
+
+ return instance
+
+ class Meta:
+ model = UserInstance
+ fields = '__all__'
diff --git a/accounts/migrations/0005_auto_20200616_1039.py b/accounts/migrations/0005_auto_20200616_1039.py
new file mode 100644
index 0000000..bf48ddc
--- /dev/null
+++ b/accounts/migrations/0005_auto_20200616_1039.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.2.13 on 2020-06-16 10:39
+
+from django.conf import settings
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('instances', '0003_auto_20200615_0637'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('accounts', '0004_auto_20200615_0637'),
+ ]
+
+ operations = [
+ migrations.AlterUniqueTogether(
+ name='userinstance',
+ unique_together={('user', 'instance')},
+ ),
+ ]
diff --git a/accounts/models.py b/accounts/models.py
index 614dfb9..072d9f2 100644
--- a/accounts/models.py
+++ b/accounts/models.py
@@ -15,7 +15,10 @@ class UserInstance(models.Model):
is_vnc = models.BooleanField(default=False)
def __str__(self):
- return self.instance.name
+ return _('Instance "%(inst)s" of user %(user)s') % {'inst': self.instance, 'user': self.user}
+
+ class Meta:
+ unique_together = ['user', 'instance']
class UserSSHKey(models.Model):
diff --git a/accounts/templates/account.html b/accounts/templates/account.html
index 087f431..658c35f 100644
--- a/accounts/templates/account.html
+++ b/accounts/templates/account.html
@@ -1,140 +1,83 @@
{% extends "base.html" %}
{% load i18n %}
-{% block title %}{% trans "User" %} - {{ user }}{% endblock %}
+{% load icons %}
+{% block title %}{% trans "User Profile" %} - {{ user }}{% endblock %}
{% block content %}
- {% include 'create_user_inst_block.html' %}
-
+
+
{% include 'errors_block.html' %}
- {% if request.user.is_superuser and publickeys %}
-
-
-
-
-
+
+
+
+
+
+
+
+ | # |
+ {% trans "Instance" %} |
+ {% trans "VNC" %} |
+ {% trans "Resize" %} |
+ {% trans "Delete" %} |
+ {% trans "Action" %} |
+
+
+
+ {% for inst in user_insts %}
- | {% trans "Key name" %} |
- {% trans "Public key" %} |
-
-
-
- {% for publickey in publickeys %}
-
- | {{ publickey.keyname }} |
- {{ publickey.keypublic|truncatechars:64 }} |
+ {{ forloop.counter }} |
+ {{ inst.instance.name }} |
+ {{ inst.is_vnc }} |
+ {{ inst.is_change }} |
+ {{ inst.is_delete }} |
+
+
+ {% icon 'pencil' %}
+
+ |
+
+
+ {% icon 'trash' %}
+
+ |
{% endfor %}
-
-
-
+
+
+
+
+
+
+
+ | {% trans "Key name" %} |
+ {% trans "Public key" %} |
+
+
+
+ {% for publickey in publickeys %}
+
+ | {{ publickey.keyname }} |
+ {{ publickey.keypublic|truncatechars:64 }} |
+
+ {% endfor %}
+
+
- {% endif %}
-
-
-
- {% if not user_insts %}
-
-
-
- {% trans "Warning" %}: {% trans "User doesn't have any Instance" %}
-
-
- {% else %}
-
-
-
-
- | # |
- {% trans "Instance" %} |
- {% trans "VNC" %} |
- {% trans "Resize" %} |
- {% trans "Delete" %} |
- {% trans "Action" %} |
-
-
-
- {% for inst in user_insts %}
-
- | {{ forloop.counter }} |
- {{ inst.instance.name }} |
- {{ inst.is_vnc }} |
- {{ inst.is_change }} |
- {{ inst.is_delete }} |
-
-
-
-
-
-
-
- |
-
-
- |
-
- {% endfor %}
-
-
-
- {% endif %}
-
-
-{% endblock %}
+{% 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/urls.py b/accounts/urls.py
index bf4ad8b..6e170ae 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -9,4 +9,7 @@ urlpatterns = [
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 53d120f..2bd765c 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -7,7 +7,7 @@ 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 redirect, render
+from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
@@ -16,15 +16,11 @@ from admin.decorators import superuser_only
from appsettings.models import AppSettings
from instances.models import Instance
+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':
@@ -35,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', '')
@@ -76,51 +58,12 @@ 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())
@@ -138,3 +81,55 @@ def change_password(request):
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/instances/models.py b/instances/models.py
index daa2e5f..cec6d39 100644
--- a/instances/models.py
+++ b/instances/models.py
@@ -12,7 +12,7 @@ class Instance(Model):
created = DateField(_('created'), auto_now_add=True)
def __str__(self):
- return self.name
+ return f'{self.compute}/{self.name}'
class PermissionSet(Model):