#31 API basic implementation Refactor

* reorganizes code into proper api/utils/serializer subclasses to keep serialization logic away from regular view logic
pull/90/head
mpeltriaux 3 years ago
parent 8d400b4ffe
commit 45ac5b68b9

@ -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/<id>", APIInterventionViewV1.as_view(), name="intervention"),
path("compensation/<id>", APICompensationViewV1.as_view(), name="compensation"),
path("ecoaccount/<id>", APIEcoAccountViewV1.as_view(), name="ecoaccount"),
path("ema/<id>", APIEmaViewV1.as_view(), name="ema"),
path("intervention/<id>", InterventionAPIViewV1.as_view(), name="intervention"),
path("compensation/<id>", CompensationAPIViewV1.as_view(), name="compensation"),
path("ecoaccount/<id>", EcoAccountAPIViewV1.as_view(), name="ecoaccount"),
path("ema/<id>", EmaAPIViewV1.as_view(), name="ema"),
]

@ -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
"""

@ -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

@ -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
"""

@ -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())

@ -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):

@ -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):

@ -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())

@ -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

@ -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
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 prepare_lookup(self, id):
""" Customizes lookup values for db filtering
Args:
id (str): The entries id
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
class InterventionAPIViewV1(AbstractModelAPIViewV1):
serializer = InterventionAPISerializerV1
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
class CompensationAPIViewV1(AbstractModelAPIViewV1):
serializer = CompensationAPISerializerV1
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
class EcoAccountAPIViewV1(AbstractModelAPIViewV1):
serializer = EcoAccountAPISerializerV1
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

@ -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)

Loading…
Cancel
Save