import uuid from typing import cast from django_core.mixins import BaseViewSetMixin # type: ignore from django.utils.translation import gettext as _ from drf_spectacular.utils import extend_schema from rest_framework.exceptions import PermissionDenied # type: ignore from rest_framework.permissions import AllowAny, IsAdminUser # type: ignore from rest_framework.viewsets import ModelViewSet # type: ignore from rest_framework.request import HttpRequest # type: ignore from rest_framework.response import Response # type: ignore from rest_framework import status # type: ignore from rest_framework.generics import GenericAPIView # type: ignore from rest_framework.parsers import MultiPartParser, FormParser # type: ignore from rest_framework.generics import get_object_or_404 # type: ignore from core.utils.views import BaseApiViewMixin from core.apps.contracts.models import ( ContractOwnerModel, ContractAttachedFileModel, ) from core.apps.contracts.serializers import ( CreateContractOwnerSerializer, ListContractOwnerSerializer, RetrieveContractOwnerSerializer, UpdateContractOwnerSerializer, DestroyContractOwnerSerializer, CreateContractFileContentFromOwnerSerializer, ) ################################################################################### # @view-set | ALL - /contract-owners ################################################################################### @extend_schema(tags=["Contract Owners"]) class ContractOwnerViewSet(BaseViewSetMixin, ModelViewSet): queryset = ContractOwnerModel.objects.all() serializer_class = ListContractOwnerSerializer permission_classes = [AllowAny] action_permission_classes = { "list": [IsAdminUser], "retrieve": [IsAdminUser], "create": [IsAdminUser], "update": [IsAdminUser], "destroy": [IsAdminUser], } action_serializer_class = { # type: ignore "list": ListContractOwnerSerializer, "retrieve": RetrieveContractOwnerSerializer, "create": CreateContractOwnerSerializer, "update": UpdateContractOwnerSerializer, "destroy": DestroyContractOwnerSerializer, } ################################################################################### # @api-view | DELETE - /contract-owners/{owner_id}/files/{file_id} ################################################################################### @extend_schema(tags=["Contract Files"]) class ContractOwnerAttachedFileApiView(BaseApiViewMixin, GenericAPIView): # type: ignore permission_classes = [AllowAny] serializer_class = ListContractOwnerSerializer queryset = ContractOwnerModel.objects.all() method_permission_classes = {"delete": [AllowAny]} method_serializer_class = {} @extend_schema( summary="Delete a file from contract", description="Deletes a contract-attached file if contract allows file deletion.", ) def delete( self, request: HttpRequest, owner_id: uuid.UUID, file_id: uuid.UUID, *args: object, **kwargs: object ) -> Response: owner = get_object_or_404( ContractOwnerModel.objects.all().select_related("contract"), pk=owner_id ) if not owner.contract.allow_delete_files: raise PermissionDenied(_("Deleting attached files was restricted for this contract")) file = get_object_or_404( ContractAttachedFileModel.objects.all().select_related("contract"), pk=file_id ) if owner.contract.pk != file.contract.pk: raise PermissionDenied(_("Contract have no such file attached")) file.delete() return Response(status=status.HTTP_204_NO_CONTENT) ################################################################################### # @api-view | POST - /contract-owners/{owner_id}/files/{file_id}/upload ################################################################################### @extend_schema(tags=["Contract File contents"]) class UploadFileContentApiView(BaseApiViewMixin, GenericAPIView): # type: ignore permission_classes = [AllowAny] parser_classes = [MultiPartParser, FormParser] # type: ignore method_permission_classes = {"post": [AllowAny]} method_serializer_class = {"post": CreateContractFileContentFromOwnerSerializer} @extend_schema( summary="Uploads a file for contract attached files", description="Creates a file for contract attached files.", ) def post( self, request: HttpRequest, owner_id: uuid.UUID, file_id: uuid.UUID, *args: object, **kwargs: object ) -> Response: serializer_context = dict(file_id=file_id, contract_owner_id=owner_id) serializer = cast( CreateContractFileContentFromOwnerSerializer, self.get_serializer(data=request.data, context=serializer_context) # type: ignore ) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED)