Merge pull request 'feature/meetings' (#46) from feature/meetings into main

Reviewed-on: https://gitea.blackbusinesslabs.com/ATTUNE-HEART-THERAPY/alternative-backend-service/pulls/46
This commit is contained in:
Saani 2025-11-27 19:55:12 +00:00
commit 9834777f94
2 changed files with 39 additions and 44 deletions

View File

@ -291,10 +291,8 @@ def api_root(request, format=None):
"user_appointments": { "user_appointments": {
"description": "Get appointments for the authenticated user", "description": "Get appointments for the authenticated user",
"url": request.build_absolute_uri("/api/meetings/user/appointments/"), "url": request.build_absolute_uri("/api/meetings/user/appointments/"),
"methods": ["GET", "POST"], "methods": ["GET"],
"authentication": "Required", "authentication": "Required",
"request_fields": ["email"],
"example_request": {"email": "saanii929@gmail.com"},
"response": "List of user's appointment requests with enhanced availability data" "response": "List of user's appointment requests with enhanced availability data"
}, },
"schedule_appointment": { "schedule_appointment": {
@ -364,9 +362,8 @@ def api_root(request, format=None):
"user_appointment_stats": { "user_appointment_stats": {
"description": "Get appointment statistics for a specific user", "description": "Get appointment statistics for a specific user",
"url": request.build_absolute_uri("/api/meetings/user/appointments/stats/"), "url": request.build_absolute_uri("/api/meetings/user/appointments/stats/"),
"methods": ["POST"], "methods": ["GET"],
"authentication": "Required", "authentication": "Required",
"required_fields": ["email"],
"response_fields": { "response_fields": {
"total_requests": "Total number of appointment requests", "total_requests": "Total number of appointment requests",
"pending_review": "Number of pending review requests", "pending_review": "Number of pending review requests",
@ -379,6 +376,7 @@ def api_root(request, format=None):
} }
}, },
"availability_system": { "availability_system": {
"description": "Flexible day-time availability management", "description": "Flexible day-time availability management",
"features": [ "features": [

View File

@ -20,6 +20,7 @@ from .serializers import (
from .email_service import EmailService from .email_service import EmailService
from users.models import CustomUser from users.models import CustomUser
from django.db.models import Count, Q from django.db.models import Count, Q
import hashlib
class AdminAvailabilityView(generics.RetrieveUpdateAPIView): class AdminAvailabilityView(generics.RetrieveUpdateAPIView):
@ -237,31 +238,19 @@ class UserAppointmentsView(generics.ListAPIView):
serializer_class = AppointmentRequestSerializer serializer_class = AppointmentRequestSerializer
def get_queryset(self): def get_queryset(self):
user_email = self.request.user.email.lower()
all_appointments = list(AppointmentRequest.objects.all())
matching_appointments = [
apt for apt in all_appointments
if apt.email and apt.email.lower() == user_email
]
appointment_ids = [apt.id for apt in matching_appointments]
return AppointmentRequest.objects.filter( return AppointmentRequest.objects.filter(
email=self.request.user.email id__in=appointment_ids
).order_by('-created_at') ).order_by('-created_at')
def post(self, request, *args, **kwargs):
email = request.data.get('email')
if not email:
return Response(
{"error": "Email is required"},
status=status.HTTP_400_BAD_REQUEST
)
if email != request.user.email:
return Response(
{"error": "You can only view your own appointments"},
status=status.HTTP_403_FORBID_REQUEST
)
appointments = AppointmentRequest.objects.filter(email__iexact=email).order_by('-created_at')
serializer = self.get_serializer(appointments, many=True)
return Response(serializer.data)
class AppointmentStatsView(generics.GenericAPIView): class AppointmentStatsView(generics.GenericAPIView):
permission_classes = [IsAuthenticated, IsAdminUser] permission_classes = [IsAuthenticated, IsAdminUser]
@ -291,26 +280,34 @@ class AppointmentStatsView(generics.GenericAPIView):
'available_days_count': days_with_availability if availability else 0 'available_days_count': days_with_availability if availability else 0
}) })
class UserAppointmentStatsView(generics.GenericAPIView): class UserAppointmentStatsView(generics.GenericAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
serializer_class = AppointmentRequestSerializer
def post(self, request): def get_queryset(self):
email = request.data.get('email', self.request.user.email) user_email = self.request.user.email.lower()
all_appointments = list(AppointmentRequest.objects.all())
if not self.request.user.is_staff and email != self.request.user.email: matching_appointments = [
return Response( apt for apt in all_appointments
{'error': 'You can only view your own statistics'}, if apt.email and apt.email.lower() == user_email
status=status.HTTP_403_FORBIDDEN ]
) appointment_ids = [apt.id for apt in matching_appointments]
return AppointmentRequest.objects.filter(
id__in=appointment_ids
)
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
appointments = AppointmentRequest.objects.filter(email__iexact=email)
stats = { stats = {
'total': appointments.count(), 'total': queryset.count(),
'pending': appointments.filter(status='pending_review').count(), 'pending': queryset.filter(status='pending_review').count(),
'scheduled': appointments.filter(status='scheduled').count(), 'scheduled': queryset.filter(status='scheduled').count(),
'rejected': appointments.filter(status='rejected').count(), 'rejected': queryset.filter(status='rejected').count(),
'completed': appointments.filter(status='completed').count(), 'completed': queryset.filter(status='completed').count(),
} }
total = stats['total'] total = stats['total']
@ -324,9 +321,9 @@ class UserAppointmentStatsView(generics.GenericAPIView):
'rejected': stats['rejected'], 'rejected': stats['rejected'],
'completed': stats['completed'], 'completed': stats['completed'],
'completion_rate': completion_rate, 'completion_rate': completion_rate,
'email': email 'email': request.user.email
}) })
class MatchingAvailabilityView(generics.GenericAPIView): class MatchingAvailabilityView(generics.GenericAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]