#31 API Share
* adds support for GET and PUT of sharing users for all data types (compensation is shared via intervention)
This commit is contained in:
		
							parent
							
								
									0b723b1529
								
							
						
					
					
						commit
						fc0cd2f086
					
				@ -8,17 +8,23 @@ Created on: 21.01.22
 | 
			
		||||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
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"
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    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/", InterventionAPIViewV1.as_view(), name="intervention"),
 | 
			
		||||
 | 
			
		||||
    path("compensation/<id>", 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/", 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/", EmaAPIViewV1.as_view(), name="ema"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ from compensation.models import Compensation
 | 
			
		||||
from intervention.models import Intervention
 | 
			
		||||
from konova.models import Geometry
 | 
			
		||||
from konova.tasks import celery_update_parcels
 | 
			
		||||
from konova.utils.message_templates import DATA_UNSHARED
 | 
			
		||||
from user.models import UserActionLogEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -88,7 +89,7 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
 | 
			
		||||
        is_shared = intervention.is_shared_with(user)
 | 
			
		||||
 | 
			
		||||
        if not is_shared:
 | 
			
		||||
            raise PermissionError("Intervention not shared with user")
 | 
			
		||||
            raise PermissionError(DATA_UNSHARED)
 | 
			
		||||
 | 
			
		||||
        obj.intervention = intervention
 | 
			
		||||
        return obj
 | 
			
		||||
 | 
			
		||||
@ -5,14 +5,20 @@ 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 django.views import View
 | 
			
		||||
from django.views.decorators.csrf import csrf_exempt
 | 
			
		||||
 | 
			
		||||
from api.models import APIUserToken
 | 
			
		||||
from api.settings import KSP_TOKEN_HEADER_IDENTIFIER
 | 
			
		||||
from compensation.models import EcoAccount
 | 
			
		||||
from ema.models import Ema
 | 
			
		||||
from intervention.models import Intervention
 | 
			
		||||
from konova.utils.message_templates import DATA_UNSHARED
 | 
			
		||||
from user.models import User
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AbstractAPIView(View):
 | 
			
		||||
@ -129,3 +135,122 @@ class InterventionCheckAPIView(AbstractAPIView):
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
        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
 | 
			
		||||
@ -245,6 +245,29 @@ class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin):
 | 
			
		||||
        # Compensations inherit their shared state from the interventions
 | 
			
		||||
        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
 | 
			
		||||
    def shared_users(self) -> QuerySet:
 | 
			
		||||
        """ Shortcut for fetching the users which have shared access on this object
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user