* adds support for GET /check on intervention to run checks automatically via API
pull/90/head
mpeltriaux 3 years ago
parent 617d969a10
commit 26f402fd3b

@ -8,9 +8,11 @@ Created on: 21.01.22
from django.urls import path from django.urls import path
from api.views.v1.views import EmaAPIViewV1, EcoAccountAPIViewV1, CompensationAPIViewV1, InterventionAPIViewV1 from api.views.v1.views import EmaAPIViewV1, EcoAccountAPIViewV1, CompensationAPIViewV1, InterventionAPIViewV1
from api.views.views import InterventionCheckAPIView
app_name = "v1" app_name = "v1"
urlpatterns = [ urlpatterns = [
path("intervention/<id>/check", InterventionCheckAPIView.as_view(), name="intervention-check"),
path("intervention/<id>", InterventionAPIViewV1.as_view(), name="intervention"), path("intervention/<id>", InterventionAPIViewV1.as_view(), name="intervention"),
path("intervention/", InterventionAPIViewV1.as_view(), name="intervention"), path("intervention/", InterventionAPIViewV1.as_view(), name="intervention"),
path("compensation/<id>", CompensationAPIViewV1.as_view(), name="compensation"), path("compensation/<id>", CompensationAPIViewV1.as_view(), name="compensation"),

@ -182,7 +182,6 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
# Fill in data to objects # Fill in data to objects
properties = json_model["properties"] properties = json_model["properties"]
obj.title = properties["title"] obj.title = properties["title"]
obj.modified = update_action
self.set_responsibility(obj, properties.get("responsible", None)) self.set_responsibility(obj, properties.get("responsible", None))
self.set_legal(obj, properties.get("legal", None)) self.set_legal(obj, properties.get("legal", None))
self.set_payments(obj, properties.get("payments", None)) self.set_payments(obj, properties.get("payments", None))
@ -194,7 +193,7 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
obj.legal.save() obj.legal.save()
obj.save() obj.save()
obj.log.add(update_action) obj.mark_as_edited(user)
celery_update_parcels.delay(obj.geometry.id) celery_update_parcels.delay(obj.geometry.id)

@ -13,13 +13,23 @@ from api.utils.serializer.v1.compensation import CompensationAPISerializerV1
from api.utils.serializer.v1.ecoaccount import EcoAccountAPISerializerV1 from api.utils.serializer.v1.ecoaccount import EcoAccountAPISerializerV1
from api.utils.serializer.v1.ema import EmaAPISerializerV1 from api.utils.serializer.v1.ema import EmaAPISerializerV1
from api.utils.serializer.v1.intervention import InterventionAPISerializerV1 from api.utils.serializer.v1.intervention import InterventionAPISerializerV1
from api.views.views import AbstractModelAPIView from api.views.views import AbstractAPIView
class AbstractModelAPIViewV1(AbstractModelAPIView): class AbstractAPIViewV1(AbstractAPIView):
""" Holds general serialization functions for API v1 """ Holds general serialization functions for API v1
""" """
serializer = None
def __init__(self, *args, **kwargs):
self.lookup = {
"id": None, # must be set in subclasses
"deleted__isnull": True,
"users__in": [], # must be set in subclasses
}
super().__init__(*args, **kwargs)
self.serializer = self.serializer()
def get(self, request: HttpRequest, id=None): def get(self, request: HttpRequest, id=None):
""" Handles the GET request """ Handles the GET request
@ -80,17 +90,17 @@ class AbstractModelAPIViewV1(AbstractModelAPIView):
return JsonResponse({"id": updated_id}) return JsonResponse({"id": updated_id})
class InterventionAPIViewV1(AbstractModelAPIViewV1): class InterventionAPIViewV1(AbstractAPIViewV1):
serializer = InterventionAPISerializerV1 serializer = InterventionAPISerializerV1
class CompensationAPIViewV1(AbstractModelAPIViewV1): class CompensationAPIViewV1(AbstractAPIViewV1):
serializer = CompensationAPISerializerV1 serializer = CompensationAPISerializerV1
class EcoAccountAPIViewV1(AbstractModelAPIViewV1): class EcoAccountAPIViewV1(AbstractAPIViewV1):
serializer = EcoAccountAPISerializerV1 serializer = EcoAccountAPISerializerV1
class EmaAPIViewV1(AbstractModelAPIViewV1): class EmaAPIViewV1(AbstractAPIViewV1):
serializer = EmaAPISerializerV1 serializer = EmaAPISerializerV1

@ -6,15 +6,16 @@ Created on: 21.01.22
""" """
from django.http import JsonResponse from django.http import JsonResponse, HttpRequest
from django.views import View from django.views import View
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from api.models import APIUserToken from api.models import APIUserToken
from api.settings import KSP_TOKEN_HEADER_IDENTIFIER from api.settings import KSP_TOKEN_HEADER_IDENTIFIER
from intervention.models import Intervention
class AbstractModelAPIView(View): class AbstractAPIView(View):
""" Base class for API views """ Base class for API views
The API must follow the GeoJSON Specification RFC 7946 The API must follow the GeoJSON Specification RFC 7946
@ -22,21 +23,11 @@ class AbstractModelAPIView(View):
https://datatracker.ietf.org/doc/html/rfc7946 https://datatracker.ietf.org/doc/html/rfc7946
""" """
serializer = None
user = None user = None
class Meta: class Meta:
abstract = True abstract = True
def __init__(self, *args, **kwargs):
self.lookup = {
"id": None, # must be set in subclasses
"deleted__isnull": True,
"users__in": [], # must be set in subclasses
}
super().__init__(*args, **kwargs)
self.serializer = self.serializer()
@csrf_exempt @csrf_exempt
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
try: try:
@ -65,3 +56,76 @@ class AbstractModelAPIView(View):
}, },
status=status_code status=status_code
) )
class InterventionCheckAPIView(AbstractAPIView):
def get(self, request: HttpRequest, id):
""" Takes the GET request
Args:
request (HttpRequest): The incoming request
id (str): The intervention's id
Returns:
response (JsonResponse)
"""
if not self.user.is_zb_user():
return self.return_error_response("Permission not granted", 403)
try:
obj = Intervention.objects.get(
id=id,
users__in=[self.user]
)
except Exception as e:
return self.return_error_response(e)
all_valid, check_details = self.run_quality_checks(obj)
if all_valid:
log_entry = obj.set_checked(self.user)
obj.log.add(log_entry)
data = {
"success": all_valid,
"details": check_details
}
return JsonResponse(data)
def run_quality_checks(self, obj: Intervention) -> (bool, dict):
""" Performs a check for intervention and related compensations
Args:
obj (Intervention): The intervention
Returns:
all_valid (boold): Whether an error occured or not
check_details (dict): A dict containg details on which elements have errors
"""
# Run quality check for Intervention
all_valid = True
intervention_checker = obj.quality_check()
all_valid = intervention_checker.valid and all_valid
# Run quality checks for linked compensations
comps = obj.compensations.all()
comp_checkers = []
for comp in comps:
comp_checker = comp.quality_check()
comp_checkers.append(comp_checker)
all_valid = comp_checker.valid and all_valid
check_details = {
"intervention": {
"id": obj.id,
"errors": intervention_checker.messages
},
"compensations": [
{
"id": comp_checker.obj.id,
"errors": comp_checker.messages
}
for comp_checker in comp_checkers
]
}
return all_valid, check_details

