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, OpenApiResponse from rest_framework.exceptions import PermissionDenied # type: ignore from rest_framework.decorators import action # 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.views import APIView # type: ignore from rest_framework.parsers import MultiPartParser, FormParser # type: ignore from rest_framework.generics import get_object_or_404 # type: ignore from core.apps.contracts.models import ( ContractOwnerModel, ContractAttachedFileModel ) from core.apps.contracts.serializers import ( CreateContractOwnerSerializer, ListContractOwnerSerializer, RetrieveContractOwnerSerializer, UpdateContractOwnerSerializer, DestroyContractOwnerSerializer, RetrieveContractAttachedFileSerializer, CreateContractAttachedFileSerializer, CreateContractFileContentFromOwnerSerializer, ) @extend_schema(tags=["ContractOwner"]) class ContractOwnerView(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, } class ContractOwnerFileViewSet(BaseViewSetMixin, ModelViewSet): queryset = ContractOwnerModel.objects.all() serializer_class = RetrieveContractAttachedFileSerializer permission_classes = [AllowAny] # action_permission_classes = { # "create_file": [AllowAny], # "list_file": [AllowAny] # } action_serializer_class = { # type: ignore "list_file": RetrieveContractAttachedFileSerializer, "create_file": CreateContractAttachedFileSerializer, } @extend_schema( summary="Contract Files Related to Owner", description="Contract Files Related to Owner", ) @action(url_path="files", methods=["GET"], detail=True) def list_file( self, request: HttpRequest, *args: object, **kwargs: object, ) -> Response: owner = cast(ContractOwnerModel, self.get_object()) files = ContractAttachedFileModel.objects.filter( contract__owners=owner, contents__owner=owner ).select_related("contents") serializer = self.get_serializer(instance=files, many=True) return Response(serializer.data, status.HTTP_200_OK) @extend_schema( summary="Create Contract Files Related to Owner", description="Create Contract Files Related to Owner" ) @action(url_path="files", methods=["GET"], detail=True) def create_file( self, request: HttpRequest, *args: object, **kwargs: object, ) -> Response: owner = cast( ContractOwnerModel, self.get_queryset().select_related("contract") ) if not owner.contract.allow_add_files: raise PermissionDenied(_("Attaching new files was restricted for this contract.")) ser = self.get_serializer(data=request.data) ser.is_valid(raise_exception=True) ser.save() # type: ignore return Response(ser.data, status.HTTP_201_CREATED) class ContractAttachedFileDeleteView(APIView): permission_classes = [AllowAny] @extend_schema( # request=ContractFileDeleteRequestSerializer, responses={204: OpenApiResponse(description="File successfully deleted.")}, 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) class UploadFileContentView(APIView): permission_classes = [AllowAny] parser_classes = [MultiPartParser, FormParser] # type: ignore @extend_schema( summary="Uploads a file for contract attached files", description="Creates a file for contract attached files.", request=CreateContractFileContentFromOwnerSerializer, responses={201: CreateContractFileContentFromOwnerSerializer}, ) def post( self, request: HttpRequest, owner_id: uuid.UUID, file_id: uuid.UUID, *args: object, **kwargs: object ) -> Response: serializer = CreateContractFileContentFromOwnerSerializer( data=request.data, # type: ignore context={ "file_id": file_id, "contract_owner_id": owner_id, } ) serializer.is_valid(raise_exception=True) serializer.save() # type: ignore return Response(serializer.data, status=status.HTTP_201_CREATED)