diff --git a/api/urls/v1/urls.py b/api/urls/v1/urls.py index 3350c6b6..4c925105 100644 --- a/api/urls/v1/urls.py +++ b/api/urls/v1/urls.py @@ -7,15 +7,12 @@ Created on: 21.01.22 """ from django.urls import path -from api.views.v1.compensation import APICompensationViewV1 -from api.views.v1.ecoaccount import APIEcoAccountViewV1 -from api.views.v1.ema import APIEmaViewV1 -from api.views.v1.intervention import APIInterventionViewV1 +from api.views.v1.views import EmaAPIViewV1, EcoAccountAPIViewV1, CompensationAPIViewV1, InterventionAPIViewV1 app_name = "v1" urlpatterns = [ - path("intervention/", APIInterventionViewV1.as_view(), name="intervention"), - path("compensation/", APICompensationViewV1.as_view(), name="compensation"), - path("ecoaccount/", APIEcoAccountViewV1.as_view(), name="ecoaccount"), - path("ema/", APIEmaViewV1.as_view(), name="ema"), + path("intervention/", InterventionAPIViewV1.as_view(), name="intervention"), + path("compensation/", CompensationAPIViewV1.as_view(), name="compensation"), + path("ecoaccount/", EcoAccountAPIViewV1.as_view(), name="ecoaccount"), + path("ema/", EmaAPIViewV1.as_view(), name="ema"), ] diff --git a/api/utils/__init__.py b/api/utils/__init__.py new file mode 100644 index 00000000..71a67bbb --- /dev/null +++ b/api/utils/__init__.py @@ -0,0 +1,7 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 24.01.22 + +""" diff --git a/api/utils/serializer.py b/api/utils/serializer.py new file mode 100644 index 00000000..eb7dc601 --- /dev/null +++ b/api/utils/serializer.py @@ -0,0 +1,76 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 24.01.22 + +""" +from abc import abstractmethod + + +class AbstractModelAPISerializer: + model = None + user = None + lookup = None + properties_data = None + + class Meta: + abstract = True + + def __init__(self, *args, **kwargs): + self.lookup = { + "id": None, # must be set + "deleted__isnull": True, + "users__in": [], # must be set + } + super().__init__(*args, **kwargs) + + @abstractmethod + def model_to_geo_json(self, entry): + """ Defines the model as geo json + + Args: + entry (): The found entry from the database + + Returns: + + """ + raise NotImplementedError("Must be implemented in subclasses") + + @abstractmethod + def extend_properties_data(self, entry): + """ Defines the 'properties' part of geo json + + Args: + entry (): The found entry from the database + + Returns: + + """ + raise NotImplementedError("Must be implemented in subclasses") + + @abstractmethod + def prepare_lookup(self, _id, user): + """ Updates lookup dict for db fetching + + Args: + _id (str): The object's id + user (User): The user requesting for + + Returns: + + """ + self.lookup["id"] = _id + self.lookup["users__in"] = [user] + + def fetch_and_serialize(self): + """ Serializes the model entry according to the given lookup data + + Args: + + Returns: + serialized_data (dict) + """ + entry = self.model.objects.get(**self.lookup) + serialized_data = self.model_to_geo_json(entry) + return serialized_data diff --git a/api/utils/v1/__init__.py b/api/utils/v1/__init__.py new file mode 100644 index 00000000..71a67bbb --- /dev/null +++ b/api/utils/v1/__init__.py @@ -0,0 +1,7 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 24.01.22 + +""" diff --git a/api/views/v1/compensation.py b/api/utils/v1/compensation.py similarity index 82% rename from api/views/v1/compensation.py rename to api/utils/v1/compensation.py index 1ef49b98..557ae13d 100644 --- a/api/views/v1/compensation.py +++ b/api/utils/v1/compensation.py @@ -2,21 +2,20 @@ Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de -Created on: 21.01.22 +Created on: 24.01.22 """ - -from api.views.v1.views import AbstractModelAPIViewV1 +from api.utils.v1.serializer import AbstractModelAPISerializerV1 from compensation.models import Compensation -class APICompensationViewV1(AbstractModelAPIViewV1): +class CompensationAPISerializerV1(AbstractModelAPISerializerV1): model = Compensation - def prepare_lookup(self, id): + def prepare_lookup(self, id, user): self.lookup["id"] = id del self.lookup["users__in"] - self.lookup["intervention__users__in"] = [self.user] + self.lookup["intervention__users__in"] = [user] def intervention_to_json(self, entry): return { @@ -33,4 +32,3 @@ class APICompensationViewV1(AbstractModelAPIViewV1): self.properties_data["after_states"] = self.compensation_state_to_json(entry.after_states.all()) self.properties_data["actions"] = self.compensation_actions_to_json(entry.actions.all()) self.properties_data["deadlines"] = self.deadlines_to_json(entry.deadlines.all()) - diff --git a/api/views/v1/ecoaccount.py b/api/utils/v1/ecoaccount.py similarity index 91% rename from api/views/v1/ecoaccount.py rename to api/utils/v1/ecoaccount.py index 7339a0a5..0aab2bba 100644 --- a/api/views/v1/ecoaccount.py +++ b/api/utils/v1/ecoaccount.py @@ -2,15 +2,15 @@ Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de -Created on: 21.01.22 +Created on: 24.01.22 """ -from api.views.v1.views import AbstractModelAPIViewV1 +from api.utils.v1.serializer import AbstractModelAPISerializerV1 from compensation.models import EcoAccount from intervention.models import Legal, Responsibility -class APIEcoAccountViewV1(AbstractModelAPIViewV1): +class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1): model = EcoAccount def extend_properties_data(self, entry): diff --git a/api/views/v1/ema.py b/api/utils/v1/ema.py similarity index 88% rename from api/views/v1/ema.py rename to api/utils/v1/ema.py index 991d3824..66e6b402 100644 --- a/api/views/v1/ema.py +++ b/api/utils/v1/ema.py @@ -2,15 +2,15 @@ Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de -Created on: 21.01.22 +Created on: 24.01.22 """ -from api.views.v1.views import AbstractModelAPIViewV1 +from api.utils.v1.serializer import AbstractModelAPISerializerV1 from ema.models import Ema from intervention.models import Responsibility -class APIEmaViewV1(AbstractModelAPIViewV1): +class EmaAPISerializerV1(AbstractModelAPISerializerV1): model = Ema def responsible_to_json(self, responsible: Responsibility): diff --git a/api/views/v1/intervention.py b/api/utils/v1/intervention.py similarity index 83% rename from api/views/v1/intervention.py rename to api/utils/v1/intervention.py index d0977939..76f08b1b 100644 --- a/api/views/v1/intervention.py +++ b/api/utils/v1/intervention.py @@ -2,16 +2,17 @@ Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de -Created on: 21.01.22 +Created on: 24.01.22 """ + from django.db.models import QuerySet -from api.views.v1.views import AbstractModelAPIViewV1 +from api.utils.v1.serializer import AbstractModelAPISerializerV1 from intervention.models import Intervention -class APIInterventionViewV1(AbstractModelAPIViewV1): +class InterventionAPISerializerV1(AbstractModelAPISerializerV1): model = Intervention def compensations_to_json(self, qs: QuerySet): @@ -26,4 +27,4 @@ class APIInterventionViewV1(AbstractModelAPIViewV1): self.properties_data["legal"] = self.legal_to_json(entry.legal) self.properties_data["compensations"] = self.compensations_to_json(entry.compensations.all()) self.properties_data["payments"] = self.payments_to_json(entry.payments.all()) - self.properties_data["deductions"] = self.deductions_to_json(entry.deductions.all()) + self.properties_data["deductions"] = self.deductions_to_json(entry.deductions.all()) \ No newline at end of file diff --git a/api/utils/v1/serializer.py b/api/utils/v1/serializer.py new file mode 100644 index 00000000..0bdef78c --- /dev/null +++ b/api/utils/v1/serializer.py @@ -0,0 +1,200 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 24.01.22 + +""" + +import json + +from django.db.models import QuerySet + +from api.utils.serializer import AbstractModelAPISerializer +from codelist.models import KonovaCode +from intervention.models import Responsibility, Legal + + +class AbstractModelAPISerializerV1(AbstractModelAPISerializer): + def model_to_geo_json(self, entry): + """ Adds the basic data, which all elements hold + + Args: + entry (): The data entry + + Returns: + + """ + geom = entry.geometry.geom.geojson + geo_json = json.loads(geom) + self.properties_data = { + "id": entry.id, + "identifier": entry.identifier, + "title": entry.title, + "created_on": self.created_on_to_json(entry), + "modified_on": self.modified_on_to_json(entry), + } + self.extend_properties_data(entry) + geo_json["properties"] = self.properties_data + return geo_json + + def konova_code_to_json(self, konova_code: KonovaCode): + """ Serializes KonovaCode model into json + + Args: + konova_code (KonovaCode): The KonovaCode entry + + Returns: + serialized_json (dict) + """ + return { + "atom_id": konova_code.atom_id, + "long_name": konova_code.long_name, + "short_name": konova_code.short_name, + } + + def responsible_to_json(self, responsible: Responsibility): + """ Serializes Responsibility model into json + + Args: + responsible (Responsibility): The Responsibility entry + + Returns: + serialized_json (dict) + """ + return { + "registration_office": self.konova_code_to_json(responsible.registration_office), + "registration_file_number": responsible.registration_file_number, + "conservation_office": self.konova_code_to_json(responsible.conservation_office), + "conservation_file_number": responsible.conservation_file_number, + "handler": responsible.handler, + } + + def legal_to_json(self, legal: Legal): + """ Serializes Legal model into json + + Args: + legal (Legal): The Legal entry + + Returns: + serialized_json (dict) + """ + return { + "registration_date": legal.registration_date, + "binding_date": legal.binding_date, + "process_type": self.konova_code_to_json(legal.process_type), + "laws": [self.konova_code_to_json(law) for law in legal.laws.all()], + } + + def payments_to_json(self, qs: QuerySet): + """ Serializes payments into json + + Args: + qs (QuerySet): A queryset of Payment entries + + Returns: + serialized_json (list) + """ + return list(qs.values("amount", "due_on", "comment")) + + def deductions_to_json(self, qs: QuerySet): + """ Serializes eco account deductions into json + + Args: + qs (QuerySet): A queryset of EcoAccountDeduction entries + + Returns: + serialized_json (list) + """ + return [ + { + "id": entry.pk, + "eco_account": { + "id": entry.account.pk, + "identifier": entry.account.identifier, + "title": entry.account.title, + }, + "surface": entry.surface, + "intervention": { + "id": entry.intervention.pk, + "identifier": entry.intervention.identifier, + "title": entry.intervention.title, + } + } + for entry in qs + ] + + def compensation_state_to_json(self, qs: QuerySet): + """ Serializes compensation states into json + + Args: + qs (QuerySet): A queryset of CompensationState entries + + Returns: + serialized_json (list) + """ + return [ + { + "biotope": self.konova_code_to_json(entry.biotope_type), + "surface": entry.surface, + } + for entry in qs + ] + + def compensation_actions_to_json(self, qs: QuerySet): + """ Serializes CompensationActions into json + + Args: + qs (QuerySet): A queryset of CompensationAction entries + + Returns: + serialized_json (list) + """ + return [ + { + "action": self.konova_code_to_json(entry.action_type), + "amount": entry.amount, + "unit": entry.unit, + "comment": entry.comment, + } + for entry in qs + ] + + def deadlines_to_json(self, qs: QuerySet): + """ Serializes deadlines into json + + Args: + qs (QuerySet): A queryset of Deadline entries + + Returns: + serialized_json (list) + """ + return list(qs.values( + "type", + "date", + "comment", + )) + + def created_on_to_json(self, entry): + """ Serializes the created_on into json + + Args: + entry (BaseObject): The entry + + Returns: + created_on (timestamp) + """ + return entry.created.timestamp + + def modified_on_to_json(self, entry): + """ Serializes the modified_on into json + + Args: + entry (BaseObject): The entry + + Returns: + modified_on (timestamp) + """ + modified_on = entry.modified or entry.created + modified_on = modified_on.timestamp + return modified_on diff --git a/api/views/v1/views.py b/api/views/v1/views.py index 7aaeb187..688d4e03 100644 --- a/api/views/v1/views.py +++ b/api/views/v1/views.py @@ -5,14 +5,13 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 21.01.22 """ -import json - -from django.db.models import QuerySet from django.http import JsonResponse, HttpRequest +from api.utils.v1.compensation import CompensationAPISerializerV1 +from api.utils.v1.ecoaccount import EcoAccountAPISerializerV1 +from api.utils.v1.ema import EmaAPISerializerV1 +from api.utils.v1.intervention import InterventionAPISerializerV1 from api.views.views import AbstractModelAPIView -from codelist.models import KonovaCode -from intervention.models import Responsibility, Legal class AbstractModelAPIViewV1(AbstractModelAPIView): @@ -32,205 +31,25 @@ class AbstractModelAPIViewV1(AbstractModelAPIView): Returns: """ - self.prepare_lookup(id) - try: - data = self.fetch_and_serialize() + self.serializer.prepare_lookup(id, self.user) + data = self.serializer.fetch_and_serialize() except Exception as e: return self.return_error_response(e, 500) return JsonResponse(data) - def model_to_geo_json(self, entry): - """ Adds the basic data, which all elements hold - Args: - entry (): The data entry +class InterventionAPIViewV1(AbstractModelAPIViewV1): + serializer = InterventionAPISerializerV1 - Returns: - """ - geom = entry.geometry.geom.geojson - geo_json = json.loads(geom) - self.properties_data = { - "id": entry.id, - "identifier": entry.identifier, - "title": entry.title, - "created_on": self.created_on_to_json(entry), - "modified_on": self.modified_on_to_json(entry), - } - self.extend_properties_data(entry) - geo_json["properties"] = self.properties_data - return geo_json +class CompensationAPIViewV1(AbstractModelAPIViewV1): + serializer = CompensationAPISerializerV1 - def prepare_lookup(self, id): - """ Customizes lookup values for db filtering - Args: - id (str): The entries id +class EcoAccountAPIViewV1(AbstractModelAPIViewV1): + serializer = EcoAccountAPISerializerV1 - Returns: - """ - self.lookup["id"] = id - self.lookup["users__in"] = [self.user] - - def konova_code_to_json(self, konova_code: KonovaCode): - """ Serializes KonovaCode model into json - - Args: - konova_code (KonovaCode): The KonovaCode entry - - Returns: - serialized_json (dict) - """ - return { - "atom_id": konova_code.atom_id, - "long_name": konova_code.long_name, - "short_name": konova_code.short_name, - } - - def responsible_to_json(self, responsible: Responsibility): - """ Serializes Responsibility model into json - - Args: - responsible (Responsibility): The Responsibility entry - - Returns: - serialized_json (dict) - """ - return { - "registration_office": self.konova_code_to_json(responsible.registration_office), - "registration_file_number": responsible.registration_file_number, - "conservation_office": self.konova_code_to_json(responsible.conservation_office), - "conservation_file_number": responsible.conservation_file_number, - "handler": responsible.handler, - } - - def legal_to_json(self, legal: Legal): - """ Serializes Legal model into json - - Args: - legal (Legal): The Legal entry - - Returns: - serialized_json (dict) - """ - return { - "registration_date": legal.registration_date, - "binding_date": legal.binding_date, - "process_type": self.konova_code_to_json(legal.process_type), - "laws": [self.konova_code_to_json(law) for law in legal.laws.all()], - } - - def payments_to_json(self, qs: QuerySet): - """ Serializes payments into json - - Args: - qs (QuerySet): A queryset of Payment entries - - Returns: - serialized_json (list) - """ - return list(qs.values("amount", "due_on", "comment")) - - def deductions_to_json(self, qs: QuerySet): - """ Serializes eco account deductions into json - - Args: - qs (QuerySet): A queryset of EcoAccountDeduction entries - - Returns: - serialized_json (list) - """ - return [ - { - "id": entry.pk, - "eco_account": { - "id": entry.account.pk, - "identifier": entry.account.identifier, - "title": entry.account.title, - }, - "surface": entry.surface, - "intervention": { - "id": entry.intervention.pk, - "identifier": entry.intervention.identifier, - "title": entry.intervention.title, - } - } - for entry in qs - ] - - def compensation_state_to_json(self, qs: QuerySet): - """ Serializes compensation states into json - - Args: - qs (QuerySet): A queryset of CompensationState entries - - Returns: - serialized_json (list) - """ - return [ - { - "biotope": self.konova_code_to_json(entry.biotope_type), - "surface": entry.surface, - } - for entry in qs - ] - - def compensation_actions_to_json(self, qs: QuerySet): - """ Serializes CompensationActions into json - - Args: - qs (QuerySet): A queryset of CompensationAction entries - - Returns: - serialized_json (list) - """ - return [ - { - "action": self.konova_code_to_json(entry.action_type), - "amount": entry.amount, - "unit": entry.unit, - "comment": entry.comment, - } - for entry in qs - ] - - def deadlines_to_json(self, qs: QuerySet): - """ Serializes deadlines into json - - Args: - qs (QuerySet): A queryset of Deadline entries - - Returns: - serialized_json (list) - """ - return list(qs.values( - "type", - "date", - "comment", - )) - - def created_on_to_json(self, entry): - """ Serializes the created_on into json - - Args: - entry (BaseObject): The entry - - Returns: - created_on (timestamp) - """ - return entry.created.timestamp - - def modified_on_to_json(self, entry): - """ Serializes the modified_on into json - - Args: - entry (BaseObject): The entry - - Returns: - modified_on (timestamp) - """ - modified_on = entry.modified or entry.created - modified_on = modified_on.timestamp - return modified_on +class EmaAPIViewV1(AbstractModelAPIViewV1): + serializer = EmaAPISerializerV1 diff --git a/api/views/views.py b/api/views/views.py index 21b60a8e..4316fb95 100644 --- a/api/views/views.py +++ b/api/views/views.py @@ -5,7 +5,6 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 21.01.22 """ -from abc import abstractmethod from django.http import JsonResponse from django.views import View @@ -22,10 +21,8 @@ class AbstractModelAPIView(View): https://datatracker.ietf.org/doc/html/rfc7946 """ - model = None + serializer = None user = None - lookup = None - properties_data = None class Meta: abstract = True @@ -37,45 +34,11 @@ class AbstractModelAPIView(View): "users__in": [], # must be set in subclasses } super().__init__(*args, **kwargs) - - @abstractmethod - def model_to_geo_json(self, entry): - """ Defines the model as geo json - - Args: - entry (): The found entry from the database - - Returns: - - """ - raise NotImplementedError("Must be implemented in subclasses") - - @abstractmethod - def extend_properties_data(self, entry): - """ Defines the 'properties' part of geo json - - Args: - entry (): The found entry from the database - - Returns: - - """ - raise NotImplementedError("Must be implemented in subclasses") - - def fetch_and_serialize(self): - """ Serializes the model entry according to the given lookup data - - Args: - - Returns: - serialized_data (dict) - """ - entry = self.model.objects.get(**self.lookup) - serialized_data = self.model_to_geo_json(entry) - return serialized_data + self.serializer = self.serializer() def dispatch(self, request, *args, **kwargs): try: + # Fetch the proper user from the given request header token self.user = APIUserToken.get_user_from_token(request.headers.get(KSP_TOKEN_HEADER_IDENTIFIER, None)) except PermissionError as e: return self.return_error_response(e, 403)