From a0b5a08f0d27f8676998eaf818c449961ccc42dd Mon Sep 17 00:00:00 2001 From: Jon Date: Sat, 18 May 2024 17:42:49 +0930 Subject: [PATCH] feat(itam): Add Operating System to ITAM models !6 --- app/app/settings.py | 2 +- app/itam/forms/device/device.py | 19 +++ app/itam/forms/device/operating_system.py | 18 +++ app/itam/forms/operating_system/__init__.py | 0 app/itam/forms/operating_system/update.py | 41 ++++++ ..._operatingsystem_operatingsystemversion.py | 47 ++++++ ...er_operatingsystemversion_name_and_more.py | 38 +++++ app/itam/models/device.py | 35 ++++- app/itam/models/operating_system.py | 64 ++++++++ app/itam/templates/itam/device.html.j2 | 138 +++++++++--------- .../templates/itam/operating_system.html.j2 | 131 +++++++++++++++++ .../itam/operating_system_index.html.j2 | 47 ++++++ app/itam/templates/itam/software.html.j2 | 6 +- app/itam/tests/test_devices.py | 8 + app/itam/tests/test_operating_system.py | 41 ++++++ app/itam/urls.py | 17 ++- app/itam/views/device.py | 66 +++++++-- app/itam/views/operating_system.py | 112 ++++++++++++++ app/itam/views/operating_system_version.py | 88 +++++++++++ 19 files changed, 830 insertions(+), 88 deletions(-) create mode 100644 app/itam/forms/device/device.py create mode 100644 app/itam/forms/device/operating_system.py create mode 100644 app/itam/forms/operating_system/__init__.py create mode 100644 app/itam/forms/operating_system/update.py create mode 100644 app/itam/migrations/0004_operatingsystem_operatingsystemversion.py create mode 100644 app/itam/migrations/0005_alter_operatingsystemversion_name_and_more.py create mode 100644 app/itam/models/operating_system.py create mode 100644 app/itam/templates/itam/operating_system.html.j2 create mode 100644 app/itam/templates/itam/operating_system_index.html.j2 create mode 100644 app/itam/tests/test_operating_system.py create mode 100644 app/itam/views/operating_system.py create mode 100644 app/itam/views/operating_system_version.py diff --git a/app/app/settings.py b/app/app/settings.py index a693e4d3..897bfc00 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -196,7 +196,7 @@ if API_ENABLED: 'TEST_REQUEST_DEFAULT_FORMAT': 'json' } - +DATETIME_FORMAT = 'j N Y H:i:s' if os.path.isdir(SETTINGS_DIR): diff --git a/app/itam/forms/device/device.py b/app/itam/forms/device/device.py new file mode 100644 index 00000000..2d1f22b3 --- /dev/null +++ b/app/itam/forms/device/device.py @@ -0,0 +1,19 @@ +from django import forms +from django.db.models import Q + +from itam.models.device import Device + + +class DeviceForm(forms.ModelForm): + + prefix = 'device' + + class Meta: + model = Device + fields = [ + 'id', + 'name', + 'serial_number', + 'uuid', + 'device_type', + ] diff --git a/app/itam/forms/device/operating_system.py b/app/itam/forms/device/operating_system.py new file mode 100644 index 00000000..dd61aa7b --- /dev/null +++ b/app/itam/forms/device/operating_system.py @@ -0,0 +1,18 @@ +from django import forms +from django.db.models import Q + +from itam.models.device import DeviceOperatingSystem + + +class Update(forms.ModelForm): + + prefix = 'operating_system' + + class Meta: + model = DeviceOperatingSystem + fields = [ + "id", + "version", + 'operating_system_version', + ] + diff --git a/app/itam/forms/operating_system/__init__.py b/app/itam/forms/operating_system/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/itam/forms/operating_system/update.py b/app/itam/forms/operating_system/update.py new file mode 100644 index 00000000..3816deff --- /dev/null +++ b/app/itam/forms/operating_system/update.py @@ -0,0 +1,41 @@ +from app import settings +from django import forms +from django.db.models import Q + +from itam.models.operating_system import OperatingSystem + + +class Update(forms.ModelForm): + + class Meta: + model = OperatingSystem + fields = [ + "name", + 'slug', + 'id', + 'organization', + 'is_global', + ] + + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.fields['_created'] = forms.DateTimeField( + label="Created", + input_formats=settings.DATETIME_FORMAT, + initial=kwargs['instance'].created, + disabled=True + ) + + self.fields['_modified'] = forms.DateTimeField( + label="Modified", + input_formats=settings.DATETIME_FORMAT, + initial=kwargs['instance'].modified, + disabled=True + ) + + + if kwargs['instance'].is_global: + + self.fields['is_global'].widget.attrs['disabled'] = True diff --git a/app/itam/migrations/0004_operatingsystem_operatingsystemversion.py b/app/itam/migrations/0004_operatingsystem_operatingsystemversion.py new file mode 100644 index 00000000..5601aa97 --- /dev/null +++ b/app/itam/migrations/0004_operatingsystem_operatingsystemversion.py @@ -0,0 +1,47 @@ +# Generated by Django 5.0.6 on 2024-05-18 08:51 + +import access.fields +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0001_initial'), + ('itam', '0003_devicesoftware_version'), + ] + + operations = [ + migrations.CreateModel( + name='OperatingSystem', + fields=[ + ('is_global', models.BooleanField(default=False)), + ('id', models.AutoField(primary_key=True, serialize=False, unique=True)), + ('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False)), + ('modified', access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False)), + ('name', models.CharField(max_length=50, unique=True)), + ('slug', access.fields.AutoSlugField()), + ('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.organization')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='OperatingSystemVersion', + fields=[ + ('is_global', models.BooleanField(default=False)), + ('id', models.AutoField(primary_key=True, serialize=False, unique=True)), + ('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False)), + ('modified', access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False)), + ('name', models.CharField(max_length=50)), + ('operating_system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='itam.operatingsystem')), + ('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.organization')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/app/itam/migrations/0005_alter_operatingsystemversion_name_and_more.py b/app/itam/migrations/0005_alter_operatingsystemversion_name_and_more.py new file mode 100644 index 00000000..51d9c97e --- /dev/null +++ b/app/itam/migrations/0005_alter_operatingsystemversion_name_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.0.6 on 2024-05-18 15:20 + +import access.fields +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0001_initial'), + ('itam', '0004_operatingsystem_operatingsystemversion'), + ] + + operations = [ + migrations.AlterField( + model_name='operatingsystemversion', + name='name', + field=models.CharField(max_length=50, verbose_name='Major Version'), + ), + migrations.CreateModel( + name='DeviceOperatingSystem', + fields=[ + ('is_global', models.BooleanField(default=False)), + ('id', models.AutoField(primary_key=True, serialize=False, unique=True)), + ('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False)), + ('modified', access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False)), + ('version', models.CharField(max_length=15, verbose_name='Installed Version')), + ('device', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='itam.device')), + ('operating_system_version', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='itam.operatingsystemversion', verbose_name='Operating System/Version')), + ('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.organization')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/app/itam/models/device.py b/app/itam/models/device.py index e4d3235a..43bdf06d 100644 --- a/app/itam/models/device.py +++ b/app/itam/models/device.py @@ -3,7 +3,7 @@ from django.db import models from access.fields import * from access.models import TenancyObject from itam.models.software import Software, SoftwareVersion - +from itam.models.operating_system import OperatingSystemVersion class DeviceCommonFields(TenancyObject, models.Model): @@ -98,9 +98,6 @@ class Device(DeviceCommonFieldsName): state = 'absent' - print(f"here: {software.version}") - - software_action = { "name": software.software.slug, "state": state @@ -157,3 +154,33 @@ class DeviceSoftware(DeviceCommonFields): blank= True ) + + + +class DeviceOperatingSystem(DeviceCommonFields): + + device = models.ForeignKey( + Device, + on_delete = models.CASCADE, + default = None, + null = False, + blank = False, + + ) + + operating_system_version = models.ForeignKey( + OperatingSystemVersion, + verbose_name = 'Operating System/Version', + on_delete = models.CASCADE, + default = None, + null = False, + blank = False + + ) + + version = models.CharField( + verbose_name = 'Installed Version', + max_length = 15, + null = False, + blank = False, + ) diff --git a/app/itam/models/operating_system.py b/app/itam/models/operating_system.py new file mode 100644 index 00000000..63b8b992 --- /dev/null +++ b/app/itam/models/operating_system.py @@ -0,0 +1,64 @@ +from django.db import models + +from access.fields import * +from access.models import TenancyObject + + + +class OperatingSystemCommonFields(TenancyObject, models.Model): + + class Meta: + abstract = True + + id = models.AutoField( + primary_key=True, + unique=True, + blank=False + ) + + created = AutoCreatedField() + + modified = AutoLastModifiedField() + + + +class OperatingSystemFieldsName(OperatingSystemCommonFields): + + class Meta: + abstract = True + + name = models.CharField( + blank = False, + max_length = 50, + unique = True, + ) + + slug = AutoSlugField() + + + +class OperatingSystem(OperatingSystemFieldsName): + + def __str__(self): + + return self.name + + +class OperatingSystemVersion(OperatingSystemCommonFields): + + operating_system = models.ForeignKey( + OperatingSystem, + on_delete=models.CASCADE, + ) + + name = models.CharField( + verbose_name = 'Major Version', + blank = False, + max_length = 50, + unique = False, + ) + + def __str__(self): + + return self.operating_system.name + ' ' + self.name + diff --git a/app/itam/templates/itam/device.html.j2 b/app/itam/templates/itam/device.html.j2 index a6187753..384cbf15 100644 --- a/app/itam/templates/itam/device.html.j2 +++ b/app/itam/templates/itam/device.html.j2 @@ -30,78 +30,80 @@
- - - - - - + + + + + +
+
+ {% csrf_token %} - -
-

