diff --git a/app/core/views/history.py b/app/core/views/history.py index b983a7036..5f24a009d 100644 --- a/app/core/views/history.py +++ b/app/core/views/history.py @@ -53,6 +53,12 @@ def get_object(self): self.model = Cluster + case 'clustertype': + + from itim.models.clusters import ClusterType + + self.model = ClusterType + case 'configgroups': self.model = ConfigGroups diff --git a/app/itim/forms/cluster_type.py b/app/itim/forms/cluster_type.py new file mode 100644 index 000000000..7bf7ba759 --- /dev/null +++ b/app/itim/forms/cluster_type.py @@ -0,0 +1,84 @@ +from django import forms +from django.forms import ValidationError +from django.urls import reverse + +from itim.models.clusters import ClusterType + +from app import settings + +from core.forms.common import CommonModelForm + + + +class ClusterTypeForm(CommonModelForm): + + + class Meta: + + fields = '__all__' + + model = ClusterType + + prefix = 'cluster_type' + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + + +class DetailForm(ClusterTypeForm): + + + tabs: dict = { + "details": { + "name": "Details", + "slug": "details", + "sections": [ + { + "layout": "double", + "left": [ + 'name', + 'organization', + 'c_created', + 'c_modified' + ], + "right": [ + 'model_notes', + ] + }, + ] + }, + "notes": { + "name": "Notes", + "slug": "notes", + "sections": [] + } + } + + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + + self.fields['c_created'] = forms.DateTimeField( + label = 'Created', + input_formats=settings.DATETIME_FORMAT, + disabled = True, + initial = self.instance.created, + ) + + self.fields['c_modified'] = forms.DateTimeField( + label = 'Modified', + input_formats=settings.DATETIME_FORMAT, + disabled = True, + initial = self.instance.modified, + ) + + self.tabs['details'].update({ + "edit_url": reverse('Settings:_cluster_type_change', args=(self.instance.pk,)) + }) + + self.url_index_view = reverse('Settings:_cluster_types') + diff --git a/app/itim/migrations/0001_initial.py b/app/itim/migrations/0001_initial.py index d85e6bce4..71baeb9c1 100644 --- a/app/itim/migrations/0001_initial.py +++ b/app/itim/migrations/0001_initial.py @@ -29,8 +29,8 @@ class Migration(migrations.Migration): ('organization', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='access.organization', validators=[access.models.TenancyObject.validatate_organization_exists])), ], options={ - 'verbose_name': 'ClusterType', - 'verbose_name_plural': 'ClusterTypes', + 'verbose_name': 'Cluster Type', + 'verbose_name_plural': 'Cluster Types', 'ordering': ['name'], }, ), diff --git a/app/itim/migrations/0002_clustertype_created_clustertype_modified.py b/app/itim/migrations/0002_clustertype_created_clustertype_modified.py new file mode 100644 index 000000000..c55a2d113 --- /dev/null +++ b/app/itim/migrations/0002_clustertype_created_clustertype_modified.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.7 on 2024-08-18 03:57 + +import access.fields +import django.utils.timezone +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('itim', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='clustertype', + name='created', + field=access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False), + ), + migrations.AddField( + model_name='clustertype', + name='modified', + field=access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False), + ), + ] diff --git a/app/itim/models/clusters.py b/app/itim/models/clusters.py index 31010e7dc..d003157fb 100644 --- a/app/itim/models/clusters.py +++ b/app/itim/models/clusters.py @@ -18,9 +18,9 @@ class Meta: 'name', ] - verbose_name = "ClusterType" + verbose_name = "Cluster Type" - verbose_name_plural = "ClusterTypes" + verbose_name_plural = "Cluster Types" id = models.AutoField( @@ -39,6 +39,15 @@ class Meta: slug = AutoSlugField() + created = AutoCreatedField() + + modified = AutoLastModifiedField() + + + def __str__(self): + + return self.name + class Cluster(TenancyObject): diff --git a/app/itim/templates/itim/cluster_type.html.j2 b/app/itim/templates/itim/cluster_type.html.j2 new file mode 100644 index 000000000..ad99f6eb0 --- /dev/null +++ b/app/itim/templates/itim/cluster_type.html.j2 @@ -0,0 +1,22 @@ +{% extends 'detail.html.j2' %} + +{% load json %} +{% load markdown %} + + +{% block tabs %} + +
+ + {% include 'content/section.html.j2' with tab=form.tabs.details %} + +
+ + +
+ + {% include 'content/section.html.j2' with tab=form.tabs.notes %} + +
+ +{% endblock %} \ No newline at end of file diff --git a/app/itim/templates/itim/cluster_type_index.html.j2 b/app/itim/templates/itim/cluster_type_index.html.j2 new file mode 100644 index 000000000..cb8e38b21 --- /dev/null +++ b/app/itim/templates/itim/cluster_type_index.html.j2 @@ -0,0 +1,47 @@ +{% extends 'base.html.j2' %} + +{% block content %} + + + + + + + + + + {% if items %} + {% for item in items %} + + + + + + + {% endfor %} + {% else %} + + + + {% endif %} +
Title Organization 
{{ item.name }} {{ item.organization }} 
Nothing Found
+
+ + +{% endblock %} \ No newline at end of file diff --git a/app/itim/views/cluster_types.py b/app/itim/views/cluster_types.py new file mode 100644 index 000000000..55380d1e8 --- /dev/null +++ b/app/itim/views/cluster_types.py @@ -0,0 +1,185 @@ +from django.contrib.auth import decorators as auth_decorator +from django.urls import reverse +from django.utils.decorators import method_decorator + +from core.forms.comment import AddNoteForm +from core.models.notes import Notes +from core.views.common import AddView, ChangeView, DeleteView, IndexView + +from itim.forms.cluster_type import ClusterTypeForm, DetailForm +from itim.models.clusters import ClusterType + +from settings.models.user_settings import UserSettings + + + +class Add(AddView): + + form_class = ClusterTypeForm + + model = ClusterType + + permission_required = [ + 'itim.add_clustertype', + ] + + + def get_initial(self): + + initial: dict = { + 'organization': UserSettings.objects.get(user = self.request.user).default_organization + } + + if 'pk' in self.kwargs: + + if self.kwargs['pk']: + + initial.update({'parent': self.kwargs['pk']}) + + self.model.parent.field.hidden = True + + return initial + + + def get_success_url(self, **kwargs): + + return reverse('Settings:_cluster_type_types') + + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['content_title'] = 'New Cluster Type' + + return context + + + +class Change(ChangeView): + + form_class = ClusterTypeForm + + model = ClusterType + + permission_required = [ + 'itim.change_clustertype', + ] + + + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + context['content_title'] = str(self.object) + + return context + + + def get_success_url(self, **kwargs): + + return reverse('Settings:_cluster_type_view', args=(self.kwargs['pk'],)) + + + +class Delete(DeleteView): + + model = ClusterType + + permission_required = [ + 'itim.delete_clustertype', + ] + + + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + context['content_title'] = 'Delete ' + str(self.object) + + return context + + + def get_success_url(self, **kwargs): + + return reverse('Settings:_cluster_types') + + + +class Index(IndexView): + + context_object_name = "items" + + model = ClusterType + + paginate_by = 10 + + permission_required = [ + 'itim.view_clustertype' + ] + + template_name = 'itim/cluster_type_index.html.j2' + + + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + context['model_docs_path'] = self.model._meta.app_label + '/' + self.model._meta.model_name + + context['content_title'] = 'Cluster Types' + + return context + + + +class View(ChangeView): + + context_object_name = "item" + + form_class = DetailForm + + model = ClusterType + + permission_required = [ + 'itim.view_clustertype', + ] + + template_name = 'itim/cluster_type.html.j2' + + + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + context['notes_form'] = AddNoteForm(prefix='note') + context['notes'] = Notes.objects.filter(service=self.kwargs['pk']) + + context['model_pk'] = self.kwargs['pk'] + context['model_name'] = self.model._meta.model_name + + context['model_delete_url'] = reverse('Settings:_cluster_type_delete', args=(self.kwargs['pk'],)) + + + context['content_title'] = self.object.name + + return context + + + def post(self, request, *args, **kwargs): + + item = ClusterType.objects.get(pk=self.kwargs['pk']) + + notes = AddNoteForm(request.POST, prefix='note') + + if notes.is_bound and notes.is_valid() and notes.instance.note != '': + + notes.instance.service = item + + notes.instance.organization = item.organization + + notes.save() + + + def get_success_url(self, **kwargs): + + return reverse('Settings:_cluster_type_view', args=(self.kwargs['pk'],)) diff --git a/app/settings/templates/settings/home.html.j2 b/app/settings/templates/settings/home.html.j2 index f73089628..fda2e5afd 100644 --- a/app/settings/templates/settings/home.html.j2 +++ b/app/settings/templates/settings/home.html.j2 @@ -62,6 +62,7 @@ div#content article h3 {

ITIM

diff --git a/app/settings/urls.py b/app/settings/urls.py index 38fc2c3e0..7f2661314 100644 --- a/app/settings/urls.py +++ b/app/settings/urls.py @@ -8,24 +8,20 @@ from itam.views import device_type, device_model, software_category -from itim.views import ports +from itim.views import cluster_types, ports app_name = "Settings" urlpatterns = [ path("", home.View.as_view(), name="Settings"), - path("external_links", external_link.Index.as_view(), name="External Links"), - path("external_links/add", external_link.Add.as_view(), name="_external_link_add"), - path("external_links/", external_link.View.as_view(), name="_external_link_view"), - path("external_links//edit", external_link.Change.as_view(), name="_external_link_change"), - path("external_links//delete", external_link.Delete.as_view(), name="_external_link_delete"), - - path('application', app_settings.View.as_view(), name="_settings_application"), - - path("task_results", celery_log.Index.as_view(), name="_task_results"), - path("task_result/", celery_log.View.as_view(), name="_task_result_view"), + + path("cluster_types", cluster_types.Index.as_view(), name="_cluster_types"), + path("cluster_types/add", cluster_types.Add.as_view(), name="_cluster_type_add"), + path("cluster_types//edit", cluster_types.Change.as_view(), name="_cluster_type_change"), + path("cluster_types//delete", cluster_types.Delete.as_view(), name="_cluster_type_delete"), + path("cluster_types/", cluster_types.View.as_view(), name="_cluster_type_view"), path("device_models", device_models.Index.as_view(), name="_device_models"), path("device_model/", device_model.View.as_view(), name="_device_model_view"), @@ -39,18 +35,18 @@ path("device_type//delete", device_type.Delete.as_view(), name="_device_type_delete"), path("device_type//edit", device_type.Change.as_view(), name="_device_type_change"), + path("external_links", external_link.Index.as_view(), name="External Links"), + path("external_links/add", external_link.Add.as_view(), name="_external_link_add"), + path("external_links/", external_link.View.as_view(), name="_external_link_view"), + path("external_links//edit", external_link.Change.as_view(), name="_external_link_change"), + path("external_links//delete", external_link.Delete.as_view(), name="_external_link_delete"), + path("kb/category", knowledge_base_category.Index.as_view(), name="KB Categories"), path("kb/category/add", knowledge_base_category.Add.as_view(), name="_knowledge_base_category_add"), path("kb/category//edit", knowledge_base_category.Change.as_view(), name="_knowledge_base_category_change"), path("kb/category//delete", knowledge_base_category.Delete.as_view(), name="_knowledge_base_category_delete"), path("kb/category/", knowledge_base_category.View.as_view(), name="_knowledge_base_category_view"), - path("software_category", software_categories.Index.as_view(), name="_software_categories"), - path("software_category/", software_category.View.as_view(), name="_software_category_view"), - path("software_category/add/", software_category.Add.as_view(), name="_software_category_add"), - path("software_category//edit", software_category.Change.as_view(), name="_software_category_change"), - path("software_category//delete", software_category.Delete.as_view(), name="_software_category_delete"), - path("manufacturers", manufacturer.Index.as_view(), name="_manufacturers"), path("manufacturer/", manufacturer.View.as_view(), name="_manufacturer_view"), path("manufacturer/add/", manufacturer.Add.as_view(), name="_manufacturer_add"), @@ -63,4 +59,13 @@ path("port//delete", ports.Delete.as_view(), name="_port_delete"), path("port/", ports.View.as_view(), name="_port_view"), + path("software_category", software_categories.Index.as_view(), name="_software_categories"), + path("software_category/", software_category.View.as_view(), name="_software_category_view"), + path("software_category/add/", software_category.Add.as_view(), name="_software_category_add"), + path("software_category//edit", software_category.Change.as_view(), name="_software_category_change"), + path("software_category//delete", software_category.Delete.as_view(), name="_software_category_delete"), + + path("task_results", celery_log.Index.as_view(), name="_task_results"), + path("task_result/", celery_log.View.as_view(), name="_task_result_view"), + ]