diff options
author | Matthew Lemon <matt@matthewlemon.com> | 2020-09-02 12:04:19 +0100 |
---|---|---|
committer | Matthew Lemon <matt@matthewlemon.com> | 2020-09-02 12:04:19 +0100 |
commit | edd91cb77191b386af95dfaca0b2706c7ee143b9 (patch) | |
tree | b94edf8e069911d0aea4e1acfc23a72a180cb2cf /ctrack/caf | |
parent | 15c89a78c097dc00ad7b8ca3314581ed3b058187 (diff) | |
parent | c406d3da83d20d65c2fc4da7d5d4d5db0f6ad115 (diff) |
Merge branch 'db_rewrite' into master
Diffstat (limited to 'ctrack/caf')
-rw-r--r-- | ctrack/caf/admin.py | 47 | ||||
-rw-r--r-- | ctrack/caf/forms.py | 38 | ||||
-rw-r--r-- | ctrack/caf/managers.py | 12 | ||||
-rw-r--r-- | ctrack/caf/migrations/0001_initial.py | 66 | ||||
-rw-r--r-- | ctrack/caf/migrations/0002_auto_20200403_1407.py | 58 | ||||
-rw-r--r-- | ctrack/caf/migrations/0002_caf_systems.py | 18 | ||||
-rw-r--r-- | ctrack/caf/migrations/0003_auto_20200424_1924.py | 18 | ||||
-rw-r--r-- | ctrack/caf/migrations/0004_auto_20200813_0953.py | 31 | ||||
-rw-r--r-- | ctrack/caf/migrations/0005_applicablesystem_oes_categorisation.py | 18 | ||||
-rw-r--r-- | ctrack/caf/migrations/0006_auto_20200813_1125.py | 22 | ||||
-rw-r--r-- | ctrack/caf/migrations/0007_auto_20200814_1230.py | 23 | ||||
-rw-r--r-- | ctrack/caf/migrations/0008_auto_20200814_1318.py | 23 | ||||
-rw-r--r-- | ctrack/caf/models.py | 66 | ||||
-rw-r--r-- | ctrack/caf/templates/caf/applicablesystem_detail.html | 39 | ||||
-rw-r--r-- | ctrack/caf/templates/caf/caf_detail.html | 2 | ||||
-rw-r--r-- | ctrack/caf/tests/factories.py | 3 | ||||
-rw-r--r-- | ctrack/caf/views.py | 16 |
17 files changed, 196 insertions, 304 deletions
diff --git a/ctrack/caf/admin.py b/ctrack/caf/admin.py index f19e8f4..5513781 100644 --- a/ctrack/caf/admin.py +++ b/ctrack/caf/admin.py @@ -1,31 +1,56 @@ from django.contrib import admin -from .models import CAF, FileStore, DocumentFile, Grading, ApplicableSystem +from .models import ( + CAF, + FileStore, + DocumentFile, + Grading, + ApplicableSystem, + EssentialService, +) + + +def get_system_org(obj): + es = obj.essentialservice_set.first() # just get the first if there are many + return es.organisation.name + + +get_system_org.short_description = "Organisation" + + +class EssentialServiceAdmin(admin.ModelAdmin): + model = EssentialService class ApplicableSystemListAdmin(admin.ModelAdmin): model = ApplicableSystem - list_display = ["name", "organisation", "caf"] + list_display = ["name", get_system_org, "function"] -class ApplicableSystemAdmin(admin.StackedInline): - model = ApplicableSystem - max_num = 3 - extra = 1 +# FIXME +# class ApplicableSystemAdmin(admin.StackedInline): +# model = ApplicableSystem +# max_num = 3 +# extra = 1 -def get_caf_name(obj): - ass = ApplicableSystem.objects.filter(caf=obj).first() - return f"{ass.organisation.name}_v{obj.version}" +# FIXME - NOT NEEDED +# def get_caf_name(obj): +# ass = ApplicableSystem.objects.filter(caf=obj).first() +# return f"{ass.organisation.name}_v{obj.version}" +# FIXME class CAFAdmin(admin.ModelAdmin): model = CAF - inlines = [ApplicableSystemAdmin] - list_display = [get_caf_name, "quality_grading", "confidence_grading", "file"] + # inlines = [ApplicableSystemAdmin] + + +# list_display = ["quality_grading", "confidence_grading", "file"] admin.site.register(CAF, CAFAdmin) +admin.site.register(EssentialService, EssentialServiceAdmin) admin.site.register(FileStore) admin.site.register(DocumentFile) admin.site.register(Grading) diff --git a/ctrack/caf/forms.py b/ctrack/caf/forms.py index 7367ccd..8e3d8ee 100644 --- a/ctrack/caf/forms.py +++ b/ctrack/caf/forms.py @@ -12,12 +12,13 @@ from django import forms from django.forms import inlineformset_factory from django.urls import reverse -from ctrack.caf.models import CAF, ApplicableSystem +from ctrack.caf.models import CAF, ApplicableSystem, EssentialService from ctrack.organisations.models import Organisation -CAFCreateInlineFormset = inlineformset_factory( - CAF, ApplicableSystem, fields=("name", "organisation"), extra=2 -) +# TODO - Replace this to get inlineformet working +# CAFCreateInlineFormset = inlineformset_factory( +# CAF, ApplicableSystem, fields=("name", "organisation"), extra=2 +# ) class ApplicableSystemCreateFromCafForm(forms.Form): @@ -77,13 +78,14 @@ class ApplicableSystemCreateFromCafForm(forms.Form): class ApplicableSystemCreateFromOrgForm(forms.Form): name = forms.CharField(max_length=255) function = forms.CharField(widget=forms.Textarea) - organisation = forms.ModelChoiceField(queryset=Organisation.objects.all()) - caf = forms.ModelChoiceField(queryset=CAF.objects.all()) - essential_service = forms.CharField( - widget=forms.Textarea, - max_length=255, - help_text="Description of the essential service which the system suppports.", - ) + # organisation = forms.ModelChoiceField(queryset=Organisation.objects.all()) + # caf = forms.ModelChoiceField(queryset=CAF.objects.all()) + # essential_service = forms.CharField( + # widget=forms.Textarea, + # max_length=255, + # help_text="Description of the essential service which the system suppports.", + # ) + essential_service = forms.ModelChoiceField(queryset=EssentialService.objects.all()) dft_categorisation = forms.ChoiceField( choices=ApplicableSystem.SYSTEM_CATEGORISATION, help_text="Refer to documentation for description of these criteria", @@ -93,16 +95,19 @@ class ApplicableSystemCreateFromOrgForm(forms.Form): help_text="Categorisation based on OES' own internal prioritisation process.", ) - def __init__(self, org_id, slug, org_name, org_cafs, *args, **kwargs): + def __init__(self, org_id, slug, org_name, *args, **kwargs): super().__init__(*args, **kwargs) cancel_redirect = reverse("organisations:detail", args=[slug]) # we need to create the choices we can use for the CAF dropdown in the form - self.fields["caf"].queryset = CAF.objects.filter( - pk__in=[caf.pk for caf in org_cafs] - ) - self.fields["caf"].label = "CAF" + # self.fields["caf"].queryset = CAF.objects.filter( + # pk__in=[caf.pk for caf in org_cafs] + # ) + # self.fields["caf"].label = "CAF" self.fields["dft_categorisation"].label = "DfT Categorisation" self.fields["oes_categorisation"].label = "OES Categorisation" + self.fields["essential_service"].queryset = EssentialService.objects.filter( + pk=org_id + ) self.helper = FormHelper(self) self.helper.layout = Layout( Fieldset( @@ -113,7 +118,6 @@ class ApplicableSystemCreateFromOrgForm(forms.Form): "dft_categorisation", "oes_categorisation", Hidden("organisation", org_id), - "caf", ), ButtonHolder( Submit("submit", "Submit", css_class="btn-primary"), diff --git a/ctrack/caf/managers.py b/ctrack/caf/managers.py index cba8c83..4d8c134 100644 --- a/ctrack/caf/managers.py +++ b/ctrack/caf/managers.py @@ -1,8 +1,8 @@ from django.db import connection from django.db import models -import ctrack.caf.models # to deal with circular import -from ctrack.organisations.models import Organisation, Person +import ctrack.caf.models as caf_models # to deal with circular import +import ctrack.organisations.models as org_models class ApplicableSystemManager(models.Manager): @@ -16,14 +16,16 @@ class ApplicableSystemManager(models.Manager): Using Custom Managers Django docs for an example. """ with connection.cursor() as cursor: - cursor.execute(""" + cursor.execute( + """ SELECT a.id, a.name, o.id, c.id, sm.id, p.id, o.name FROM caf_applicablesystem a, organisations_organisation o, organisations_person p, caf_caf c, organisations_submode sm WHERE a.organisation_id = o.id AND a.caf_id = c.id AND p.organisation_id = o.id AND o.submode_id = sm.id AND p.primary_nis_contact = True; - """) + """ + ) result_list = [] for row in cursor.fetchall(): - org = Organisation.objects.get(pk=row[2]) + org = org_models.Organisation.objects.get(pk=row[3]) caf = ctrack.caf.models.CAF.objects.get(pk=row[3]) ass = self.model(id=row[0], name=row[1], organisation=org, caf=caf) ass.nis_contact = Person.objects.get(pk=row[5]) diff --git a/ctrack/caf/migrations/0001_initial.py b/ctrack/caf/migrations/0001_initial.py index 5e184df..ca65af6 100644 --- a/ctrack/caf/migrations/0001_initial.py +++ b/ctrack/caf/migrations/0001_initial.py @@ -1,6 +1,8 @@ -# Generated by Django 2.2.9 on 2020-04-03 14:07 +# Generated by Django 2.2.12 on 2020-08-27 09:40 +import ctrack.caf.models from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): @@ -8,6 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('organisations', '0001_initial'), ] operations = [ @@ -15,49 +18,68 @@ class Migration(migrations.Migration): name='ApplicableSystem', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256)), - ('description', models.TextField(max_length=1000)), + ('name', models.CharField(help_text='System name assigned by OES', max_length=256)), + ('function', models.TextField(blank=True, help_text='How the system is relevant to delivering or supporting the essential service', max_length=1000, null=True)), + ('dft_categorisation', models.CharField(choices=[('CR', 'Critical'), ('IM', 'Important (Legacy use only)')], default='CR', help_text='Refer to documentation for description of these criteria', max_length=2, verbose_name='DfT Categorisation')), + ('oes_categorisation', models.CharField(default='NA', help_text="Categorisation based on OES' own internal prioritisation process.", max_length=255, verbose_name='OES Categorisation')), ], options={ - 'verbose_name': 'Applicable System', + 'verbose_name': 'NIS System', }, ), migrations.CreateModel( - name='CAF', + name='Grading', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('version', models.CharField(blank=True, max_length=10, null=True)), - ('triage_review_date', models.DateField(blank=True, null=True)), - ('comments', models.TextField(max_length=1000)), + ('descriptor', models.CharField(help_text='Q1, C1, etc', max_length=2)), + ('description', models.TextField(max_length=250)), + ('type', models.CharField(choices=[('CONFIDENCE', 'Confidence'), ('QUALITY', 'Quality'), ('MISC', 'Misc')], help_text='Type of grading', max_length=20)), ], - options={ - 'verbose_name': 'CAF', - }, ), migrations.CreateModel( - name='DocumentFile', + name='FileStore', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('type', models.IntegerField(choices=[(1, 'Excel'), (2, 'Word'), (3, 'PDF'), (4, 'Hard Copy')], default=1)), + ('descriptor', models.CharField(max_length=100)), + ('virtual_location', models.CharField(help_text='USB, Rosa, email, etc', max_length=100)), + ('physical_location', models.CharField(blank=True, help_text='Cupboard, room, building, etc', max_length=100)), + ('physical_location_organisation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='organisations.Organisation')), ], ), migrations.CreateModel( - name='FileStore', + name='EssentialService', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('descriptor', models.CharField(max_length=100)), - ('virtual_location', models.CharField(help_text='USB, Rosa, email, etc', max_length=100)), - ('physical_location', models.CharField(blank=True, help_text='Cupboard, room, building, etc', max_length=100)), + ('name', models.CharField(max_length=256)), + ('description', models.CharField(max_length=512)), + ('organisation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='organisations.Organisation')), + ('systems', models.ManyToManyField(to='caf.ApplicableSystem')), ], ), migrations.CreateModel( - name='Grading', + name='DocumentFile', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('descriptor', models.CharField(help_text='Q1, C1, etc', max_length=2)), - ('description', models.TextField(max_length=250)), - ('type', models.CharField(choices=[('CONFIDENCE', 'Confidence'), ('QUALITY', 'Quality'), ('MISC', 'Misc')], help_text='Type of grading', max_length=20)), + ('name', models.CharField(max_length=255)), + ('type', models.IntegerField(choices=[(1, 'Excel'), (2, 'Word'), (3, 'PDF'), (4, 'Hard Copy')], default=1)), + ('file_store_location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='caf.FileStore')), ], ), + migrations.CreateModel( + name='CAF', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('version', models.CharField(blank=True, max_length=10, null=True)), + ('triage_review_date', models.DateField(blank=True, null=True)), + ('comments', models.TextField(max_length=1000)), + ('confidence_grading', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='confidence_grading', to='caf.Grading')), + ('file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='caf.DocumentFile')), + ('organisation', models.ForeignKey(on_delete=models.SET(ctrack.caf.models.CAF.get_sentinel_org), to='organisations.Organisation')), + ('quality_grading', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quality_grading', to='caf.Grading')), + ('triage_review_inspector', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='organisations.Person')), + ], + options={ + 'verbose_name': 'CAF', + }, + ), ] diff --git a/ctrack/caf/migrations/0002_auto_20200403_1407.py b/ctrack/caf/migrations/0002_auto_20200403_1407.py deleted file mode 100644 index e5963d5..0000000 --- a/ctrack/caf/migrations/0002_auto_20200403_1407.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 2.2.9 on 2020-04-03 14:07 - -import ctrack.caf.models -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('caf', '0001_initial'), - ('organisations', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='filestore', - name='physical_location_organisation', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='organisations.Organisation'), - ), - migrations.AddField( - model_name='documentfile', - name='file_store_location', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='caf.FileStore'), - ), - migrations.AddField( - model_name='caf', - name='confidence_grading', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='confidence_grading', to='caf.Grading'), - ), - migrations.AddField( - model_name='caf', - name='file', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='caf.DocumentFile'), - ), - migrations.AddField( - model_name='caf', - name='quality_grading', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quality_grading', to='caf.Grading'), - ), - migrations.AddField( - model_name='caf', - name='triage_review_inspector', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='organisations.Person'), - ), - migrations.AddField( - model_name='applicablesystem', - name='caf', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='applicable_systems', to='caf.CAF'), - ), - migrations.AddField( - model_name='applicablesystem', - name='organisation', - field=models.ForeignKey(on_delete=models.SET(ctrack.caf.models.ApplicableSystem.get_sentinel_org), to='organisations.Organisation'), - ), - ] diff --git a/ctrack/caf/migrations/0002_caf_systems.py b/ctrack/caf/migrations/0002_caf_systems.py new file mode 100644 index 0000000..9e0f76a --- /dev/null +++ b/ctrack/caf/migrations/0002_caf_systems.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.12 on 2020-08-27 12:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('caf', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='caf', + name='systems', + field=models.ManyToManyField(to='caf.ApplicableSystem'), + ), + ] diff --git a/ctrack/caf/migrations/0003_auto_20200424_1924.py b/ctrack/caf/migrations/0003_auto_20200424_1924.py deleted file mode 100644 index 34613c6..0000000 --- a/ctrack/caf/migrations/0003_auto_20200424_1924.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.9 on 2020-04-24 19:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('caf', '0002_auto_20200403_1407'), - ] - - operations = [ - migrations.AlterField( - model_name='applicablesystem', - name='description', - field=models.TextField(blank=True, max_length=1000, null=True), - ), - ] diff --git a/ctrack/caf/migrations/0004_auto_20200813_0953.py b/ctrack/caf/migrations/0004_auto_20200813_0953.py deleted file mode 100644 index ad1ca96..0000000 --- a/ctrack/caf/migrations/0004_auto_20200813_0953.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 2.2.12 on 2020-08-13 09:53 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('caf', '0003_auto_20200424_1924'), - ] - - operations = [ - migrations.AlterModelOptions( - name='applicablesystem', - options={'verbose_name': 'NIS System'}, - ), - migrations.RemoveField( - model_name='applicablesystem', - name='description', - ), - migrations.AddField( - model_name='applicablesystem', - name='function', - field=models.TextField(blank=True, help_text='How the system is relevant to delivering or supporting the essential service', max_length=1000, null=True), - ), - migrations.AlterField( - model_name='applicablesystem', - name='name', - field=models.CharField(help_text='System name assigned by OES', max_length=256), - ), - ] diff --git a/ctrack/caf/migrations/0005_applicablesystem_oes_categorisation.py b/ctrack/caf/migrations/0005_applicablesystem_oes_categorisation.py deleted file mode 100644 index dc8c928..0000000 --- a/ctrack/caf/migrations/0005_applicablesystem_oes_categorisation.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.12 on 2020-08-13 11:17 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('caf', '0004_auto_20200813_0953'), - ] - - operations = [ - migrations.AddField( - model_name='applicablesystem', - name='oes_categorisation', - field=models.CharField(choices=[('CR', 'Critical'), ('IM', 'Important')], default='CR', max_length=2), - ), - ] diff --git a/ctrack/caf/migrations/0006_auto_20200813_1125.py b/ctrack/caf/migrations/0006_auto_20200813_1125.py deleted file mode 100644 index 1e97dff..0000000 --- a/ctrack/caf/migrations/0006_auto_20200813_1125.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.2.12 on 2020-08-13 11:25 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('caf', '0005_applicablesystem_oes_categorisation'), - ] - - operations = [ - migrations.RemoveField( - model_name='applicablesystem', - name='oes_categorisation', - ), - migrations.AddField( - model_name='applicablesystem', - name='dft_categorisation', - field=models.CharField(choices=[('CR', 'Critical'), ('IM', 'Important')], default='CR', help_text='Refer to documentation for description of these criteria', max_length=2, verbose_name='DfT Categorisation'), - ), - ] diff --git a/ctrack/caf/migrations/0007_auto_20200814_1230.py b/ctrack/caf/migrations/0007_auto_20200814_1230.py deleted file mode 100644 index 68a12bd..0000000 --- a/ctrack/caf/migrations/0007_auto_20200814_1230.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2.12 on 2020-08-14 12:30 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('caf', '0006_auto_20200813_1125'), - ] - - operations = [ - migrations.AddField( - model_name='applicablesystem', - name='oes_categorisation', - field=models.CharField(default='', help_text="Categorisation based on OES' own internal prioritisation process.", max_length=255, verbose_name='OES Categorisation'), - ), - migrations.AlterField( - model_name='applicablesystem', - name='dft_categorisation', - field=models.CharField(choices=[('CR', 'Critical'), ('IM', 'Important (Legacy use only)')], default='CR', help_text='Refer to documentation for description of these criteria', max_length=2, verbose_name='DfT Categorisation'), - ), - ] diff --git a/ctrack/caf/migrations/0008_auto_20200814_1318.py b/ctrack/caf/migrations/0008_auto_20200814_1318.py deleted file mode 100644 index 90f188f..0000000 --- a/ctrack/caf/migrations/0008_auto_20200814_1318.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2.12 on 2020-08-14 13:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('caf', '0007_auto_20200814_1230'), - ] - - operations = [ - migrations.AddField( - model_name='applicablesystem', - name='essential_service', - field=models.CharField(default='NA', help_text='Name of the essential service which the system suppports.', max_length=255, verbose_name='Essential Service'), - ), - migrations.AlterField( - model_name='applicablesystem', - name='oes_categorisation', - field=models.CharField(default='NA', help_text="Categorisation based on OES' own internal prioritisation process.", max_length=255, verbose_name='OES Categorisation'), - ), - ] diff --git a/ctrack/caf/models.py b/ctrack/caf/models.py index 27220bc..5fd586f 100644 --- a/ctrack/caf/models.py +++ b/ctrack/caf/models.py @@ -45,13 +45,6 @@ class DocumentFile(models.Model): class ApplicableSystem(models.Model): - CRITICAL = "CR" - IMPORTANT = "IM" - SYSTEM_CATEGORISATION = ( - (CRITICAL, "Critical"), - (IMPORTANT, "Important (Legacy use only)"), - ) - def get_sentinel_org(): """ We need this so that we can ensure models.SET() is applied with a callable @@ -60,6 +53,13 @@ class ApplicableSystem(models.Model): """ return Organisation.objects.get_or_create(name="DELETED ORGANISATION")[0] + CRITICAL = "CR" + IMPORTANT = "IM" + SYSTEM_CATEGORISATION = ( + (CRITICAL, "Critical"), + (IMPORTANT, "Important (Legacy use only)"), + ) + name = models.CharField(max_length=256, help_text="System name assigned by OES") function = models.TextField( max_length=1000, @@ -68,22 +68,6 @@ class ApplicableSystem(models.Model): help_text="How the system is relevant to delivering or supporting the " "essential service", ) - organisation = models.ForeignKey( - Organisation, on_delete=models.SET(get_sentinel_org) - ) - caf = models.ForeignKey( - "CAF", - on_delete=models.CASCADE, - blank=True, - null=True, - related_name="applicable_systems", - ) - essential_service = models.CharField( - max_length=255, - default="NA", - verbose_name="Essential Service", - help_text="Description of the essential service which the system suppports.", - ) dft_categorisation = models.CharField( max_length=2, choices=SYSTEM_CATEGORISATION, @@ -105,12 +89,20 @@ class ApplicableSystem(models.Model): return self.organisation.person_set.filter(primary_nis_contact=True) def __str__(self): - return f"{self.organisation.name} | {self.name}" + return self.name objects = ApplicableSystemManager() class CAF(models.Model): + def get_sentinel_org(): + """ + We need this so that we can ensure models.SET() is applied with a callable + to handle when Users are deleted from the system, preventing the Organisation + objects related to them being deleted also. + """ + return Organisation.objects.get_or_create(name="DELETED ORGANISATION")[0] + quality_grading = models.ForeignKey( Grading, on_delete=models.CASCADE, @@ -129,10 +121,14 @@ class CAF(models.Model): DocumentFile, on_delete=models.CASCADE, blank=True, null=True ) version = models.CharField(max_length=10, blank=True, null=True) + organisation = models.ForeignKey( + Organisation, on_delete=models.SET(get_sentinel_org) + ) triage_review_date = models.DateField(blank=True, null=True) triage_review_inspector = models.ForeignKey( Person, on_delete=models.CASCADE, blank=True, null=True ) + systems = models.ManyToManyField(ApplicableSystem) comments = models.TextField(max_length=1000) class Meta: @@ -147,14 +143,24 @@ class CAF(models.Model): """ return ApplicableSystem.objects.filter(caf=self) - def organisation(self): - first_ass = ApplicableSystem.objects.filter(caf=self).first() - return first_ass.organisation + # FIXME remove once we know we don't need it + # def organisation(self): + # first_ass = ApplicableSystem.objects.filter(caf=self).first() + # return first_ass.organisation def sub_mode(self): - return self.organisation().submode + return self.organisation.submode def __str__(self): # Get the organisation and applicable system - ass = ApplicableSystem.objects.filter(caf=self).first() - return f"CAF | {ass.organisation.name}_v{self.version}" + return f"CAF | {self.organisation.name}_v{self.version}" + + +class EssentialService(models.Model): + name = models.CharField(max_length=256) + description = models.CharField(max_length=512) + organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE) + systems = models.ManyToManyField(ApplicableSystem) + + def __str__(self): + return self.name diff --git a/ctrack/caf/templates/caf/applicablesystem_detail.html b/ctrack/caf/templates/caf/applicablesystem_detail.html index 9e12043..b8467b0 100644 --- a/ctrack/caf/templates/caf/applicablesystem_detail.html +++ b/ctrack/caf/templates/caf/applicablesystem_detail.html @@ -5,24 +5,31 @@ {% block title %}{{ object.name }}{% endblock %} {% block content %} - <div class="container mt-3"> - <div class="row"> - <div class="col-sm-12 pl-0 my-2"> + <div class="container mt-3"> <div class="row"> - <h4>{{ object.name }}</h4> + <div class="col-sm-12 pl-0 my-2"> + <div class="row"> + <h4>{{ object.name }}</h4> + </div> + <div class="row"> + <h5>{{ object.caf.organisation }}</h5> + </div> + <div class="row"> + <h5>Function</h5> + </div> + <div class="row"> + <p>{{ object.function }}</p> + <p>Supports Essential Services:</p> + </div> + <div class="row"> + <ul> + {% for s in object.essentialservice_set.all %} + <li>{{ s.name }}</li> + {% endfor %} + </ul> + </div> + </div> </div> - <div class="row"> - <h5>{{ object.caf.organisation }}</h5> - </div> - <div class="row"> - <h6>Function</h6> - </div> - <div class="row"> - <p>{{ object.function }}</p> - <p>Contained within CAF: <a href="{% url "caf:detail" object.caf.pk %}">{{ object.caf }}</a></p> - </div> - </div> </div> - </div> {% endblock %} diff --git a/ctrack/caf/templates/caf/caf_detail.html b/ctrack/caf/templates/caf/caf_detail.html index fc2fcfd..fdd939e 100644 --- a/ctrack/caf/templates/caf/caf_detail.html +++ b/ctrack/caf/templates/caf/caf_detail.html @@ -72,7 +72,7 @@ <tr> <td><a href="{% url "caf:ass_detail" system.id %}">{{ system.name }}</a></td> <td>{{ system.function }}<br> - <a href="{% url "caf:detail" system.caf.pk %}" class="small"> + <a href="{% url "caf:detail" system.pk %}" class="small"> {{ system.caf }} </a> <span class="text-muted"> | <a href="#" class="small">Edit System</a></span> </td> diff --git a/ctrack/caf/tests/factories.py b/ctrack/caf/tests/factories.py index 3c62307..7aaf716 100644 --- a/ctrack/caf/tests/factories.py +++ b/ctrack/caf/tests/factories.py @@ -10,6 +10,7 @@ from ctrack.organisations.tests.factories import OrganisationFactory, PersonFact class CAFFactory(factory.DjangoModelFactory): quality_grading = factory.SubFactory("ctrack.caf.tests.factories.GradingFactory") confidence_grading = factory.SubFactory("ctrack.caf.tests.factories.GradingFactory") + organisation = factory.SubFactory("ctrack.organisations.tests.OrganisationFactory") file = None version = Faker("bothify", text="??##", letters="ABCD") triage_review_date = Faker("date_object") @@ -29,8 +30,6 @@ class ApplicableSystemFactory(factory.DjangoModelFactory): function = Faker( "paragraph", nb_sentences=4, variable_nb_sentences=True, ext_word_list=None ) - organisation = factory.SubFactory(OrganisationFactory) - caf = factory.SubFactory("ctrack.caf.tests.factories.CAFFactory") dft_categorisation = "CR" class Meta: diff --git a/ctrack/caf/views.py b/ctrack/caf/views.py index 258774e..480e305 100644 --- a/ctrack/caf/views.py +++ b/ctrack/caf/views.py @@ -36,8 +36,8 @@ def caf_detail_view(request, pk): context = { "object": caf, "assessments_and_scores": _scrs, - "organisation": ApplicableSystem.objects.filter(caf=caf).first().organisation, - "systems": caf.applicable_systems.all(), + "organisation": caf.organisation, + "systems": caf.systems.all(), } return render(request, "caf/caf_detail.html", context) @@ -107,20 +107,22 @@ class ApplicableSystemCreateFromOrg( ass = ApplicableSystem.objects.create( name=form.cleaned_data["name"], function=form.cleaned_data["function"], - organisation=form.cleaned_data["organisation"], - caf=form.cleaned_data["caf"], + # organisation=form.cleaned_data["organisation"], + # caf=form.cleaned_data["caf"], ) + es = form.cleaned_data["essential_service"] + es.systems.add(ass) return super().form_valid(form) def get_form_kwargs(self): kwargs = super().get_form_kwargs() org = Organisation.objects.get(slug=self.kwargs["slug"]) - asses = org.applicablesystem_set.all() - org_cafs = {ass.caf for ass in asses} + asses = org.applicable_systems() + # org_cafs = org.caf_set.all() kwargs["org_id"] = org.id kwargs["slug"] = org.slug kwargs["org_name"] = org.name - kwargs["org_cafs"] = list(org_cafs) + # kwargs["org_cafs"] = list(org_cafs) return kwargs def get_success_url(self): |