Details

- - {% csrf_token %} - {{ form }} - - - +
+

Details

+ {{ form.as_p }} + + -
- -
-

Operating System

-
- -
-

Software

- - - - - - - - - - - {% if softwares %} - {% for software in softwares %} - - - - - - - - {% endfor %} - {% else %} - - {% endif %} -
NameActionVersionInstalled 
{{ software.software }}{{ software.get_action_display }} - {% if software.version %} - {{ software.version }} - {% else %} - Any - {% endif %} - - {% include 'icons/issue_link.html.j2' with issue=2 %} -  
Nothing Found {% include 'icons/issue_link.html.j2' with issue=2 %}
-
- -
-

Configuration Management

-
-
-
+
+

Operating System

+ {{ operating_system.as_p }} + +
+ +
+

Software

+ + + + + + + + + + + {% if softwares %} + {% for software in softwares %} + + + + + + + + {% endfor %} + {% else %} + + {% endif %} +
NameActionVersionInstalled 
{{ software.software }}{{ software.get_action_display }} + {% if software.version %} + {{ software.version }} + {% else %} + Any + {% endif %} + + {% include 'icons/issue_link.html.j2' with issue=2 %} +  
Nothing Found {% include 'icons/issue_link.html.j2' with issue=2 %}
+
+ +
+

