From c39efd8a0b716d65a0abc23c4005f6d21859bec9 Mon Sep 17 00:00:00 2001 From: Real-Gecko Date: Thu, 28 May 2020 11:20:23 +0600 Subject: [PATCH] Added 'instances:clone_instances' permission Replaces 'can_clone_instances' user attribute --- ...move_userattributes_can_clone_instances.py | 18 +++ accounts/models.py | 50 ++++----- admin/templates/admin/user_list.html | 104 ++++++++++-------- instances/migrations/0002_permissionset.py | 24 ++++ .../0003_migrate_can_clone_instances.py | 35 ++++++ instances/models.py | 17 ++- webvirtcloud/common_tags.py | 7 ++ 7 files changed, 179 insertions(+), 76 deletions(-) create mode 100644 accounts/migrations/0005_remove_userattributes_can_clone_instances.py create mode 100644 instances/migrations/0002_permissionset.py create mode 100644 instances/migrations/0003_migrate_can_clone_instances.py diff --git a/accounts/migrations/0005_remove_userattributes_can_clone_instances.py b/accounts/migrations/0005_remove_userattributes_can_clone_instances.py new file mode 100644 index 0000000..76e0458 --- /dev/null +++ b/accounts/migrations/0005_remove_userattributes_can_clone_instances.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.12 on 2020-05-28 04:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0004_apply_change_password'), + ('instances', '0003_migrate_can_clone_instances'), + ] + + operations = [ + migrations.RemoveField( + model_name='userattributes', + name='can_clone_instances', + ), + ] diff --git a/accounts/models.py b/accounts/models.py index d4bb941..ee7da60 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,52 +1,50 @@ from django.conf import settings from django.contrib.auth.models import User from django.core.validators import MinValueValidator -from django.db.models import (CASCADE, DO_NOTHING, BooleanField, CharField, - ForeignKey, IntegerField, Model, OneToOneField) +from django.db import models from django.utils.translation import ugettext_lazy as _ from instances.models import Instance -class UserInstance(Model): - user = ForeignKey(User, on_delete=CASCADE) - instance = ForeignKey(Instance, on_delete=CASCADE) - is_change = BooleanField(default=False) - is_delete = BooleanField(default=False) - is_vnc = BooleanField(default=False) +class UserInstance(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + instance = models.ForeignKey(Instance, on_delete=models.CASCADE) + is_change = models.BooleanField(default=False) + is_delete = models.BooleanField(default=False) + is_vnc = models.BooleanField(default=False) def __unicode__(self): return self.instance.name -class UserSSHKey(Model): - user = ForeignKey(User, on_delete=DO_NOTHING) - keyname = CharField(max_length=25) - keypublic = CharField(max_length=500) +class UserSSHKey(models.Model): + user = models.ForeignKey(User, on_delete=models.DO_NOTHING) + keyname = models.CharField(max_length=25) + keypublic = models.CharField(max_length=500) def __unicode__(self): return self.keyname -class UserAttributes(Model): - user = OneToOneField(User, on_delete=CASCADE) - can_clone_instances = BooleanField(default=True) - max_instances = IntegerField(default=2, - help_text="-1 for unlimited. Any integer value", - validators=[ - MinValueValidator(-1), - ]) - max_cpus = IntegerField( +class UserAttributes(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + max_instances = models.IntegerField(default=2, + help_text="-1 for unlimited. Any integer value", + validators=[ + MinValueValidator(-1), + ]) + max_cpus = models.IntegerField( default=2, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)], ) - max_memory = IntegerField( + max_memory = models.IntegerField( default=2048, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)], ) - max_disk_size = IntegerField( + max_disk_size = models.IntegerField( default=20, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)], @@ -78,14 +76,12 @@ class UserAttributes(Model): return self.user.username -class PermissionSet(Model): +class PermissionSet(models.Model): """ Dummy model for holding set of permissions we need to be automatically added by Django """ class Meta: default_permissions = () - permissions = ( - ('change_password', _('Can change password')), - ) + permissions = (('change_password', _('Can change password')), ) managed = False diff --git a/admin/templates/admin/user_list.html b/admin/templates/admin/user_list.html index c5b0b08..73c6a80 100644 --- a/admin/templates/admin/user_list.html +++ b/admin/templates/admin/user_list.html @@ -1,6 +1,7 @@ {% extends "base.html" %} {% load i18n %} {% load static %} +{% load common_tags %} {% load font_awesome %} {% block title %}{% trans "Users" %}{% endblock %} {% block content %} @@ -18,62 +19,69 @@ {% include 'errors_block.html' %}
{% if not users %} -
-
- - {% icon 'exclamation-triangle '%} {% trans "Warning" %}: {% trans "You don't have any users" %} -
+
+
+ + {% icon 'exclamation-triangle '%} {% trans "Warning" %}: + {% trans "You don't have any users" %}
+
{% else %} -
- - - - - - - - - - - - - {% for user in users %} - - - + + {% endfor %} + +
{% trans "Username" %}{% trans "Status" %}{% trans "Staff" %}{% trans "Superuser" %}{% trans "Clone" %}{% trans "" %}
- {{ user.username }} - +
+ + + + + + + + + + + + + {% for user in users %} + {% has_perm user 'instances.clone_instances' as can_clone %} + + + + + + + - - - - - - {% endfor %} - -
{% trans "Username" %}{% trans "Status" %}{% trans "Staff" %}{% trans "Superuser" %}{% trans "Can Clone" %}{% trans "" %}
+ {{ user.username }} + + {% if user.is_active %} + {% trans "Active" %} + {% else %} + {% trans "Blocked" %} + {% endif %} + {% if user.is_staff %}{% icon 'check' %}{% endif %}{% if user.is_superuser %}{% icon 'check' %}{% endif %}{% if can_clone %}{% icon 'check' %}{% endif %} +
+ {% icon 'eye' %} + {% icon 'pencil' %} {% if user.is_active %} - {% trans "Active" %} + {% icon 'stop' %} {% else %} - {% trans "Blocked" %} + {% icon 'play' %} {% endif %} -
{% if user.is_staff %}{% icon 'check' %}{% endif %}{% if user.is_superuser %}{% icon 'check' %}{% endif %}{% if user.userattributes.can_clone_instances %}{% icon 'check' %}{% endif %} -
- {% icon 'eye' %} - {% icon 'pencil' %} - {% if user.is_active %} - {% icon 'stop' %} - {% else %} - {% icon 'play' %} - {% endif %} - {% icon 'times' %} -
-
-
+ {% icon 'times' %} + +
+
{% endif %}
{% endblock content %} {% block script %} -{% endblock script %} +{% endblock script %} \ No newline at end of file diff --git a/instances/migrations/0002_permissionset.py b/instances/migrations/0002_permissionset.py new file mode 100644 index 0000000..251a56a --- /dev/null +++ b/instances/migrations/0002_permissionset.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.12 on 2020-05-27 07:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('instances', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='PermissionSet', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'permissions': (('clone_instances', 'Can clone instances'),), + 'managed': False, + 'default_permissions': (), + }, + ), + ] diff --git a/instances/migrations/0003_migrate_can_clone_instances.py b/instances/migrations/0003_migrate_can_clone_instances.py new file mode 100644 index 0000000..6b7cc16 --- /dev/null +++ b/instances/migrations/0003_migrate_can_clone_instances.py @@ -0,0 +1,35 @@ +from django.db import migrations + + +def migrate_can_clone_instances(apps, schema_editor): + from django.contrib.auth.models import User, Permission + user: User + users = User.objects.all() + + permission = Permission.objects.get(codename='clone_instances') + + for user in users: + if user.userattributes.can_clone_instances: + user.user_permissions.add(permission) + + +def reverse_can_clone_instances(apps, schema_editor): + from django.contrib.auth.models import User, Permission + user: User + users = User.objects.all() + + permission = Permission.objects.get(codename='clone_instances') + + for user in users: + user.user_permissions.remove(permission) + + +class Migration(migrations.Migration): + + dependencies = [ + ('instances', '0002_permissionset'), + ] + + operations = [ + migrations.RunPython(migrate_can_clone_instances, reverse_can_clone_instances), + ] diff --git a/instances/models.py b/instances/models.py index 436ab41..dd44c54 100644 --- a/instances/models.py +++ b/instances/models.py @@ -1,4 +1,7 @@ -from django.db.models import Model, ForeignKey, CharField, BooleanField, DateField, CASCADE +from django.db.models import (CASCADE, BooleanField, CharField, DateField, + ForeignKey, Model) +from django.utils.translation import ugettext_lazy as _ + from computes.models import Compute @@ -11,3 +14,15 @@ class Instance(Model): def __unicode__(self): return self.name + +class PermissionSet(Model): + """ + Dummy model for holding set of permissions we need to be automatically added by Django + """ + class Meta: + default_permissions = () + permissions = ( + ('clone_instances', _('Can clone instances')), + ) + + managed = False diff --git a/webvirtcloud/common_tags.py b/webvirtcloud/common_tags.py index 4344e59..0b43d01 100644 --- a/webvirtcloud/common_tags.py +++ b/webvirtcloud/common_tags.py @@ -24,3 +24,10 @@ def class_active(request, pattern): # Not sure why 'class="active"' returns class=""active"" return 'active' return '' + + +@register.simple_tag +def has_perm(user, permission_codename): + if user.has_perm(permission_codename): + return True + return False