Skip to content

Commit 9b65ea3

Browse files
committed
refactor(drivers): add profile and request resources actions for a driver, remove views
1 parent 2e67a5e commit 9b65ea3

File tree

4 files changed

+108
-167
lines changed

4 files changed

+108
-167
lines changed

apps/drivers/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ class Meta:
126126
ordering = ["pk"]
127127
verbose_name = "resource"
128128
verbose_name_plural = "resources"
129+
indexes = [
130+
models.Index(fields=["driver_id", "resource_type"]),
131+
]
129132

130133
def __str__(self):
131134
return f"Resources for {self.driver_id}"

apps/drivers/views.py

Lines changed: 44 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,164 +1,44 @@
1-
"""Views for Drivers App."""
2-
3-
from django.db import transaction
4-
from django.core.cache import cache
5-
from django.shortcuts import get_object_or_404
6-
from rest_framework.views import APIView
7-
from rest_framework.response import Response
8-
from rest_framework import status
9-
from drf_spectacular.utils import extend_schema_view
10-
11-
from apps.utilities.functions import encrypt_field
12-
from apps.users.permissions import IsClient, IsDriver
13-
from apps.users.choices import RoleChoices
14-
from .models import Driver, Resource
15-
from .serializers import (
16-
DriverReadSerializer,
17-
DriverWriteSerializer,
18-
ResourceReadSerializer,
19-
ResourceWriteSerializer,
20-
)
21-
from .schemas import driver_create_schema
22-
23-
24-
class DriverProfileView(APIView):
25-
"""
26-
View to manage the driver profile.
27-
28-
Endpoints:
29-
- GET api/v1/drivers/profile/
30-
- PATCH api/v1/drivers/profile/
31-
- DELETE api/v1/drivers/profile/
32-
"""
33-
34-
permission_classes = [IsDriver]
35-
36-
def get_object(self, request):
37-
# Get a driver instance by user
38-
user = request.user
39-
return get_object_or_404(Driver, user_id=user)
40-
41-
def get(self, request):
42-
# Get driver profile
43-
driver_profile = self.get_object(request)
44-
if driver_profile.is_available:
45-
serializer = DriverReadSerializer(driver_profile)
46-
return Response(serializer.data)
47-
return Response(
48-
{"detail": "Your profile has been deactivated."},
49-
status=status.HTTP_400_BAD_REQUEST,
50-
)
51-
52-
@transaction.atomic
53-
def patch(self, request):
54-
# Update driver profile
55-
driver_profile = self.get_object(request)
56-
57-
if driver_profile.user_id == request.user:
58-
serializer = DriverReadSerializer(
59-
driver_profile, data=request.data, partial=True
60-
)
61-
if serializer.is_valid():
62-
serializer.save()
63-
return Response(serializer.data)
64-
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
65-
return Response(
66-
{"detail": "You are not the owner of this profile."},
67-
status=status.HTTP_403_FORBIDDEN,
68-
)
69-
70-
@transaction.atomic
71-
def delete(self, request):
72-
# Delete driver profile
73-
driver_profile = self.get_object(request)
74-
if driver_profile.user_id == request.user:
75-
driver_profile.is_available = False # Logical deletion
76-
driver_profile.save()
77-
return Response(status=status.HTTP_204_NO_CONTENT)
78-
return Response(
79-
{"detail": "You are not the owner of this profile."},
80-
status=status.HTTP_403_FORBIDDEN,
81-
)
82-
83-
84-
@extend_schema_view(**driver_create_schema)
85-
class DriverCreateView(APIView):
86-
"""
87-
View to create a driver profile.
88-
NOTE: Refactor this
89-
90-
Endpoints:
91-
- POST api/v1/drivers/
92-
"""
93-
94-
permission_classes = [IsClient]
95-
96-
@transaction.atomic
97-
def post(self, request):
98-
# Create a new driver
99-
# Check if the user already has a driver profile
100-
if Driver.objects.filter(user_id=request.user).exists():
101-
return Response(
102-
{"detail": "This user already has a driver profile."},
103-
status=status.HTTP_400_BAD_REQUEST,
104-
)
105-
106-
serializer = DriverWriteSerializer(data=request.data)
107-
if serializer.is_valid():
108-
109-
# Encrypt specific fields after they have been validated
110-
validated_data = serializer.validated_data
111-
validated_data["phone"] = encrypt_field(validated_data["phone"])
112-
validated_data["address"] = encrypt_field(validated_data["address"])
113-
114-
serializer.save(user_id=request.user)
115-
request.user.role = RoleChoices.DRIVER # Update role
116-
request.user.save()
117-
cache.delete(self.cache_key) # Invalidate cache
118-
return Response(serializer.data, status=status.HTTP_201_CREATED)
119-
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
120-
121-
122-
class DriverResourceRequestView(APIView):
123-
"""
124-
View for requesting resources.
125-
126-
Endpoints:
127-
- POST api/v1/resources/request/
128-
"""
129-
130-
permission_classes = [IsDriver]
131-
132-
@transaction.atomic
133-
def post(self, request):
134-
# Submit a resource request
135-
serializer = ResourceWriteSerializer(data=request.data)
136-
serializer.is_valid(raise_exception=True)
137-
driver = get_object_or_404(Driver, user_id=request.user)
138-
serializer.save(driver_id=driver)
139-
return Response(
140-
{"detail": "Request successful."}, status=status.HTTP_201_CREATED
141-
)
142-
143-
144-
class DriverResourceHistoryView(APIView):
145-
"""
146-
View for retrieving a driver's resource history.
147-
148-
Endpoints:
149-
- GET api/v1/drivers/resources/history/
150-
"""
151-
152-
permission_classes = [IsDriver]
153-
154-
def get(self, request, *args, **kwargs):
155-
# Retrieve a driver's resource history
156-
driver = get_object_or_404(Driver, user_id=request.user)
157-
resources = Resource.objects.filter(driver_id=driver)
158-
if not resources:
159-
return Response(
160-
{"detail": "There are no resources available."},
161-
status=status.HTTP_404_NOT_FOUND,
162-
)
163-
serializer = ResourceReadSerializer(resources, many=True)
164-
return Response(serializer.data, status=status.HTTP_200_OK)
1+
# """Views for Drivers App."""
2+
3+
# from django.db import transaction
4+
# from django.core.cache import cache
5+
# from django.shortcuts import get_object_or_404
6+
# from rest_framework.views import APIView
7+
# from rest_framework.response import Response
8+
# from rest_framework import status
9+
# from drf_spectacular.utils import extend_schema_view
10+
11+
# from apps.utilities.functions import encrypt_field
12+
# from apps.users.permissions import IsClient, IsDriver
13+
# from apps.users.choices import RoleChoices
14+
# from .models import Driver, Resource
15+
# from .serializers import (
16+
# DriverReadSerializer,
17+
# DriverWriteSerializer,
18+
# ResourceReadSerializer,
19+
# ResourceWriteSerializer,
20+
# )
21+
# from .schemas import driver_create_schema
22+
23+
24+
# class DriverResourceHistoryView(APIView):
25+
# """
26+
# View for retrieving a driver's resource history.
27+
28+
# Endpoints:
29+
# - GET api/v1/drivers/resources/history/
30+
# """
31+
32+
# permission_classes = [IsDriver]
33+
34+
# def get(self, request, *args, **kwargs):
35+
# # Retrieve a driver's resource history
36+
# driver = get_object_or_404(Driver, user_id=request.user)
37+
# resources = Resource.objects.filter(driver_id=driver)
38+
# if not resources:
39+
# return Response(
40+
# {"detail": "There are no resources available."},
41+
# status=status.HTTP_404_NOT_FOUND,
42+
# )
43+
# serializer = ResourceReadSerializer(resources, many=True)
44+
# return Response(serializer.data, status=status.HTTP_200_OK)