Configuration Management

+
+ +
+
+ {% endblock %} \ No newline at end of file diff --git a/app/itam/templates/itam/operating_system.html.j2 b/app/itam/templates/itam/operating_system.html.j2 new file mode 100644 index 00000000..8341e831 --- /dev/null +++ b/app/itam/templates/itam/operating_system.html.j2 @@ -0,0 +1,131 @@ +{% extends 'base.html.j2' %} + +{% block title %}{{ operating_system.name }}{% endblock %} + +{% block body %} + + + +
+ + + + + +
+ +
+

Details

+
+ {% csrf_token %} + {{ form }} + +
+ + + +
+ +
+

Versions

+ + + + + + + + + + {% for version in operating_system_versions %} + + + + + + + {% endfor %} +
VersionInstallationsVulnerable 
{{ version.name }}{% if version.installs == 0%}-{% else %}{{ version.installs }}{% endif %} DELETE
+ +
+ +
+

Licences

+ {% include 'icons/issue_link.html.j2' with issue=4 %} + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAvailable 
GPL-3Open Source1 / 5 
MITOpen SourceUnlimited 
Windows DeviceCAL11 / 15 
+ +
+ +
+

Installations

+ + + + + + + + + {% for install in installs %} + + + + + + + + {% endfor %} +
DeviceOrganizationVersionInstalled 
{{ install.device }}{{ install.organization }}{{ install.version }}{% include 'icons/issue_link.html.j2' with issue=2 %} 
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/itam/templates/itam/operating_system_index.html.j2 b/app/itam/templates/itam/operating_system_index.html.j2 new file mode 100644 index 00000000..a44d2016 --- /dev/null +++ b/app/itam/templates/itam/operating_system_index.html.j2 @@ -0,0 +1,47 @@ +{% extends 'base.html.j2' %} + +{% block title %}Operating Systems{% endblock %} +{% block content_header_icon %}{% endblock %} + +{% block body %} + + + + + + + + + + + {% for operating_system in operating_systems %} + + + + + + + + {% endfor %} + +
NameCreatedModifiedOrganization 
{{ operating_system.name }}{{ operating_system.created }}{{ operating_system.modified }}{% if operating_system.is_global %}Global{% else %}{{ operating_system.organization }}{% endif %}Delete
+ + + +{% endblock %} \ No newline at end of file diff --git a/app/itam/templates/itam/software.html.j2 b/app/itam/templates/itam/software.html.j2 index 4edf5cd0..b15a3f20 100644 --- a/app/itam/templates/itam/software.html.j2 +++ b/app/itam/templates/itam/software.html.j2 @@ -66,14 +66,14 @@ Vulnerable   + {% for version in software_versions %} - {% for version in software_versions %} {{ version.name }} {% include 'icons/issue_link.html.j2' with issue=2 %} {% include 'icons/issue_link.html.j2' with issue=3 %}   - {% endfor %} + {% endfor %}
@@ -110,7 +110,7 @@

