415 lines
16 KiB
Python
415 lines
16 KiB
Python
from django.db.models import Q
|
|
from django.shortcuts import get_object_or_404
|
|
from drf_spectacular.utils import extend_schema, inline_serializer
|
|
|
|
from rest_framework import serializers, status
|
|
from rest_framework.pagination import LimitOffsetPagination
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.utils import json
|
|
from rest_framework.views import APIView
|
|
|
|
from common import swagger_params
|
|
from common.models import Document, Profile, Teams
|
|
from common.permissions import HasOrgContext
|
|
from common.serializer import (
|
|
DocumentCreateSerializer,
|
|
DocumentCreateSwaggerSerializer,
|
|
DocumentEditSwaggerSerializer,
|
|
DocumentSerializer,
|
|
ProfileSerializer,
|
|
)
|
|
|
|
|
|
class DocumentListView(APIView, LimitOffsetPagination):
|
|
permission_classes = (IsAuthenticated, HasOrgContext)
|
|
model = Document
|
|
|
|
def get_context_data(self, **kwargs):
|
|
params = self.request.query_params
|
|
queryset = self.model.objects.filter(org=self.request.profile.org).order_by(
|
|
"-id"
|
|
)
|
|
if self.request.user.is_superuser or self.request.profile.role == "ADMIN":
|
|
queryset = queryset
|
|
else:
|
|
if self.request.profile.documents():
|
|
doc_ids = self.request.profile.documents().values_list("id", flat=True)
|
|
shared_ids = queryset.filter(
|
|
Q(status="active") & Q(shared_to__id__in=[self.request.profile.id])
|
|
).values_list("id", flat=True)
|
|
queryset = queryset.filter(Q(id__in=doc_ids) | Q(id__in=shared_ids))
|
|
else:
|
|
queryset = queryset.filter(
|
|
Q(status="active") & Q(shared_to__id__in=[self.request.profile.id])
|
|
)
|
|
|
|
request_post = params
|
|
if request_post:
|
|
if request_post.get("title"):
|
|
queryset = queryset.filter(title__icontains=request_post.get("title"))
|
|
if request_post.get("status"):
|
|
queryset = queryset.filter(status=request_post.get("status"))
|
|
|
|
if request_post.get("shared_to"):
|
|
queryset = queryset.filter(
|
|
shared_to__id__in=json.loads(request_post.get("shared_to"))
|
|
)
|
|
|
|
context = {}
|
|
profile_list = Profile.objects.filter(
|
|
is_active=True, org=self.request.profile.org
|
|
)
|
|
if self.request.profile.role == "ADMIN" or self.request.profile.is_admin:
|
|
profiles = profile_list.order_by("user__email")
|
|
else:
|
|
profiles = profile_list.filter(role="ADMIN").order_by("user__email")
|
|
search = False
|
|
if (
|
|
params.get("document_file")
|
|
or params.get("status")
|
|
or params.get("shared_to")
|
|
):
|
|
search = True
|
|
context["search"] = search
|
|
|
|
queryset_documents_active = queryset.filter(status="active")
|
|
results_documents_active = self.paginate_queryset(
|
|
queryset_documents_active.distinct(), self.request, view=self
|
|
)
|
|
documents_active = DocumentSerializer(results_documents_active, many=True).data
|
|
if results_documents_active:
|
|
offset = queryset_documents_active.filter(
|
|
id__gte=results_documents_active[-1].id
|
|
).count()
|
|
if offset == queryset_documents_active.count():
|
|
offset = None
|
|
else:
|
|
offset = 0
|
|
context["documents_active"] = {
|
|
"documents_active_count": self.count,
|
|
"documents_active": documents_active,
|
|
"offset": offset,
|
|
}
|
|
|
|
queryset_documents_inactive = queryset.filter(status="inactive")
|
|
results_documents_inactive = self.paginate_queryset(
|
|
queryset_documents_inactive.distinct(), self.request, view=self
|
|
)
|
|
documents_inactive = DocumentSerializer(
|
|
results_documents_inactive, many=True
|
|
).data
|
|
if results_documents_inactive:
|
|
offset = queryset_documents_inactive.filter(
|
|
id__gte=results_documents_active[-1].id
|
|
).count()
|
|
if offset == queryset_documents_inactive.count():
|
|
offset = None
|
|
else:
|
|
offset = 0
|
|
context["documents_inactive"] = {
|
|
"documents_inactive_count": self.count,
|
|
"documents_inactive": documents_inactive,
|
|
"offset": offset,
|
|
}
|
|
|
|
context["users"] = ProfileSerializer(profiles, many=True).data
|
|
context["status_choices"] = Document.DOCUMENT_STATUS_CHOICE
|
|
return context
|
|
|
|
@extend_schema(
|
|
tags=["documents"],
|
|
operation_id="documents_list",
|
|
parameters=swagger_params.document_get_params,
|
|
responses={
|
|
200: inline_serializer(
|
|
name="DocumentListResponse",
|
|
fields={
|
|
"search": serializers.BooleanField(),
|
|
"documents_active": serializers.DictField(),
|
|
"documents_inactive": serializers.DictField(),
|
|
"users": ProfileSerializer(many=True),
|
|
"status_choices": serializers.ListField(),
|
|
},
|
|
)
|
|
},
|
|
)
|
|
def get(self, request, *args, **kwargs):
|
|
context = self.get_context_data(**kwargs)
|
|
return Response(context)
|
|
|
|
@extend_schema(
|
|
tags=["documents"],
|
|
operation_id="documents_create",
|
|
parameters=swagger_params.organization_params,
|
|
request=DocumentCreateSwaggerSerializer,
|
|
responses={
|
|
201: inline_serializer(
|
|
name="DocumentCreateResponse",
|
|
fields={
|
|
"error": serializers.BooleanField(),
|
|
"message": serializers.CharField(),
|
|
},
|
|
)
|
|
},
|
|
)
|
|
def post(self, request, *args, **kwargs):
|
|
params = request.data
|
|
serializer = DocumentCreateSerializer(data=params, request_obj=request)
|
|
if serializer.is_valid():
|
|
doc = serializer.save(
|
|
created_by=request.profile.user,
|
|
org=request.profile.org,
|
|
document_file=request.FILES.get("document_file"),
|
|
)
|
|
if params.get("shared_to"):
|
|
assinged_to_list = params.get("shared_to")
|
|
profiles = Profile.objects.filter(
|
|
id__in=assinged_to_list, org=request.profile.org, is_active=True
|
|
)
|
|
if profiles:
|
|
doc.shared_to.add(*profiles)
|
|
if params.get("teams"):
|
|
teams_list = params.get("teams")
|
|
teams = Teams.objects.filter(id__in=teams_list, org=request.profile.org)
|
|
if teams:
|
|
doc.teams.add(*teams)
|
|
|
|
return Response(
|
|
{"error": False, "message": "Document Created Successfully"},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
return Response(
|
|
{"error": True, "errors": serializer.errors},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
|
|
|
|
class DocumentDetailView(APIView):
|
|
permission_classes = (IsAuthenticated, HasOrgContext)
|
|
|
|
def get_object(self, pk):
|
|
# Security fix: Filter by org to prevent cross-org enumeration
|
|
return get_object_or_404(Document, id=pk, org=self.request.profile.org)
|
|
|
|
@extend_schema(
|
|
tags=["documents"],
|
|
operation_id="documents_retrieve",
|
|
parameters=swagger_params.organization_params,
|
|
responses={
|
|
200: inline_serializer(
|
|
name="DocumentDetailResponse",
|
|
fields={
|
|
"doc_obj": DocumentSerializer(),
|
|
"file_type_code": serializers.CharField(),
|
|
"users": ProfileSerializer(many=True),
|
|
},
|
|
)
|
|
},
|
|
)
|
|
def get(self, request, pk, format=None):
|
|
# get_object_or_404 now handles org filtering - returns 404 if not found/wrong org
|
|
self.object = self.get_object(pk)
|
|
if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser:
|
|
if not (
|
|
(self.request.profile == self.object.created_by)
|
|
or (self.request.profile in self.object.shared_to.all())
|
|
):
|
|
return Response(
|
|
{
|
|
"error": True,
|
|
"errors": "You do not have Permission to perform this action",
|
|
},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
profile_list = Profile.objects.filter(org=self.request.profile.org)
|
|
if request.profile.role == "ADMIN" or request.user.is_superuser:
|
|
profiles = profile_list.order_by("user__email")
|
|
else:
|
|
profiles = profile_list.filter(role="ADMIN").order_by("user__email")
|
|
context = {}
|
|
context.update(
|
|
{
|
|
"doc_obj": DocumentSerializer(self.object).data,
|
|
"file_type_code": self.object.file_type()[1],
|
|
"users": ProfileSerializer(profiles, many=True).data,
|
|
}
|
|
)
|
|
return Response(context, status=status.HTTP_200_OK)
|
|
|
|
@extend_schema(
|
|
tags=["documents"],
|
|
operation_id="documents_destroy",
|
|
parameters=swagger_params.organization_params,
|
|
responses={
|
|
200: inline_serializer(
|
|
name="DocumentDeleteResponse",
|
|
fields={
|
|
"error": serializers.BooleanField(),
|
|
"message": serializers.CharField(),
|
|
},
|
|
)
|
|
},
|
|
)
|
|
def delete(self, request, pk, format=None):
|
|
document = self.get_object(pk)
|
|
if not document:
|
|
return Response(
|
|
{"error": True, "errors": "Documdnt does not exist"},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
if document.org != self.request.profile.org:
|
|
return Response(
|
|
{"error": True, "errors": "User company doesnot match with header...."},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
|
|
if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser:
|
|
if (
|
|
self.request.profile != document.created_by
|
|
): # or (self.request.profile not in document.shared_to.all()):
|
|
return Response(
|
|
{
|
|
"error": True,
|
|
"errors": "You do not have Permission to perform this action",
|
|
},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
document.delete()
|
|
return Response(
|
|
{"error": False, "message": "Document deleted Successfully"},
|
|
status=status.HTTP_200_OK,
|
|
)
|
|
|
|
@extend_schema(
|
|
tags=["documents"],
|
|
operation_id="documents_update",
|
|
parameters=swagger_params.organization_params,
|
|
request=DocumentEditSwaggerSerializer,
|
|
responses={
|
|
200: inline_serializer(
|
|
name="DocumentUpdateResponse",
|
|
fields={
|
|
"error": serializers.BooleanField(),
|
|
"message": serializers.CharField(),
|
|
},
|
|
)
|
|
},
|
|
)
|
|
def put(self, request, pk, format=None):
|
|
self.object = self.get_object(pk)
|
|
params = request.data
|
|
if not self.object:
|
|
return Response(
|
|
{"error": True, "errors": "Document does not exist"},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
if self.object.org != self.request.profile.org:
|
|
return Response(
|
|
{"error": True, "errors": "User company doesnot match with header...."},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser:
|
|
if not (
|
|
(self.request.profile == self.object.created_by)
|
|
or (self.request.profile in self.object.shared_to.all())
|
|
):
|
|
return Response(
|
|
{
|
|
"error": True,
|
|
"errors": "You do not have Permission to perform this action",
|
|
},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
serializer = DocumentCreateSerializer(
|
|
data=params, instance=self.object, request_obj=request
|
|
)
|
|
if serializer.is_valid():
|
|
doc = serializer.save(
|
|
document_file=request.FILES.get("document_file"),
|
|
status=params.get("status"),
|
|
org=request.profile.org,
|
|
)
|
|
doc.shared_to.clear()
|
|
if params.get("shared_to"):
|
|
assinged_to_list = params.get("shared_to")
|
|
profiles = Profile.objects.filter(
|
|
id__in=assinged_to_list, org=request.profile.org, is_active=True
|
|
)
|
|
if profiles:
|
|
doc.shared_to.add(*profiles)
|
|
|
|
doc.teams.clear()
|
|
if params.get("teams"):
|
|
teams_list = params.get("teams")
|
|
teams = Teams.objects.filter(id__in=teams_list, org=request.profile.org)
|
|
if teams:
|
|
doc.teams.add(*teams)
|
|
return Response(
|
|
{"error": False, "message": "Document Updated Successfully"},
|
|
status=status.HTTP_200_OK,
|
|
)
|
|
return Response(
|
|
{"error": True, "errors": serializer.errors},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
|
|
@extend_schema(
|
|
tags=["documents"],
|
|
parameters=swagger_params.organization_params,
|
|
request=DocumentEditSwaggerSerializer,
|
|
description="Partial Document Update",
|
|
responses={
|
|
200: inline_serializer(
|
|
name="DocumentPatchResponse",
|
|
fields={
|
|
"error": serializers.BooleanField(),
|
|
"message": serializers.CharField(),
|
|
},
|
|
)
|
|
},
|
|
)
|
|
def patch(self, request, pk, format=None):
|
|
"""Handle partial updates to a document."""
|
|
self.object = self.get_object(pk)
|
|
params = request.data
|
|
if not self.object:
|
|
return Response(
|
|
{"error": True, "errors": "Document does not exist"},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
if self.object.org != self.request.profile.org:
|
|
return Response(
|
|
{
|
|
"error": True,
|
|
"errors": "User company does not match with header....",
|
|
},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
if self.request.profile.role != "ADMIN" and not self.request.user.is_superuser:
|
|
if not (
|
|
(self.request.profile == self.object.created_by)
|
|
or (self.request.profile in self.object.shared_to.all())
|
|
):
|
|
return Response(
|
|
{
|
|
"error": True,
|
|
"errors": "You do not have Permission to perform this action",
|
|
},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
serializer = DocumentCreateSerializer(
|
|
data=params, instance=self.object, request_obj=request, partial=True
|
|
)
|
|
if serializer.is_valid():
|
|
doc = serializer.save(
|
|
org=request.profile.org,
|
|
)
|
|
return Response(
|
|
{"error": False, "message": "Document Updated Successfully"},
|
|
status=status.HTTP_200_OK,
|
|
)
|
|
return Response(
|
|
{"error": True, "errors": serializer.errors},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|