From 26ae6bc96b0fe9129edb09d4513ecbebefb6504a Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Mon, 15 Nov 2021 17:19:06 +0100 Subject: [PATCH] Refactoring * splits intervention/models.py into subpackage --- intervention/models/__init__.py | 12 ++ .../{models.py => models/intervention.py} | 169 +----------------- intervention/models/legal.py | 46 +++++ intervention/models/responsibility.py | 53 ++++++ intervention/models/revocation.py | 87 +++++++++ 5 files changed, 207 insertions(+), 160 deletions(-) create mode 100644 intervention/models/__init__.py rename intervention/{models.py => models/intervention.py} (59%) create mode 100644 intervention/models/legal.py create mode 100644 intervention/models/responsibility.py create mode 100644 intervention/models/revocation.py diff --git a/intervention/models/__init__.py b/intervention/models/__init__.py new file mode 100644 index 00000000..97b96910 --- /dev/null +++ b/intervention/models/__init__.py @@ -0,0 +1,12 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 15.11.21 + +""" + +from .intervention import * +from .legal import * +from .revocation import * +from .responsibility import * diff --git a/intervention/models.py b/intervention/models/intervention.py similarity index 59% rename from intervention/models.py rename to intervention/models/intervention.py index d025cddd..9b69764e 100644 --- a/intervention/models.py +++ b/intervention/models/intervention.py @@ -2,174 +2,23 @@ Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de -Created on: 17.11.20 +Created on: 15.11.21 """ -import shutil - from django.contrib.auth.models import User -from django.contrib.gis.db import models -from django.db import transaction +from django.db import models, transaction from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ -from codelist.models import KonovaCode -from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_LAW_ID, \ - CODELIST_PROCESS_TYPE_ID from intervention.managers import InterventionManager +from intervention.models.legal import Legal +from intervention.models.responsibility import Responsibility +from intervention.models.revocation import RevocationDocument from intervention.utils.quality import InterventionQualityChecker -from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \ - generate_document_file_upload_path, RecordableObject, CheckableObject, ShareableObject -from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT -from user.models import UserActionLogEntry, UserAction - - -class Responsibility(UuidModel): - """ - Holds intervention data about responsible organizations and their file numbers for this case - - """ - registration_office = models.ForeignKey( - KonovaCode, - on_delete=models.SET_NULL, - null=True, - related_name="+", - blank=True, - limit_choices_to={ - "code_lists__in": [CODELIST_REGISTRATION_OFFICE_ID], - "is_selectable": True, - "is_archived": False, - } - ) - registration_file_number = models.CharField(max_length=1000, blank=True, null=True) - conservation_office = models.ForeignKey( - KonovaCode, - on_delete=models.SET_NULL, - null=True, - related_name="+", - blank=True, - limit_choices_to={ - "code_lists__in": [CODELIST_CONSERVATION_OFFICE_ID], - "is_selectable": True, - "is_archived": False, - } - ) - conservation_file_number = models.CharField(max_length=1000, blank=True, null=True) - handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher' or 'Maßnahmenträger'") - - def __str__(self): - return "ZB: {} | ETS: {} | Handler: {}".format( - self.registration_office, - self.conservation_office, - self.handler - ) - - -class Revocation(BaseResource): - """ - Holds revocation data e.g. for intervention objects - """ - date = models.DateField(null=True, blank=True, help_text="Revocation from") - legal = models.ForeignKey("Legal", null=False, blank=False, on_delete=models.CASCADE, help_text="Refers to 'Widerspruch am'", related_name="revocations") - comment = models.TextField(null=True, blank=True) - - def delete(self, *args, **kwargs): - # Make sure related objects are being removed as well - if self.document: - self.document.delete(*args, **kwargs) - super().delete() - - -class RevocationDocument(AbstractDocument): - """ - Specializes document upload for revocations with certain path - """ - instance = models.OneToOneField( - Revocation, - on_delete=models.CASCADE, - related_name="document", - ) - file = models.FileField( - upload_to=generate_document_file_upload_path, - max_length=1000, - ) - - @property - def intervention(self): - """ - Shortcut for opening the related intervention - - Returns: - intervention (Intervention) - """ - return self.instance.legal.intervention - - def delete(self, *args, **kwargs): - """ - Custom delete functionality for RevocationDocuments. - Removes the folder from the file system if there are no further documents for this entry. - - Args: - *args (): - **kwargs (): - - Returns: - - """ - revoc_docs, other_intervention_docs = self.intervention.get_documents() - - # Remove the file itself - super().delete(*args, **kwargs) - - # Always remove 'revocation' folder if the one revocation we just processed is the only one left - folder_path = self.file.path.split("/") - if revoc_docs.count() == 0: - try: - shutil.rmtree("/".join(folder_path[:-1])) - except FileNotFoundError: - # Revocation subfolder seems to be missing already - pass - - if other_intervention_docs.count() == 0: - # If there are no further documents for the intervention, we can simply remove the whole folder as well! - try: - shutil.rmtree("/".join(folder_path[:-2])) - except FileNotFoundError: - # Folder seems to be missing already - pass - - -class Legal(UuidModel): - """ - Holds intervention legal data such as important dates, laws or responsible handler - """ - # Refers to "zugelassen am" - registration_date = models.DateField(null=True, blank=True, help_text="Refers to 'Zugelassen am'") - - # Refers to "Bestandskraft am" - binding_date = models.DateField(null=True, blank=True, help_text="Refers to 'Bestandskraft am'") - - process_type = models.ForeignKey( - KonovaCode, - on_delete=models.SET_NULL, - null=True, - related_name="+", - blank=True, - limit_choices_to={ - "code_lists__in": [CODELIST_PROCESS_TYPE_ID], - "is_selectable": True, - "is_archived": False, - } - ) - laws = models.ManyToManyField( - KonovaCode, - blank=True, - limit_choices_to={ - "code_lists__in": [CODELIST_LAW_ID], - "is_selectable": True, - "is_archived": False, - } - ) +from konova.models import generate_document_file_upload_path, AbstractDocument, Geometry, BaseObject, ShareableObject, \ + RecordableObject, CheckableObject +from konova.settings import LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT, DEFAULT_SRID_RLP +from user.models import UserAction, UserActionLogEntry class Intervention(BaseObject, ShareableObject, RecordableObject, CheckableObject): diff --git a/intervention/models/legal.py b/intervention/models/legal.py new file mode 100644 index 00000000..032bb015 --- /dev/null +++ b/intervention/models/legal.py @@ -0,0 +1,46 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 15.11.21 + +""" +from django.db import models + +from codelist.models import KonovaCode +from codelist.settings import CODELIST_LAW_ID, CODELIST_PROCESS_TYPE_ID +from konova.models import UuidModel + + +class Legal(UuidModel): + """ + Holds intervention legal data such as important dates, laws or responsible handler + """ + # Refers to "zugelassen am" + registration_date = models.DateField(null=True, blank=True, help_text="Refers to 'Zugelassen am'") + + # Refers to "Bestandskraft am" + binding_date = models.DateField(null=True, blank=True, help_text="Refers to 'Bestandskraft am'") + + process_type = models.ForeignKey( + KonovaCode, + on_delete=models.SET_NULL, + null=True, + related_name="+", + blank=True, + limit_choices_to={ + "code_lists__in": [CODELIST_PROCESS_TYPE_ID], + "is_selectable": True, + "is_archived": False, + } + ) + laws = models.ManyToManyField( + KonovaCode, + blank=True, + limit_choices_to={ + "code_lists__in": [CODELIST_LAW_ID], + "is_selectable": True, + "is_archived": False, + } + ) + diff --git a/intervention/models/responsibility.py b/intervention/models/responsibility.py new file mode 100644 index 00000000..19234acd --- /dev/null +++ b/intervention/models/responsibility.py @@ -0,0 +1,53 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 15.11.21 + +""" +from django.db import models + +from codelist.models import KonovaCode +from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID +from konova.models import UuidModel + + +class Responsibility(UuidModel): + """ + Holds intervention data about responsible organizations and their file numbers for this case + + """ + registration_office = models.ForeignKey( + KonovaCode, + on_delete=models.SET_NULL, + null=True, + related_name="+", + blank=True, + limit_choices_to={ + "code_lists__in": [CODELIST_REGISTRATION_OFFICE_ID], + "is_selectable": True, + "is_archived": False, + } + ) + registration_file_number = models.CharField(max_length=1000, blank=True, null=True) + conservation_office = models.ForeignKey( + KonovaCode, + on_delete=models.SET_NULL, + null=True, + related_name="+", + blank=True, + limit_choices_to={ + "code_lists__in": [CODELIST_CONSERVATION_OFFICE_ID], + "is_selectable": True, + "is_archived": False, + } + ) + conservation_file_number = models.CharField(max_length=1000, blank=True, null=True) + handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher' or 'Maßnahmenträger'") + + def __str__(self): + return "ZB: {} | ETS: {} | Handler: {}".format( + self.registration_office, + self.conservation_office, + self.handler + ) diff --git a/intervention/models/revocation.py b/intervention/models/revocation.py new file mode 100644 index 00000000..5eb70e5e --- /dev/null +++ b/intervention/models/revocation.py @@ -0,0 +1,87 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 15.11.21 + +""" + +import shutil + +from django.contrib.gis.db import models +from konova.models import BaseResource, AbstractDocument, generate_document_file_upload_path + + +class Revocation(BaseResource): + """ + Holds revocation data e.g. for intervention objects + """ + date = models.DateField(null=True, blank=True, help_text="Revocation from") + legal = models.ForeignKey("Legal", null=False, blank=False, on_delete=models.CASCADE, help_text="Refers to 'Widerspruch am'", related_name="revocations") + comment = models.TextField(null=True, blank=True) + + def delete(self, *args, **kwargs): + # Make sure related objects are being removed as well + if self.document: + self.document.delete(*args, **kwargs) + super().delete() + + +class RevocationDocument(AbstractDocument): + """ + Specializes document upload for revocations with certain path + """ + instance = models.OneToOneField( + Revocation, + on_delete=models.CASCADE, + related_name="document", + ) + file = models.FileField( + upload_to=generate_document_file_upload_path, + max_length=1000, + ) + + @property + def intervention(self): + """ + Shortcut for opening the related intervention + + Returns: + intervention (Intervention) + """ + return self.instance.legal.intervention + + def delete(self, *args, **kwargs): + """ + Custom delete functionality for RevocationDocuments. + Removes the folder from the file system if there are no further documents for this entry. + + Args: + *args (): + **kwargs (): + + Returns: + + """ + revoc_docs, other_intervention_docs = self.intervention.get_documents() + + # Remove the file itself + super().delete(*args, **kwargs) + + # Always remove 'revocation' folder if the one revocation we just processed is the only one left + folder_path = self.file.path.split("/") + if revoc_docs.count() == 0: + try: + shutil.rmtree("/".join(folder_path[:-1])) + except FileNotFoundError: + # Revocation subfolder seems to be missing already + pass + + if other_intervention_docs.count() == 0: + # If there are no further documents for the intervention, we can simply remove the whole folder as well! + try: + shutil.rmtree("/".join(folder_path[:-2])) + except FileNotFoundError: + # Folder seems to be missing already + pass +