apps/drivers/viewsets.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@
99
from rest_framework import status
1010

1111
from apps.utilities.mixins import ListCacheMixin, LogicalDeleteMixin
12-
from apps.users.permissions import IsSupport, IsClient, IsDriver
12+
from apps.users.permissions import IsSupport, IsClient, IsDriver, IsOwner
1313
from apps.orders.models import Order
1414
from apps.orders.serializers import OrderMinimalSerializer
1515
from apps.deliveries.models import Delivery
16-
from .models import Driver
16+
from .models import Driver, Resource
1717
from .services import DriverService
1818
from .serializers import (
1919
DriverReadSerializer,
2020
DriverWriteSerializer,
2121
DriverMinimalSerializer,
22+
ResourceWriteSerializer,
2223
)
2324

2425

@@ -35,7 +36,7 @@ class DriverViewSet(ListCacheMixin, LogicalDeleteMixin, ModelViewSet):
3536
- DELETE /api/v1/drivers/{id}/
3637
"""
3738

38-
permission_classes = [IsSupport]
39+
permission_classes = [IsSupport, IsOwner]
3940
serializer_class = DriverWriteSerializer
4041
search_fields = ["user_id"]
4142
# filterset_class = DriverFilter
@@ -60,6 +61,28 @@ def get_permissions(self):
6061
def create(self, request, *args, **kwargs):
6162
return DriverService.create_driver(request.user, request.data)
6263

64+
@action(
65+
detail=False,
66+
methods=["get"],
67+
permission_classes=[IsDriver],
68+
url_path="profile",
69+
)
70+
def get_profile(self, request, *args, **kwargs):
71+
"""
72+
Action retrieve a driver profile.
73+
74+
Endpoints:
75+
- GET api/v1/driver/profile/
76+
"""
77+
driver = Driver.objects.get(user_id=request.user)
78+
if driver.is_available:
79+
serializer = DriverReadSerializer(driver)
80+
return Response(serializer.data)
81+
return Response(
82+
{"error": "Your profile has been deactivated."},
83+
status=status.HTTP_400_BAD_REQUEST,
84+
)
85+
6386
@action(
6487
detail=True,
6588
methods=["get"],
@@ -88,6 +111,39 @@ def get_earnings(self, request, *args, **kwargs):
88111
status=status.HTTP_404_NOT_FOUND,
89112
)
90113

114+
@action(
115+
detail=True,
116+
methods=["post"],
117+
permission_classes=[IsDriver],
118+
url_path="request_resources",
119+
)
120+
def request_resources(self, request, *args, **kwargs):
121+
"""
122+
Action for requesting resources.
123+
124+
Endpoints:
125+
- POST api/v1/resources/request/
126+
"""
127+
driver = self.get_object()
128+
129+
# Check if a previous request already exists
130+
if Resource.objects.filter(
131+
driver_id=driver,
132+
resource_type=request.data.get("resource_type"),
133+
).exists():
134+
return Response(
135+
{"error": "You have already requested this resource."},
136+
status=status.HTTP_400_BAD_REQUEST,
137+
)
138+
139+
# Create and validate the request
140+
serializer = ResourceWriteSerializer(data=request.data)
141+
serializer.is_valid(raise_exception=True)
142+
serializer.save(driver_id=driver)
143+
return Response(
144+
{"detail": "Request successful."}, status=status.HTTP_201_CREATED
145+
)
146+
91147
@action(
92148
detail=True,
93149
methods=["patch"],

apps/restaurants/signals.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ def update_restaurant_verification(sender, instance, **kwargs):
1111
"""Signal update the restaurant verification status."""
1212
restaurant = instance.restaurant_id
1313

14+
# ! TODO: Move to services layer
15+
1416
# Count the number of foods for that restaurant
1517
product_count = Food.objects.filter(
1618
restaurant_id=restaurant, is_available=True

0 commit comments

Comments
 (0)