373 lines
15 KiB
Python
373 lines
15 KiB
Python
from django.db.models import Q
|
|
from rest_framework.generics import ListAPIView
|
|
|
|
from fellchensammlung.api.serializers import LocationSerializer, AdoptionNoticeGeoJSONSerializer
|
|
from rest_framework.views import APIView
|
|
from rest_framework.response import Response
|
|
from django.db import transaction
|
|
from fellchensammlung.models import AdoptionNotice, Animal, Log, TrustLevel, Location, AdoptionNoticeStatus
|
|
from fellchensammlung.tasks import post_adoption_notice_save, post_rescue_org_save
|
|
from rest_framework import status
|
|
from rest_framework.permissions import IsAuthenticated
|
|
|
|
from .renderers import GeoJSONRenderer
|
|
from .serializers import (
|
|
AnimalGetSerializer,
|
|
AnimalCreateSerializer,
|
|
RescueOrgeGeoJSONSerializer,
|
|
AdoptionNoticeSerializer,
|
|
ImageCreateSerializer,
|
|
SpeciesSerializer, RescueOrganizationSerializer,
|
|
)
|
|
from fellchensammlung.models import Animal, RescueOrganization, AdoptionNotice, Species, Image
|
|
from drf_spectacular.utils import extend_schema
|
|
|
|
|
|
class AdoptionNoticeApiView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
parameters=[
|
|
{
|
|
'name': 'id',
|
|
'required': False,
|
|
'description': 'ID of the adoption notice to retrieve.',
|
|
'type': int
|
|
},
|
|
],
|
|
responses={200: AdoptionNoticeSerializer(many=True)}
|
|
)
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Retrieve adoption notices with their related animals and images.
|
|
"""
|
|
adoption_notice_id = kwargs.get("id")
|
|
if adoption_notice_id:
|
|
try:
|
|
adoption_notice = AdoptionNotice.objects.get(pk=adoption_notice_id)
|
|
serializer = AdoptionNoticeSerializer(adoption_notice, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
except AdoptionNotice.DoesNotExist:
|
|
return Response({"error": "Adoption notice not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
adoption_notices = AdoptionNotice.objects.all()
|
|
serializer = AdoptionNoticeSerializer(adoption_notices, many=True, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
@transaction.atomic
|
|
@extend_schema(
|
|
request=AdoptionNoticeSerializer,
|
|
responses={201: 'Adoption notice created successfully!'}
|
|
)
|
|
def post(self, request, *args, **kwargs):
|
|
"""
|
|
API view to add an adoption notice.
|
|
"""
|
|
serializer = AdoptionNoticeSerializer(data=request.data, context={'request': request})
|
|
if not serializer.is_valid():
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
adoption_notice = serializer.save(owner=request.user)
|
|
|
|
# Add the location
|
|
post_adoption_notice_save.delay_on_commit(adoption_notice.pk)
|
|
|
|
# Only set active when user has trust level moderator or higher
|
|
if request.user.trust_level >= TrustLevel.MODERATOR:
|
|
adoption_notice.set_active()
|
|
else:
|
|
adoption_notice.set_unchecked()
|
|
|
|
# Log the action
|
|
Log.objects.create(
|
|
user=request.user,
|
|
action="add_adoption_notice",
|
|
text=f"{request.user} added adoption notice {adoption_notice.pk} via API",
|
|
)
|
|
|
|
# Return success response with new adoption notice details
|
|
return Response(
|
|
{"message": "Adoption notice created successfully!", "id": adoption_notice.pk},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
|
|
class AnimalApiView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Get list of animals or a specific animal by ID.
|
|
"""
|
|
animal_id = kwargs.get("id")
|
|
if animal_id:
|
|
try:
|
|
animal = Animal.objects.get(pk=animal_id)
|
|
serializer = AnimalGetSerializer(animal, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
except Animal.DoesNotExist:
|
|
return Response({"error": "Animal not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
animals = Animal.objects.all()
|
|
serializer = AnimalGetSerializer(animals, many=True, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
@transaction.atomic
|
|
def post(self, request, *args, **kwargs):
|
|
"""
|
|
Create a new animal.
|
|
"""
|
|
serializer = AnimalCreateSerializer(data=request.data, context={"request": request})
|
|
if serializer.is_valid():
|
|
animal = serializer.save(owner=request.user)
|
|
return Response(
|
|
{"message": "Animal created successfully!", "id": animal.id},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
class RescueOrganizationApiView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
parameters=[
|
|
{
|
|
'name': 'id',
|
|
'required': False,
|
|
'description': 'ID of the rescue organization to retrieve.',
|
|
'type': int
|
|
},
|
|
{
|
|
'name': 'trusted',
|
|
'required': False,
|
|
'description': 'Filter by trusted status (true/false).',
|
|
'type': bool
|
|
},
|
|
{
|
|
'name': 'external_object_identifier',
|
|
'required': False,
|
|
'description': 'Filter by external object identifier. Use "None" to filter for an empty field',
|
|
'type': str
|
|
},
|
|
{
|
|
'name': 'external_source_identifier',
|
|
'required': False,
|
|
'description': 'Filter by external source identifier. Use "None" to filter for an empty field',
|
|
'type': str
|
|
},
|
|
{
|
|
'name': 'search',
|
|
'required': False,
|
|
'description': 'Search by organization name or location name/city.',
|
|
'type': str
|
|
},
|
|
],
|
|
responses={200: RescueOrganizationSerializer(many=True)}
|
|
)
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Get list of rescue organizations or a specific organization by ID or get a list with available filters for
|
|
- external_object_identifier
|
|
- external_source_identifier
|
|
"""
|
|
org_id = request.query_params.get("id")
|
|
external_object_identifier = request.query_params.get("external_object_identifier")
|
|
external_source_identifier = request.query_params.get("external_source_identifier")
|
|
search_query = request.query_params.get("search")
|
|
|
|
if org_id:
|
|
try:
|
|
organization = RescueOrganization.objects.get(pk=org_id)
|
|
serializer = RescueOrganizationSerializer(organization, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
except RescueOrganization.DoesNotExist:
|
|
return Response({"error": "Organization not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
organizations = RescueOrganization.objects.all()
|
|
|
|
if external_object_identifier:
|
|
if external_object_identifier == "None":
|
|
external_object_identifier = None
|
|
organizations = organizations.filter(external_object_identifier=external_object_identifier)
|
|
|
|
if external_source_identifier:
|
|
if external_source_identifier == "None":
|
|
external_source_identifier = None
|
|
organizations = organizations.filter(external_source_identifier=external_source_identifier)
|
|
if search_query:
|
|
organizations = organizations.filter(
|
|
Q(name__icontains=search_query) |
|
|
Q(location_string__icontains=search_query) |
|
|
Q(location__name__icontains=search_query) |
|
|
Q(location__city__icontains=search_query)
|
|
)
|
|
if organizations.count() == 0:
|
|
return Response({"error": "No organizations found."}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
serializer = RescueOrganizationSerializer(organizations, many=True, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
@transaction.atomic
|
|
@extend_schema(
|
|
request=RescueOrganizationSerializer,
|
|
responses={201: 'Rescue organization created successfully!'}
|
|
)
|
|
def post(self, request, *args, **kwargs):
|
|
"""
|
|
Create or update a rescue organization.
|
|
"""
|
|
serializer = RescueOrganizationSerializer(data=request.data, context={"request": request})
|
|
if serializer.is_valid():
|
|
rescue_org = serializer.save()
|
|
if rescue_org.location is None:
|
|
# Add the location
|
|
post_rescue_org_save.delay_on_commit(rescue_org.pk)
|
|
return Response(
|
|
{"message": "Rescue organization created successfully!", "id": rescue_org.id},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
@transaction.atomic
|
|
@extend_schema(
|
|
request=RescueOrganizationSerializer,
|
|
responses={200: 'Rescue organization updated successfully!'}
|
|
)
|
|
def patch(self, request, *args, **kwargs):
|
|
"""
|
|
Partially update a rescue organization.
|
|
"""
|
|
org_id = request.data.get("id")
|
|
if not org_id:
|
|
return Response({"error": "ID is required for updating."}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
organization = RescueOrganization.objects.get(pk=org_id)
|
|
except RescueOrganization.DoesNotExist:
|
|
return Response({"error": "Organization not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
serializer = RescueOrganizationSerializer(organization, data=request.data, partial=True)
|
|
if serializer.is_valid():
|
|
serializer.save()
|
|
return Response({"message": "Rescue organization updated successfully!"}, status=status.HTTP_200_OK)
|
|
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
class AddImageApiView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@transaction.atomic
|
|
@extend_schema(
|
|
request=ImageCreateSerializer,
|
|
responses={201: 'Image added successfully!'}
|
|
)
|
|
def post(self, request, *args, **kwargs):
|
|
"""
|
|
Add an image to an animal or adoption notice.
|
|
"""
|
|
serializer = ImageCreateSerializer(data=request.data, context={"request": request})
|
|
if serializer.is_valid():
|
|
if serializer.validated_data["attach_to_type"] == "animal":
|
|
object_to_attach_to = Animal.objects.get(id=serializer.validated_data["attach_to"])
|
|
elif serializer.validated_data["attach_to_type"] == "adoption_notice":
|
|
object_to_attach_to = AdoptionNotice.objects.get(id=serializer.validated_data["attach_to"])
|
|
else:
|
|
raise ValueError("Unknown attach_to_type given, should not happen. Check serializer")
|
|
serializer.validated_data.pop('attach_to_type', None)
|
|
serializer.validated_data.pop('attach_to', None)
|
|
image = serializer.save(owner=request.user)
|
|
object_to_attach_to.photos.add(image)
|
|
return Response(
|
|
{"message": "Image added successfully!", "id": image.id},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
class SpeciesApiView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
responses={200: SpeciesSerializer(many=True)}
|
|
)
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Retrieve a list of species.
|
|
"""
|
|
species = Species.objects.all()
|
|
serializer = SpeciesSerializer(species, many=True, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
|
|
class LocationApiView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
parameters=[
|
|
{
|
|
'name': 'id',
|
|
'required': False,
|
|
'description': 'ID of the location to retrieve.',
|
|
'type': int
|
|
},
|
|
],
|
|
responses={200: LocationSerializer(many=True)}
|
|
)
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Retrieve a location
|
|
"""
|
|
location_id = kwargs.get("id")
|
|
if location_id:
|
|
try:
|
|
location = Location.objects.get(pk=location_id)
|
|
serializer = LocationSerializer(location, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
except Location.DoesNotExist:
|
|
return Response({"error": "Location not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
locations = Location.objects.all()
|
|
serializer = LocationSerializer(locations, many=True, context={"request": request})
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
@transaction.atomic
|
|
@extend_schema(
|
|
request=LocationSerializer,
|
|
responses={201: 'Location created successfully!'}
|
|
)
|
|
def post(self, request, *args, **kwargs):
|
|
"""
|
|
API view to add a location
|
|
"""
|
|
serializer = LocationSerializer(data=request.data, context={'request': request})
|
|
if not serializer.is_valid():
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
location = serializer.save()
|
|
|
|
# Log the action
|
|
Log.objects.create(
|
|
user=request.user,
|
|
action="add_location",
|
|
text=f"{request.user} added adoption notice {location.pk} via API",
|
|
)
|
|
|
|
# Return success response with new adoption notice details
|
|
return Response(
|
|
{"message": "Location created successfully!", "id": location.pk},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
|
|
class AdoptionNoticeGeoJSONView(ListAPIView):
|
|
queryset = AdoptionNotice.objects.select_related('location').filter(location__isnull=False).filter(
|
|
adoptionnoticestatus__major_status=AdoptionNoticeStatus.ACTIVE)
|
|
serializer_class = AdoptionNoticeGeoJSONSerializer
|
|
renderer_classes = [GeoJSONRenderer]
|
|
|
|
|
|
class RescueOrgGeoJSONView(ListAPIView):
|
|
queryset = RescueOrganization.objects.select_related('location').filter(location__isnull=False)
|
|
serializer_class = RescueOrgeGeoJSONSerializer
|
|
renderer_classes = [GeoJSONRenderer]
|