@ -154,6 +154,7 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
def set_unrecorded(self, user: User): def set_unrecorded(self, user: User):
log_entry = super().set_unrecorded(user) log_entry = super().set_unrecorded(user)
self.add_log_entry_to_compensations(log_entry) self.add_log_entry_to_compensations(log_entry)
return log_entry
def set_recorded(self, user: User) -> UserActionLogEntry: def set_recorded(self, user: User) -> UserActionLogEntry:
log_entry = super().set_recorded(user) log_entry = super().set_recorded(user)
@ -259,11 +260,6 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
Returns: Returns:
""" """
user_action_edit = UserActionLogEntry.get_edited_action(performing_user, comment=edit_comment)
self.log.add(user_action_edit)
self.modified = user_action_edit
self.save()
super().mark_as_edited(performing_user, request) super().mark_as_edited(performing_user, request)
if self.checked: if self.checked:
self.set_unchecked() self.set_unchecked()

@ -75,9 +75,7 @@ def default_group_required(function):
@wraps(function) @wraps(function)
def wrap(request, *args, **kwargs): def wrap(request, *args, **kwargs):
user = request.user user = request.user
has_group = user.groups.filter( has_group = user.is_default_user()
name=DEFAULT_GROUP
).exists()
if has_group: if has_group:
return function(request, *args, **kwargs) return function(request, *args, **kwargs)
else: else:
@ -95,9 +93,7 @@ def registration_office_group_required(function):
@wraps(function) @wraps(function)
def wrap(request, *args, **kwargs): def wrap(request, *args, **kwargs):
user = request.user user = request.user
has_group = user.groups.filter( has_group = user.is_zb_user()
name=ZB_GROUP
).exists()
if has_group: if has_group:
return function(request, *args, **kwargs) return function(request, *args, **kwargs)
else: else:
@ -115,9 +111,7 @@ def conservation_office_group_required(function):
@wraps(function) @wraps(function)
def wrap(request, *args, **kwargs): def wrap(request, *args, **kwargs):
user = request.user user = request.user
has_group = user.groups.filter( has_group = user.is_ets_user()
name=ETS_GROUP
).exists()
if has_group: if has_group:
return function(request, *args, **kwargs) return function(request, *args, **kwargs)
else: else:

@ -277,7 +277,8 @@ class RecordableObjectMixin(models.Model):
self.save() self.save()
if self.recorded: if self.recorded:
self.set_unrecorded(performing_user) action = self.set_unrecorded(performing_user)
self.log.add(action)
if request: if request:
messages.info( messages.info(
request, request,

@ -9,6 +9,7 @@ from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from konova.settings import ZB_GROUP, DEFAULT_GROUP, ETS_GROUP
from konova.utils.mailer import Mailer from konova.utils.mailer import Mailer
from user.enums import UserNotificationEnum from user.enums import UserNotificationEnum
@ -28,6 +29,36 @@ class User(AbstractUser):
id=notification_enum.value id=notification_enum.value
).exists() ).exists()
def is_zb_user(self):
""" Shortcut for checking whether a user is of a special group or not
Returns:
bool
"""
return self.groups.filter(
name=ZB_GROUP
).exists()
def is_default_user(self):
""" Shortcut for checking whether a user is of a special group or not
Returns:
bool
"""
return self.groups.filter(
name=DEFAULT_GROUP
).exists()
def is_ets_user(self):
""" Shortcut for checking whether a user is of a special group or not
Returns:
bool
"""
return self.groups.filter(
name=ETS_GROUP
).exists()
def send_mail_shared_access_removed(self, obj_identifier): def send_mail_shared_access_removed(self, obj_identifier):
""" Sends a mail to the user in case of removed shared access """ Sends a mail to the user in case of removed shared access

Loading…
Cancel
Save