1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-11-01 03:54:15 +00:00

Reworked some account views

This commit is contained in:
Real-Gecko 2020-06-16 18:35:08 +06:00
parent 1a3cc36ada
commit 636b5bb1bc
8 changed files with 179 additions and 221 deletions

30
accounts/forms.py Normal file
View file

@ -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__'

View file

@ -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')},
),
]

View file

@ -15,7 +15,10 @@ class UserInstance(models.Model):
is_vnc = models.BooleanField(default=False) is_vnc = models.BooleanField(default=False)
def __str__(self): 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): class UserSSHKey(models.Model):

View file

@ -1,140 +1,83 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% block title %}{% trans "User" %} - {{ user }}{% endblock %} {% load icons %}
{% block title %}{% trans "User Profile" %} - {{ user }}{% endblock %}
{% block content %} {% block content %}
<!-- Page Heading --> <!-- Page Heading -->
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
{% include 'create_user_inst_block.html' %} <a href="{% url 'user_instance_create' user.id %}" class="btn btn-success btn-header float-right">
<h2 class="page-header">{{ user }}</h2> {% icon 'plus' %}
</a>
<h2 class="page-header">{% trans "User Profile" %}: {{ user }}</h2>
</div> </div>
</div> </div>
<!-- /.row --> <!-- /.row -->
{% include 'errors_block.html' %} {% include 'errors_block.html' %}
{% if request.user.is_superuser and publickeys %} <ul class="nav nav-tabs">
<div class="row"> <li class="nav-item">
<div class="col-lg-12"> <a class="nav-link active" data-toggle="tab" href="#instances">{% trans "Instances" %}</a>
<div class="table-responsive"> </li>
<table class="table table-bordered table-hover"> <li class="nav-item">
<thead> <a class="nav-link" data-toggle="tab" href="#public-keys">{% trans "Public Keys" %}</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="instances">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">{% trans "Instance" %}</th>
<th scope="col">{% trans "VNC" %}</th>
<th scope="col">{% trans "Resize" %}</th>
<th scope="col">{% trans "Delete" %}</th>
<th scope="colgroup" colspan="2">{% trans "Action" %}</th>
</tr>
</thead>
<tbody>
{% for inst in user_insts %}
<tr> <tr>
<th scope="col">{% trans "Key name" %}</th> <td>{{ forloop.counter }}</td>
<th scope="col">{% trans "Public key" %}</th> <td><a href="{% url 'instance' inst.instance.compute.id inst.instance.name %}">{{ inst.instance.name }}</a></td>
</tr> <td>{{ inst.is_vnc }}</td>
</thead> <td>{{ inst.is_change }}</td>
<tbody> <td>{{ inst.is_delete }}</td>
{% for publickey in publickeys %} <td style="width:5px;">
<tr> <a href="{% url 'user_instance_update' inst.id %}" class="btn btn-sm btn-secondary" title="{% trans "edit" %}">
<td>{{ publickey.keyname }}</td> {% icon 'pencil' %}
<td title="{{ publickey.keypublic }}">{{ publickey.keypublic|truncatechars:64 }}</td> </a>
</td>
<td style="width:5px;">
<a class="btn btn-sm btn-secondary" href="{% url 'user_instance_delete' inst.id %}" title="{% trans "Delete" %}">
{% icon 'trash' %}
</a>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="tab-pane fade" id="public-keys">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">{% trans "Key name" %}</th>
<th scope="col">{% trans "Public key" %}</th>
</tr>
</thead>
<tbody>
{% for publickey in publickeys %}
<tr>
<td>{{ publickey.keyname }}</td>
<td title="{{ publickey.keypublic }}">{{ publickey.keypublic|truncatechars:64 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
</div> </div>
{% endif %} {% endblock content %}
<div class="row">
<div class="col-lg-12">
{% if not user_insts %}
<div class="col-lg-12">
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong> {% trans "User doesn't have any Instance" %}
</div>
</div>
{% else %}
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">{% trans "Instance" %}</th>
<th scope="col">{% trans "VNC" %}</th>
<th scope="col">{% trans "Resize" %}</th>
<th scope="col">{% trans "Delete" %}</th>
<th scope="colgroup" colspan="2">{% trans "Action" %}</th>
</tr>
</thead>
<tbody>
{% for inst in user_insts %}
<tr>
<td>{{ forloop.counter }}</td>
<td><a href="{% url 'instance' inst.instance.compute.id inst.instance.name %}">{{ inst.instance.name }}</a></td>
<td>{{ inst.is_vnc }}</td>
<td>{{ inst.is_change }}</td>
<td>{{ inst.is_delete }}</td>
<td style="width:5px;">
<a href="#editPriv{{ forloop.counter }}" type="button" class="btn btn-sm btn-secondary" data-toggle="modal">
<span class="fa fa-pencil" aria-hidden="true"></span>
</a>
<!-- Modal pool -->
<div class="modal fade" id="editPriv{{ forloop.counter }}" tabindex="-1" role="dialog" aria-labelledby="editPrivLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Edit privilegies for" %} {{ inst.instance.name }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div>
<div class="modal-body">
<form method="post" action="" role="form" aria-label="Edit privileges form">{% csrf_token %}
<input type="hidden" name="user_inst" value="{{ inst.id }}">
<div class="form-group row">
<label class="col-sm-4 col-form-label">{% trans "VNC" %}</label>
<div class="col-sm-6">
<select class="form-control" name="inst_vnc">
<option value="">{% trans 'False' %}</option>
<option value="1" {% if inst.is_vnc %}selected{% endif %}>True</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">{% trans "Resize" %}</label>
<div class="col-sm-6">
<select class="form-control" name="inst_change">
<option value="">{% trans 'False' %}</option>
<option value="1" {% if inst.is_change %}selected{% endif %}>True</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">{% trans "Delete" %}</label>
<div class="col-sm-6">
<select class="form-control" name="inst_delete">
<option value="">{% trans 'False' %}</option>
<option value="1" {% if inst.is_delete %}selected{% endif %}>True</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary" name="permission">{% trans "Edit" %}</button>
</div>
</form>
</div> <!-- /.modal-content -->
</div> <!-- /.modal-dialog -->
</div> <!-- /.modal -->
</td>
<td style="width:5px;">
<form action="" method="post" role="form" aria-label="Delete user form">{% csrf_token %}
<input type="hidden" name="user_inst" value="{{ inst.id }}">
<button type="submit" class="btn btn-sm btn-secondary" name="delete" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
<span class="fa fa-trash" aria-hidden="true"></span>
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -1,36 +0,0 @@
{% load i18n %}
{% if request.user.is_superuser %}
<a href="#addUserInst" type="button" class="btn btn-success btn-header float-right" data-toggle="modal">
<span class="fa fa-plus" aria-hidden="true"></span>
</a>
<!-- Modal pool -->
<div class="modal fade" id="addUserInst" tabindex="-1" role="dialog" aria-labelledby="addUserInstLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Add Instance for User" %}</h5>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div>
<div class="modal-body">
<form method="post" action="" role="form" aria-label="Add user instance form">{% csrf_token %}
<div class="form-group row">
<label class="col-sm-4 col-form-label">{% trans "Host" %} / {% trans "Instance" %}</label>
<div class="col-sm-6">
<select class="custom-select" name="inst_id">
{% for inst in instances %}
<option value="{{ inst.id }}">{{ inst.compute.name }} / {{ inst.name }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary" name="add">{% trans "Add" %}</button>
</div>
</form>
</div> <!-- /.modal-content -->
</div> <!-- /.modal-dialog -->
</div> <!-- /.modal -->
{% endif %}

View file

@ -9,4 +9,7 @@ urlpatterns = [
path('profile/', views.profile, name='profile'), path('profile/', views.profile, name='profile'),
path('profile/<int:user_id>/', views.account, name='account'), path('profile/<int:user_id>/', views.account, name='account'),
path('change_password/', views.change_password, name='change_password'), path('change_password/', views.change_password, name='change_password'),
path('user_instance/create/<int:user_id>/', views.user_instance_create, name='user_instance_create'),
path('user_instance/<int:pk>/update/', views.user_instance_update, name='user_instance_update'),
path('user_instance/<int:pk>/delete/', views.user_instance_delete, name='user_instance_delete'),
] ]

View file

@ -7,7 +7,7 @@ from django.contrib.auth.decorators import permission_required
from django.contrib.auth.forms import PasswordChangeForm from django.contrib.auth.forms import PasswordChangeForm
from django.core.validators import ValidationError from django.core.validators import ValidationError
from django.http import HttpResponseRedirect 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.urls import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -16,15 +16,11 @@ from admin.decorators import superuser_only
from appsettings.models import AppSettings from appsettings.models import AppSettings
from instances.models import Instance from instances.models import Instance
from . import forms
def profile(request): def profile(request):
"""
:param request:
:return:
"""
error_messages = [] error_messages = []
# user = User.objects.get(id=request.user.id)
publickeys = UserSSHKey.objects.filter(user_id=request.user.id) publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
if request.method == 'POST': if request.method == 'POST':
@ -35,20 +31,6 @@ def profile(request):
user.email = email user.email = email
request.user.save() request.user.save()
return HttpResponseRedirect(request.get_full_path()) 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: if 'keyname' in request.POST:
keyname = request.POST.get('keyname', '') keyname = request.POST.get('keyname', '')
keypublic = request.POST.get('keypublic', '') keypublic = request.POST.get('keypublic', '')
@ -76,51 +58,12 @@ def profile(request):
@superuser_only @superuser_only
def account(request, user_id): def account(request, user_id):
"""
:param request:
:param user_id:
:return:
"""
error_messages = [] error_messages = []
user = User.objects.get(id=user_id) user = User.objects.get(id=user_id)
user_insts = UserInstance.objects.filter(user_id=user_id) user_insts = UserInstance.objects.filter(user_id=user_id)
instances = Instance.objects.all().order_by('name') instances = Instance.objects.all().order_by('name')
publickeys = UserSSHKey.objects.filter(user_id=user_id) 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()) return render(request, 'account.html', locals())
@ -138,3 +81,55 @@ def change_password(request):
else: else:
form = PasswordChangeForm(request.user) form = PasswordChangeForm(request.user)
return render(request, 'accounts/change_password_form.html', {'form': form}) 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},
)

View file

@ -12,7 +12,7 @@ class Instance(Model):
created = DateField(_('created'), auto_now_add=True) created = DateField(_('created'), auto_now_add=True)
def __str__(self): def __str__(self):
return self.name return f'{self.compute}/{self.name}'
class PermissionSet(Model): class PermissionSet(Model):