* adds support for GET and PUT of sharing users for all data types (compensation is shared via intervention)
This commit is contained in:
mpeltriaux 2022-01-26 09:16:37 +01:00
parent 0b723b1529
commit fc0cd2f086
4 changed files with 157 additions and 2 deletions

View File

@ -8,17 +8,23 @@ 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 from api.views.views import InterventionCheckAPIView, InterventionAPIShareView, EcoAccountAPIShareView, EmaAPIShareView
app_name = "v1" app_name = "v1"
urlpatterns = [ urlpatterns = [
path("intervention/<id>/check", InterventionCheckAPIView.as_view(), name="intervention-check"), path("intervention/<id>/check", InterventionCheckAPIView.as_view(), name="intervention-check"),
path("intervention/<id>/share", InterventionAPIShareView.as_view(), name="intervention-share"),
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"),
path("compensation/", CompensationAPIViewV1.as_view(), name="compensation"), path("compensation/", CompensationAPIViewV1.as_view(), name="compensation"),
path("ecoaccount/<id>/share", EcoAccountAPIShareView.as_view(), name="ecoaccount-share"),
path("ecoaccount/<id>", EcoAccountAPIViewV1.as_view(), name="ecoaccount"), path("ecoaccount/<id>", EcoAccountAPIViewV1.as_view(), name="ecoaccount"),
path("ecoaccount/", EcoAccountAPIViewV1.as_view(), name="ecoaccount"), path("ecoaccount/", EcoAccountAPIViewV1.as_view(), name="ecoaccount"),
path("ema/<id>/share", EmaAPIShareView.as_view(), name="ema-share"),
path("ema/<id>", EmaAPIViewV1.as_view(), name="ema"), path("ema/<id>", EmaAPIViewV1.as_view(), name="ema"),
path("ema/", EmaAPIViewV1.as_view(), name="ema"), path("ema/", EmaAPIViewV1.as_view(), name="ema"),
] ]

View File

@ -12,6 +12,7 @@ from compensation.models import Compensation
from intervention.models import Intervention from intervention.models import Intervention
from konova.models import Geometry from konova.models import Geometry
from konova.tasks import celery_update_parcels from konova.tasks import celery_update_parcels
from konova.utils.message_templates import DATA_UNSHARED
from user.models import UserActionLogEntry from user.models import UserActionLogEntry
@ -88,7 +89,7 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
is_shared = intervention.is_shared_with(user) is_shared = intervention.is_shared_with(user)
if not is_shared: if not is_shared:
raise PermissionError("Intervention not shared with user") raise PermissionError(DATA_UNSHARED)
obj.intervention = intervention obj.intervention = intervention
return obj return obj

View File

@ -5,14 +5,20 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 21.01.22 Created on: 21.01.22
""" """
import json
from django.db.models import QuerySet
from django.http import JsonResponse, HttpRequest 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 compensation.models import EcoAccount
from ema.models import Ema
from intervention.models import Intervention from intervention.models import Intervention
from konova.utils.message_templates import DATA_UNSHARED
from user.models import User
class AbstractAPIView(View): class AbstractAPIView(View):
@ -129,3 +135,122 @@ class InterventionCheckAPIView(AbstractAPIView):
] ]
} }
return all_valid, check_details return all_valid, check_details
class AbstractModelShareAPIView(AbstractAPIView):
model = None
class Meta:
abstract = True
def get(self, request: HttpRequest, id):
""" Performs the GET request handling
Args:
request (HttpRequest): The incoming request
id (str): The object's id
Returns:
"""
try:
users = self._get_shared_users_of_object(id)
except Exception as e:
return self.return_error_response(e)
data = {
"users": [
user.username for user in users
]
}
return JsonResponse(data)
def put(self, request: HttpRequest, id):
""" Performs the PUT request handling
Args:
request (HttpRequest): The incoming request
id (str): The object's id
Returns:
"""
try:
success = self._process_put_body(request.body, id)
except Exception as e:
return self.return_error_response(e)
data = {
"success": success,
}
return JsonResponse(data)
def _check_user_has_shared_access(self, obj):
""" Raises a PermissionError if user has no shared access
Args:
obj (BaseObject): The object
Returns:
"""
is_shared = obj.is_shared_with(self.user)
if not is_shared:
raise PermissionError(DATA_UNSHARED)
def _get_shared_users_of_object(self, id) -> QuerySet:
""" Check permissions and get the users
Args:
id (str): The object's id
Returns:
users (QuerySet)
"""
obj = self.model.objects.get(
id=id
)
self._check_user_has_shared_access(obj)
users = obj.shared_users
return users
def _process_put_body(self, body: bytes, id: str):
""" Reads the body data, performs validity checks and sets the new users
Args:
body (bytes): The request.body
id (str): The object's id
Returns:
success (bool)
"""
obj = self.model.objects.get(id=id)
self._check_user_has_shared_access(obj)
new_users = json.loads(body.decode("utf-8"))
new_users = new_users.get("users", [])
if len(new_users) == 0:
raise ValueError("Shared user list must not be empty!")
# Eliminate duplicates
new_users = list(dict.fromkeys(new_users))
# Make sure each of these names exist as a user
new_users_objs = []
for user in new_users:
new_users_objs.append(User.objects.get(username=user))
obj.share_with_list(new_users_objs)
return True
class InterventionAPIShareView(AbstractModelShareAPIView):
model = Intervention
class EcoAccountAPIShareView(AbstractModelShareAPIView):
model = EcoAccount
class EmaAPIShareView(AbstractModelShareAPIView):
model = Ema

View File

@ -245,6 +245,29 @@ class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin):
# Compensations inherit their shared state from the interventions # Compensations inherit their shared state from the interventions
return self.intervention.is_shared_with(user) return self.intervention.is_shared_with(user)
def share_with(self, user: User):
""" Adds user to list of shared access users
Args:
user (User): The user to be added to the object
Returns:
"""
if not self.intervention.is_shared_with(user):
self.intervention.users.add(user)
def share_with_list(self, user_list: list):
""" Sets the list of shared access users
Args:
user_list (list): The users to be added to the object
Returns:
"""
self.intervention.users.set(user_list)
@property @property
def shared_users(self) -> QuerySet: def shared_users(self) -> QuerySet:
""" Shortcut for fetching the users which have shared access on this object """ Shortcut for fetching the users which have shared access on this object