Installations

- +
diff --git a/app/itam/tests/test_devices.py b/app/itam/tests/test_devices.py index bdbf107a..112897e2 100644 --- a/app/itam/tests/test_devices.py +++ b/app/itam/tests/test_devices.py @@ -21,6 +21,7 @@ def test_device_software_action(user): """ pass + @pytest.mark.skip(reason="to be written") def test_device_not_global(user): """Devices are not global items. @@ -28,3 +29,10 @@ def test_device_not_global(user): Ensure that a device can't be set to be global. """ pass + + +@pytest.mark.skip(reason="to be written") +def test_device_operating_system_version_only_one(user): + """model deviceoperatingsystem must only contain one value per device + """ + pass diff --git a/app/itam/tests/test_operating_system.py b/app/itam/tests/test_operating_system.py new file mode 100644 index 00000000..ceb96e91 --- /dev/null +++ b/app/itam/tests/test_operating_system.py @@ -0,0 +1,41 @@ +# from django.conf import settings +# from django.shortcuts import reverse +from django.test import TestCase, Client + +import pytest +import unittest +import requests + +# from django.contrib.auth import get_user_model +# from django.core.exceptions import ValidationError +# from access.models import Organization + +# class Test_app_structure_auth(unittest.TestCase): + +@pytest.mark.skip(reason="to be written") +def test_operating_system_update_is_global_no_change(user): + """Once operating_system is set to global it can't be changed. + + global status can't be changed as non-global items may reference the item. + """ + + pass + +@pytest.mark.skip(reason="to be written") +def test_operating_system_prevent_delete_if_used(user): + """Any operating_system in use by a device must not be deleted. + + i.e. A global os can't be deleted + """ + + pass + + +@pytest.mark.skip(reason="to be written") +def test_operating_system_version_installs_by_os_count(user): + """Operating System Versions has a count field that must be accurate + + The count is of model OperatingSystemVersion linked to model DeviceOperatingSystem + """ + + pass diff --git a/app/itam/urls.py b/app/itam/urls.py index 67f7ea8d..b12248df 100644 --- a/app/itam/urls.py +++ b/app/itam/urls.py @@ -1,7 +1,7 @@ from django.urls import path from . import views -from .views import device, device_type, software, software_category, software_version +from .views import device, device_type, software, software_category, software_version, operating_system, operating_system_version app_name = "ITAM" urlpatterns = [ @@ -11,12 +11,25 @@ urlpatterns = [ path("device//", device.View.as_view(), name="_device_view"), path("device//software/add", device.SoftwareAdd.as_view(), name="_device_software_add"), path("device//software/", device.SoftwareView.as_view(), name="_device_software_view"), - path("device//delete", device.Delete.as_view(), name="_device_delete"), path("device/add/", device.Add.as_view(), name="_device_add"), + path("device_type/add/", device_type.Add.as_view(), name="_device_type_add"), + + path("operating_system", operating_system.IndexView.as_view(), name="Operating Systems"), + path("operating_system/", operating_system.View.as_view(), name="_operating_system_view"), + path("operating_system/add", operating_system.Add.as_view(), name="_operating_system_add"), + path("operating_system/delete/", operating_system.Delete.as_view(), name="_operating_system_delete"), + + + path("operating_system//version/", operating_system_version.View.as_view(), name="_operating_system_version_view"), + path("operating_system//version/add", operating_system_version.Add.as_view(), name="_operating_system_version_add"), + path("operating_system//version//delete", operating_system_version.Delete.as_view(), name="_operating_system_version_delete"), + + + path("software/", software.IndexView.as_view(), name="Software"), path("software//", software.View.as_view(), name="_software_view"), path("software//delete", software.Delete.as_view(), name="_software_delete"), diff --git a/app/itam/views/device.py b/app/itam/views/device.py index 9f72f2c5..0a6146dd 100644 --- a/app/itam/views/device.py +++ b/app/itam/views/device.py @@ -7,10 +7,13 @@ from django.views import generic from access.mixin import OrganizationPermission from access.models import Organization -from ..models.device import Device, DeviceSoftware +from ..models.device import Device, DeviceSoftware, DeviceOperatingSystem from itam.forms.device_softwareadd import SoftwareAdd from itam.forms.device_softwareupdate import SoftwareUpdate +from itam.forms.device.device import DeviceForm +from itam.forms.device.operating_system import Update as OperatingSystemForm + class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListView): model = Device @@ -32,37 +35,80 @@ class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListVie +def _get_form(request, formcls, prefix, **kwargs): + data = request.POST if prefix in request.POST else None + return formcls(data, prefix=prefix, **kwargs) + class View(OrganizationPermission, generic.UpdateView): + model = Device + permission_required = [ 'itam.view_device' ] + template_name = 'itam/device.html.j2' - fields = [ - 'id', - 'name', - 'serial_number', - 'uuid', - 'device_type', - ] + form_class = DeviceForm context_object_name = "device" + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - softwares = DeviceSoftware.objects.filter(device=self.kwargs['pk']) + try: + operating_system_version = DeviceOperatingSystem.objects.get(device=self.kwargs['pk']) + + except DeviceOperatingSystem.DoesNotExist: - context['content_title'] = self.object.name + operating_system_version = None + + if operating_system_version: + + context['operating_system'] = OperatingSystemForm(prefix='operating_system', instance=operating_system_version) + + else: + + context['operating_system'] = OperatingSystemForm(prefix='operating_system') + + + softwares = DeviceSoftware.objects.filter(device=self.kwargs['pk']) context['softwares'] = softwares config = self.object.get_configuration(self.kwargs['pk']) context['config'] = json.dumps(config, indent=4, sort_keys=True) + context['content_title'] = self.object.name + return context + + def post(self, request, *args, **kwargs): + + device = Device.objects.get(pk=self.kwargs['pk']) + + try: + + existing_os = DeviceOperatingSystem.objects.get(device=self.kwargs['pk']) + + except DeviceOperatingSystem.DoesNotExist: + + existing_os = None + + operating_system = OperatingSystemForm(request.POST, prefix='operating_system', instance=existing_os) + + if operating_system.is_bound and operating_system.is_valid(): + + operating_system.instance.organization = device.organization + operating_system.instance.device = device + + operating_system.save() + + return super().post(request, *args, **kwargs) + + def get_success_url(self, **kwargs): return f"/itam/device/{self.kwargs['pk']}/" diff --git a/app/itam/views/operating_system.py b/app/itam/views/operating_system.py new file mode 100644 index 00000000..1aeaa2f8 --- /dev/null +++ b/app/itam/views/operating_system.py @@ -0,0 +1,112 @@ +from django.contrib.auth.mixins import PermissionRequiredMixin +from django.db.models import Q, Count +from django.urls import reverse +from django.views import generic + +from access.mixin import OrganizationPermission + +from itam.models.device import DeviceOperatingSystem +from itam.models.operating_system import OperatingSystem, OperatingSystemVersion +from itam.forms.operating_system.update import Update + + + +class IndexView(PermissionRequiredMixin, OrganizationPermission, generic.ListView): + model = OperatingSystem + permission_required = 'itam.view_operating_system' + template_name = 'itam/operating_system_index.html.j2' + context_object_name = "operating_systems" + paginate_by = 10 + + + def get_queryset(self): + + if self.request.user.is_superuser: + + return OperatingSystem.objects.filter().order_by('name') + + else: + + return OperatingSystem.objects.filter(Q(organization__in=self.user_organizations()) | Q(is_global = True)).order_by('name') + + + +class View(OrganizationPermission, generic.UpdateView): + model = OperatingSystem + permission_required = [ + 'itam.view_operating_system' + ] + template_name = 'itam/operating_system.html.j2' + + form_class = Update + + context_object_name = "operating_system" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + operating_system_versions = OperatingSystemVersion.objects.filter(operating_system=self.kwargs['pk']).order_by('name').annotate(installs=Count("deviceoperatingsystem")) + context['operating_system_versions'] = operating_system_versions + + installs = DeviceOperatingSystem.objects.filter(operating_system_version__operating_system_id=self.kwargs['pk']) + context['installs'] = installs + + context['content_title'] = self.object.name + + return context + + def get_success_url(self, **kwargs): + + return reverse('ITAM:_operating_system_view', args=(self.kwargs['pk'],)) + + + +class Add(PermissionRequiredMixin, OrganizationPermission, generic.CreateView): + model = OperatingSystem + permission_required = [ + 'access.add_operating_system', + ] + template_name = 'form.html.j2' + fields = [ + 'name', + 'organization', + 'is_global' + ] + + + def get_success_url(self, **kwargs): + + return reverse('ITAM:Operating Systems') + + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['content_title'] = 'Add Operating System' + + return context + + + +class Delete(PermissionRequiredMixin, OrganizationPermission, generic.DeleteView): + + model = OperatingSystem + + permission_required = [ + 'access.delete_operating_system', + ] + + template_name = 'form.html.j2' + + + def get_success_url(self, **kwargs): + + return reverse('ITAM:Operating Systems') + + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['content_title'] = 'Delete ' + self.object.name + + return context diff --git a/app/itam/views/operating_system_version.py b/app/itam/views/operating_system_version.py new file mode 100644 index 00000000..be11fb3b --- /dev/null +++ b/app/itam/views/operating_system_version.py @@ -0,0 +1,88 @@ +from django.contrib.auth.mixins import PermissionRequiredMixin +from django.urls import reverse +from django.views import generic + +from access.mixin import OrganizationPermission + +from ..models.operating_system import OperatingSystem, OperatingSystemVersion + + + +class View(OrganizationPermission, generic.UpdateView): + model = OperatingSystemVersion + permission_required = [ + 'itam.view_operating_systemversion' + ] + template_name = 'form.html.j2' + + fields = [ + "name", + ] + + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['content_title'] = self.object.operating_system.name + ' ' + self.object.name + + return context + + + def get_success_url(self, **kwargs): + + return reverse('ITAM:_operating_system_view', args=(self.kwargs['operating_system_id'],)) + + + +class Add(PermissionRequiredMixin, OrganizationPermission, generic.CreateView): + model = OperatingSystemVersion + permission_required = [ + 'access.add_operating_systemversion', + ] + template_name = 'form.html.j2' + fields = [ + 'name' + ] + + def form_valid(self, form): + operating_system = OperatingSystem.objects.get(pk=self.kwargs['pk']) + + form.instance.is_global = operating_system.is_global + form.instance.organization_id = operating_system.organization.id + form.instance.operating_system_id = self.kwargs['pk'] + return super().form_valid(form) + + + def get_success_url(self, **kwargs): + + return reverse('ITAM:_operating_system_view', args=(self.kwargs['pk'],)) + + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['content_title'] = 'Add Operating System Version' + + return context + + + +class Delete(PermissionRequiredMixin, OrganizationPermission, generic.DeleteView): + model = OperatingSystemVersion + permission_required = [ + 'access.delete_operating_system', + ] + template_name = 'form.html.j2' + + + def get_success_url(self, **kwargs): + + return reverse('ITAM:_operating_system_view', args=(self.kwargs['operating_system_id'],)) + + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['content_title'] = 'Delete ' + self.object.name + + return context
Device Organization