add license models

This commit is contained in:
Andreas Zweili 2019-12-29 23:54:27 +01:00
parent c885ab4ac7
commit ba61934b6b
8 changed files with 223 additions and 7 deletions

View File

@ -12,7 +12,8 @@ from .models import (Backup, BackupMethod, TargetDevice, Device, RamType, Ram,
DeviceManufacturer, AdGroup, MailGroup, Location,
MailAlias, IpStatus, Notification, NotificationType,
SoftwareArchitecture, SoftwareCategory, Software, User,
UserInAdGroup, UserInMailGroup)
UserInAdGroup, UserInMailGroup, UserLicense,
ComputerLicense, LicenseWithComputer, LicenseWithUser)
class CustomerAdmin(GuardedModelAdmin):
@ -75,6 +76,22 @@ class IpStatusAdmin(admin.ModelAdmin):
return {}
class LicenseWithComputerAdmin(admin.ModelAdmin):
def get_model_perms(self, request):
"""
Return empty perms dict thus hiding the model from admin index.
"""
return {}
class LicenseWithUserAdmin(admin.ModelAdmin):
def get_model_perms(self, request):
"""
Return empty perms dict thus hiding the model from admin index.
"""
return {}
class MailAliasAdmin(admin.ModelAdmin):
def get_model_perms(self, request):
"""
@ -238,10 +255,16 @@ class DeviceInNetInline(nested_admin.NestedStackedInline):
verbose_name_plural = 'Nets'
class LicenseWithComputerInLine(nested_admin.NestedStackedInline):
model = LicenseWithComputer
extra = 0
verbose_name_plural = 'Licenses'
class ComputerAdmin(nested_admin.NestedModelAdmin):
list_display = ('name', 'host')
inlines = (SoftwareInLine, CpusInLine, RamInLine, DiskInLine, RaidInLine,
DeviceInNetInline)
DeviceInNetInline, LicenseWithComputerInLine)
class AdGroupInLine(admin.StackedInline):
@ -250,6 +273,12 @@ class AdGroupInLine(admin.StackedInline):
verbose_name_plural = 'AD Groups'
class LicenseWithUserInLine(admin.StackedInline):
model = LicenseWithUser
extra = 0
verbose_name_plural = 'Licenses'
class MailGroupInLine(admin.StackedInline):
model = UserInMailGroup
extra = 0
@ -264,7 +293,7 @@ class MailAliasInLine(admin.StackedInline):
class UserAdmin(admin.ModelAdmin):
list_display = ('name', 'customer', 'enabled')
inlines = (AdGroupInLine, MailGroupInLine, MailAliasInLine)
inlines = (AdGroupInLine, MailGroupInLine, MailAliasInLine, LicenseWithUserInLine)
class TargetDeviceInLine(admin.StackedInline):
@ -277,10 +306,23 @@ class BackupAdmin(admin.ModelAdmin):
inlines = (TargetDeviceInLine,)
class UserLicenseAdmin(admin.ModelAdmin):
model = UserLicense
extra = 0
verbose_name_plural = 'User Licenses'
class ComputerLicenseAdmin(admin.ModelAdmin):
model = ComputerLicense
extra = 0
verbose_name_plural = 'Computer Licenses'
admin.site.register(AdGroup)
admin.site.register(Backup, BackupAdmin)
admin.site.register(BackupMethod, BackupMethodAdmin)
admin.site.register(Computer, ComputerAdmin)
admin.site.register(ComputerLicense, ComputerLicenseAdmin)
admin.site.register(ConnectedDevice)
admin.site.register(Cpu, CpuAdmin)
admin.site.register(CpuArchitecture, CpuArchitectureAdmin)
@ -293,6 +335,8 @@ admin.site.register(DeviceManufacturer, DeviceManufacturerAdmin)
admin.site.register(Disk)
admin.site.register(DiskType, DiskTypeAdmin)
admin.site.register(IpStatus, IpStatusAdmin)
admin.site.register(LicenseWithComputer, LicenseWithComputerAdmin)
admin.site.register(LicenseWithUser, LicenseWithUserAdmin)
admin.site.register(Location)
admin.site.register(MailAlias, MailAliasAdmin)
admin.site.register(MailGroup)
@ -311,6 +355,7 @@ admin.site.register(TargetDevice, TargetDeviceAdmin)
admin.site.register(User, UserAdmin)
admin.site.register(UserInAdGroup, UserInAdGroupAdmin)
admin.site.register(UserInMailGroup, UserInMailGroupAdmin)
admin.site.register(UserLicense, UserLicenseAdmin)
admin.site.register(Warranty)
admin.site.register(WarrantyType, WarrantyTypeAdmin)

View File

@ -9,6 +9,8 @@ from .cpu import CpuArchitecture, CpuManufacturer, Cpu
from .devices import (DeviceCategory, Device, ConnectedDevice, DeviceInNet)
from .disk import DiskType, Disk
from .groups import Group, AdGroup, MailGroup
from .license import (License, ComputerLicense, UserLicense,
LicenseWithComputer, LicenseWithUser)
from .location import Location
from .mailalias import MailAlias
from .net import Net, IpStatus

View File

@ -0,0 +1,51 @@
from django.db import models
from .companies import Customer
from .computer import Computer
from .user import User
from .software import Software
class License(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
key = models.CharField(max_length=50, null=True, blank=True)
software = models.ForeignKey(Software,
null=True,
on_delete=models.CASCADE)
def __str__(self):
return str(self.customer) + ": " + str(self.software)
def get_absolute_url(self):
from django.urls import reverse
return reverse('license', args=[str(self.id)])
class Meta:
abstract = True
class UserLicense(License):
max_allowed_users = models.IntegerField(null=True, blank=True)
user = models.ManyToManyField(User, through="LicenseWithUser")
@property
def used_licenses(self):
return LicenseWithUser.objects.filter(pk=self.id).count()
class ComputerLicense(License):
max_allowed_computers = models.IntegerField(null=True, blank=True)
computer = models.ManyToManyField(Computer, through="LicenseWithComputer")
@property
def used_licenses(self):
return LicenseWithComputer.objects.filter(license=self).count()
class LicenseWithUser(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
license = models.ForeignKey(UserLicense, on_delete=models.CASCADE)
class LicenseWithComputer(models.Model):
computer = models.ForeignKey(Computer, on_delete=models.CASCADE)
license = models.ForeignKey(ComputerLicense, on_delete=models.CASCADE)

View File

@ -1,5 +1,5 @@
import django_tables2 as tables
from .models import Net, Device, Backup, DeviceInNet
from .models import Net, Device, Backup, DeviceInNet, ComputerLicense, UserLicense
from django_tables2.utils import A
@ -9,6 +9,7 @@ class CustomersTable(tables.Table):
computers = tables.LinkColumn('computers', text='Computers', args=[A('pk')])
devices = tables.LinkColumn('devices', text='Devices', args=[A('pk')])
backups = tables.LinkColumn('backups', text='Backups', args=[A('pk')])
licenses = tables.LinkColumn('licenses', text='Licenses', args=[A('pk')])
class Meta:
template_name = 'django_tables2/semantic.html'
@ -64,3 +65,25 @@ class NetDetailTable(tables.Table):
class Meta:
template_name = 'django_tables2/semantic.html'
model = DeviceInNet
class UserLicensesTable(tables.Table):
id = tables.Column(visible=False)
license_ptr = tables.Column(visible=False)
customer = tables.Column('Customer', linkify=True)
used_licenses = tables.Column()
class Meta:
template_name = 'django_tables2/semantic.html'
model = UserLicense
class ComputerLicensesTable(tables.Table):
id = tables.Column(visible=False)
license_ptr = tables.Column(visible=False)
customer = tables.Column('Customer', linkify=True)
used_licenses = tables.Column()
class Meta:
template_name = 'django_tables2/semantic.html'
model = ComputerLicense

View File

@ -0,0 +1,9 @@
{% extends "inventory/base.html" %}
{% load render_table from django_tables2 %}
{% block section_title %}Licenses{% endblock %}
{% block content %}
<h3>User Licenses</h3>
{% render_table user_licenses %}
<h3>Computer Licenses</h3>
{% render_table computer_licenses %}
{% endblock %}

View File

@ -0,0 +1,73 @@
import pytest
from django.test import Client
from mixer.backend.django import mixer
import helper
from inventory.models import Customer
pytestmark = pytest.mark.django_db
def test_customer_license_table_not_logged_in():
response = Client().get('/customer/1/licenses/')
assert response.status_code == 302 and 'login' in response.url
def test_customer_license_table(create_admin_user):
fixture = create_admin_user()
customer = fixture['customer']
client = Client()
client.login(username="novartis-admin", password="password")
license = mixer.blend('inventory.UserLicense', customer=customer,
software=mixer.SELECT, key=mixer.RANDOM,
max_allowed_users=mixer.RANDOM)
response = client.get('/customer/' + str(customer.id) + '/licenses/')
assert (response.status_code == 200
and helper.in_content(response, license.software)
and helper.in_content(response, license.key)
and helper.in_content(response, license.max_allowed_users))
def test_customer_license_table_no_license(create_admin_user):
fixture = create_admin_user()
customer = fixture['customer']
client = Client()
client.login(username="novartis-admin", password="password")
response = client.get('/customer/' + str(customer.id) + '/licenses/')
assert (response.status_code == 200
and helper.not_in_content(response, customer))
def test_customer_license_table_no_permission(create_admin_user):
create_admin_user()
customer = Customer.objects.create(name='Nestle')
client = Client()
client.login(username="novartis-admin", password="password")
mixer.blend('inventory.UserLicense', customer=customer)
response = client.get('/customer/' + str(customer.id) + '/licenses/')
assert response.status_code == 403
def test_customer_license_table_multiple_licenses(create_admin_user):
fixture = create_admin_user()
customer = fixture['customer']
user = mixer.blend('inventory.User')
client = Client()
client.login(username="novartis-admin", password="password")
license1 = mixer.blend('inventory.UserLicense', customer=customer,
software=mixer.SELECT, key=mixer.RANDOM,
max_allowed_users=mixer.RANDOM)
license2 = mixer.blend('inventory.UserLicense', customer=customer,
software=mixer.SELECT, key=mixer.RANDOM,
max_allowed_users=mixer.RANDOM)
mixer.blend('inventory.LicenseWithUser', user=user, license=mixer.SELECT)
response = client.get('/customer/' + str(customer.id) + '/licenses/')
assert (response.status_code == 200
and helper.in_content(response, license1.software)
and helper.in_content(response, license1.key)
and helper.in_content(response, license1.max_allowed_users)
and helper.in_content(response, license2.software)
and helper.in_content(response, license2.key)
and helper.in_content(response, license2.max_allowed_users))

View File

@ -21,5 +21,7 @@ urlpatterns = [
path('net/<int:pk>/', views.net_detail_view, name='net'),
path('backup/<int:pk>/', views.backup_detail_view, name='backup'),
path('computers/all/', views.ComputersFilterView.as_view(),
name='all_computers')
name='all_computers'),
path('customer/<int:pk>/licenses/', views.licenses_table_view,
name='licenses'),
]

View File

@ -17,9 +17,9 @@ from .decorators import (computer_view_permission, customer_view_permission,
from .models import (Device, Computer, ComputerRamRelation,
ComputerDiskRelation, ComputerCpuRelation,
ComputerSoftwareRelation, Customer, Net, Raid,
Backup, DeviceInNet, TargetDevice)
Backup, DeviceInNet, TargetDevice, UserLicense, ComputerLicense)
from .tables import (CustomersTable, ComputersTable, DevicesTable, NetsTable,
BackupsTable, NetDetailTable)
BackupsTable, NetDetailTable, UserLicensesTable, ComputerLicensesTable)
from .filters import ComputerFilter
@ -135,3 +135,14 @@ class ComputersFilterView(LoginRequiredMixin, SingleTableMixin, FilterView):
klass=Customer)
results = Computer.objects.filter(customer__in=customers)
return results
@login_required
@customer_view_permission
def licenses_table_view(request, pk):
user_licenses = UserLicensesTable(UserLicense.objects.filter(customer=pk))
computer_licenses = ComputerLicensesTable(ComputerLicense.objects.filter(customer=pk))
RequestConfig(request).configure(user_licenses)
RequestConfig(request).configure(computer_licenses)
return render(request, 'inventory/license_list.html', {'user_licenses': user_licenses,
'computer_licenses': computer_licenses})