alternative-backend-service/booking_system/views.py

637 lines
32 KiB
Python
Raw Permalink Normal View History

from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from django.utils import timezone
@api_view(['GET'])
@permission_classes([AllowAny])
def api_root(request, format=None):
base_url = request.build_absolute_uri('/api/')
endpoints = {
'contact': {
'description': 'Contact form submission endpoint',
'base_path': '/api/auth/',
'endpoints': {
'contact': {
'description': 'Submit a contact form',
'url': request.build_absolute_uri('/api/auth/contact/'),
'methods': ['POST'],
'required_fields': ['name', 'email', 'phone', 'message'],
'example_request': {
'name': 'John Doe',
'email': 'n8E5I@example.com',
'phone': '+1234567890',
'message': 'Hello, how can I help you?'
}
}
},
},
'authentication': {
'description': 'User authentication and management endpoints',
'base_path': '/api/auth/',
'endpoints': {
'register': {
'description': 'Register a new user and send verification OTP',
'url': request.build_absolute_uri('/api/auth/register/'),
'methods': ['POST'],
'required_fields': ['email', 'first_name', 'last_name', 'password', 'password2'],
'example_request': {
'email': 'saanii929@gmail',
'first_name': 'Saani',
'last_name': 'Iddi',
'phone_number': '+233552732025',
'password': 'SecurePassword123',
'password2': 'SecurePassword123'
}
},
'verify_otp': {
'description': 'Verify email address using OTP',
'url': request.build_absolute_uri('/api/auth/verify-otp/'),
'methods': ['POST'],
'required_fields': ['email', 'otp'],
'example_request': {
'email': 'saanii929@gmail',
'otp': '123456'
}
},
'login': {
'description': 'Authenticate user and return JWT tokens',
'url': request.build_absolute_uri('/api/auth/login/'),
'methods': ['POST'],
'required_fields': ['email', 'password'],
'example_request': {
'email': 'saanii929@gmail',
'password': 'SecurePassword123'
}
},
'resend_otp': {
'description': 'Resend OTP for email verification or password reset',
'url': request.build_absolute_uri('/api/auth/resend-otp/'),
'methods': ['POST'],
'required_fields': ['email'],
'optional_fields': ['context (registration/password_reset)'],
'example_request': {
'email': 'saanii929@gmail',
'context': 'registration'
}
},
'forgot_password': {
'description': 'Initiate password reset process',
'url': request.build_absolute_uri('/api/auth/forgot-password/'),
'methods': ['POST'],
'required_fields': ['email'],
'example_request': {
'email': 'saanii929@gmail'
}
},
'verify_password_reset_otp': {
'description': 'Verify OTP for password reset',
'url': request.build_absolute_uri('/api/auth/verify-password-reset-otp/'),
'methods': ['POST'],
'required_fields': ['email', 'otp'],
'example_request': {
'email': 'saanii929@gmail',
'otp': '123456'
}
},
'reset_password': {
'description': 'Reset password after OTP verification',
'url': request.build_absolute_uri('/api/auth/reset-password/'),
'methods': ['POST'],
'required_fields': ['email', 'otp', 'new_password', 'confirm_password'],
'example_request': {
'email': 'saanii929@gmail',
'otp': '123456',
'new_password': 'NewSecurePassword123',
'confirm_password': 'NewSecurePassword123'
}
},
'token_refresh': {
'description': 'Refresh access token using refresh token',
'url': request.build_absolute_uri('/api/auth/token/refresh/'),
'methods': ['POST'],
'required_fields': ['refresh'],
'example_request': {
'refresh': 'your_refresh_token_here'
}
},
"update_profile": {
"description": "Update user profile (Authenticated users only)",
"url": request.build_absolute_uri("/api/auth/profile/update/"),
"methods": ["PATCH"],
"authentication": "Required (Authenticated users only)",
"required_fields": ["first_name", "last_name", "phone_number"],
"example_request": {
"first_name": "Saani",
"last_name": "Iddi",
"phone_number": "+233552732025"
}
},
"get_profile": {
"description": "Get user profile (Authenticated users only)",
"url": request.build_absolute_uri("/api/auth/profile/"),
"methods": ["GET"],
"authentication": "Required (Authenticated users only)",
"response_fields": {
"user": "User object"
}
},
"all-users": {
"description": "Get all users (Admin only)",
"url": request.build_absolute_uri("/api/auth/all-users/"),
"methods": ["GET"],
"authentication": "Required (Admin users only)",
"response_fields": {
"users": "List of user objects"
}
},
"activate-deactivate-user": {
"description": "Activate or deactivate a user (Admin only)",
"url": request.build_absolute_uri("/api/auth/activate-deactivate-user/<uuid:pk>/"),
"methods": ["GET"],
"authentication": "Required (Admin users only)",
"response_fields": {
"user": "User object"
}
},
"delete-user": {
"description": "Delete a user (Admin only)",
"url": request.build_absolute_uri("/api/auth/delete-user/<uuid:pk>/"),
"methods": ["GET"],
"authentication": "Required (Admin users only)",
"response_fields": {
"user": "User object"
}
}
}
},
"appointments": {
"description": "Appointment request and management system with Jitsi video meetings and flexible availability",
"base_path": "/api/meetings/",
"endpoints": {
"admin_availability": {
"description": "Get or update admin weekly availability with day-time combinations (Admin only)",
"url": request.build_absolute_uri("/api/meetings/admin/availability/"),
"methods": ["GET", "PUT", "PATCH"],
"authentication": "Required (Staff users only)",
"response_fields": {
"availability_schedule": "Dictionary with days as keys and time slots as values",
"availability_schedule_display": "Human-readable availability schedule",
"all_available_slots": "All available day-time combinations"
},
"example_request": {
"availability_schedule": {
"0": ["morning", "evening"],
"1": ["morning", "afternoon"],
"3": ["afternoon", "evening"]
}
}
},
"availability_config": {
"description": "Get availability configuration for frontend (Public)",
"url": request.build_absolute_uri("/api/meetings/availability/config/"),
"methods": ["GET"],
"authentication": "None required",
"response": "Default availability configuration with all days and time slots"
},
"check_date_availability": {
"description": "Check available time slots for a specific date (Public)",
"url": request.build_absolute_uri("/api/meetings/availability/check/"),
"methods": ["POST"],
"authentication": "None required",
"required_fields": ["date (YYYY-MM-DD)"],
"example_request": {
"date": "2024-01-15"
},
"response_fields": {
"date": "The checked date",
"day_name": "Day of the week",
"available_slots": "List of available time slots",
"available_slots_display": "Human-readable time slots",
"is_available": "Boolean indicating if any slots are available"
}
},
"weekly_availability": {
"description": "Get complete weekly availability overview (Public)",
"url": request.build_absolute_uri("/api/meetings/availability/weekly/"),
"methods": ["GET"],
"authentication": "None required",
"response": "Array of days with their available time slots for the entire week"
},
"availability_overview": {
"description": "Get public availability overview and next available dates (Public)",
"url": request.build_absolute_uri("/api/meetings/availability/overview/"),
"methods": ["GET"],
"authentication": "None required",
"response_fields": {
"available": "Boolean indicating if admin has any availability",
"total_available_slots": "Total number of available day-time slots",
"available_days": "List of days with availability",
"next_available_dates": "Next 7 days with availability information"
}
},
"available_dates": {
"description": "Get available appointment dates with time slots for the next 30 days (Public)",
"url": request.build_absolute_uri("/api/meetings/appointments/available-dates/"),
"methods": ["GET"],
"authentication": "None required",
"response": "List of available dates with their available time slots"
},
"create_appointment": {
"description": "Create a new appointment request with availability validation (Public)",
"url": request.build_absolute_uri("/api/meetings/appointments/create/"),
"methods": ["POST"],
"authentication": "Required (User only)",
"required_fields": [
"first_name", "last_name", "email",
"selected_slots"
],
"optional_fields": ["phone", "reason"],
"validation": [
"Selected slots must match admin availability",
"At least one time slot must be selected"
],
"example_request": {
"first_name": "Shani",
"last_name": "Iddi",
"email": "saanii929@gmail.com",
"phone": "+233552732025",
"reason": "Therapy session",
"selected_slots": [
{"day": 1, "time_slot": "morning"},
{"day": 1, "time_slot": "afternoon"},
{"day": 3, "time_slot": "afternoon"},
{"day": 3, "time_slot": "evening"},
{"day": 4, "time_slot": "evening"}
]
},
"response_includes": {
"appointment_id": "UUID of the created appointment",
"message": "Success message"
}
},
"list_appointments": {
"description": "List appointment requests (Admin sees all, users see their own)",
"url": request.build_absolute_uri("/api/meetings/appointments/"),
"methods": ["GET"],
"authentication": "Required",
"response_fields": {
"jitsi_meet_url": "Jitsi meeting URL (only for scheduled appointments)",
"jitsi_room_id": "Jitsi room ID",
"has_jitsi_meeting": "Boolean indicating if meeting is created",
"can_join_meeting": "Boolean indicating if meeting can be joined now",
"meeting_status": "Current meeting status",
"matching_availability": "Date-time combinations that match admin availability",
"are_preferences_available": "Boolean indicating if preferences match availability"
}
},
"appointment_detail": {
"description": "Get detailed information about a specific appointment",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/"),
"methods": ["GET"],
"authentication": "Required",
"url_parameter": "pk (UUID of the appointment)",
"response_includes": "Jitsi meeting information and availability matching data"
},
"matching_availability": {
"description": "Get matching availability for a specific appointment request",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/matching-availability/"),
"methods": ["GET"],
"authentication": "Required",
"response_fields": {
"appointment_id": "UUID of the appointment",
"preferences_match_availability": "Boolean indicating if preferences match",
"matching_slots": "List of date-time combinations that match",
"total_matching_slots": "Number of matching combinations"
}
},
"user_appointments": {
"description": "Get appointments for the authenticated user",
"url": request.build_absolute_uri("/api/meetings/user/appointments/"),
"methods": ["GET"],
"authentication": "Required",
"response": "List of user's appointment requests with enhanced availability data"
},
"schedule_appointment": {
"description": "Schedule an appointment and automatically create Jitsi meeting (Admin only)",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/schedule/"),
"methods": ["POST"],
"authentication": "Required (Staff users only)",
"required_fields": ["scheduled_datetime"],
"optional_fields": ["scheduled_duration", "date_str", "time_slot"],
"prerequisites": "Appointment must be in 'pending_review' status",
"scheduling_options": {
"direct_datetime": {
"example": {
"scheduled_datetime": "2025-12-05T10:30:00Z",
"scheduled_duration": 30,
"timezone": timezone.get_current_timezone_name(),
"create_jitsi_meeting": "true"
}
},
"date_and_slot": {
"example": {"date_str": "2024-01-15", "time_slot": "morning", "scheduled_duration": 60}
}
},
"validation": "Validates against admin availability when using date_str + time_slot",
"side_effects": [
"Updates status to 'scheduled'",
"Automatically generates Jitsi meeting room",
"Creates unique Jitsi room ID and URL",
"Sends confirmation email to user with meeting link",
"Clears rejection reason if any"
],
"response_includes": {
"jitsi_meet_url": "Generated Jitsi meeting URL",
"jitsi_room_id": "Unique Jitsi room ID",
"has_jitsi_meeting": "true"
}
},
"reschedule_appointment": {
"description": "Reschedule an existing appointment (Admin only)",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/reschedule/"),
"methods": ["POST"],
"authentication": "Required (Staff users only)",
"required_fields": ["scheduled_datetime"],
"optional_fields": ["scheduled_duration", "date_str", "time_slot"],
"prerequisites": "Appointment must be in 'scheduled' status",
"scheduling_options": {
"direct_datetime": {
"example": {
"scheduled_datetime": "2025-12-10T11:00:00Z",
"scheduled_duration": 45,
"timezone": timezone.get_current_timezone_name()
}
},
"date_and_slot": {
"example": {"date_str": "2024-01-20", "time_slot": "afternoon", "scheduled_duration": 60}
}
},
"validation": "Validates against admin availability when using date_str + time_slot",
"side_effects": [
"Updates scheduled_datetime and scheduled_duration",
"Clears Jitsi meeting information",
"Sends rescheduled email to user"
]
},
"reject_appointment": {
"description": "Reject an appointment request (Admin only)",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/reject/"),
"methods": ["POST"],
"authentication": "Required (Staff users only)",
"optional_fields": ["rejection_reason"],
"prerequisites": "Appointment must be in 'pending_review' status",
"example_request": {
"rejection_reason": "No availability for preferred dates"
},
"side_effects": [
"Updates status to 'rejected'",
"Clears Jitsi meeting information",
"Sends rejection email to user",
"Clears scheduled datetime if any"
]
},
"start_meeting": {
"description": "Start the Jitsi meeting for a scheduled appointment",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/start/"),
"methods": ["POST"],
"authentication": "Required",
"prerequisites": "Appointment must be in 'scheduled' status",
"side_effects": [
"Updates meeting status to 'active'",
"Allows participants to join the meeting"
]
},
"end_meeting": {
"description": "End the Jitsi meeting for a scheduled appointment",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/end/"),
"methods": ["POST"],
"authentication": "Required",
"prerequisites": "Appointment must be in 'scheduled' or 'active' status",
"side_effects": [
"Updates meeting status to 'completed'",
"Clears Jitsi meeting information",
"Sends completion email to user"
]
},
"cancel_meeting": {
"description": "Cancel a scheduled appointment and its Jitsi meeting",
"url": request.build_absolute_uri("/api/meetings/appointments/<uuid:pk>/cancel/"),
"methods": ["POST"],
"authentication": "Required",
"prerequisites": "Appointment must be in 'scheduled' or 'active' status",
"side_effects": [
"Updates meeting status to 'cancelled'",
"Clears Jitsi meeting information",
"Sends cancellation email to user",
]
},
"appointment_stats": {
"description": "Get appointment statistics and analytics with availability metrics (Admin only)",
"url": request.build_absolute_uri("/api/meetings/appointments/stats/"),
"methods": ["GET"],
"authentication": "Required (Staff users only)",
"response_fields": {
"total_requests": "Total number of appointment requests",
"pending_review": "Number of pending review requests",
"scheduled": "Number of scheduled appointments",
"rejected": "Number of rejected requests",
"completed": "Number of completed appointments",
"completion_rate": "Percentage of requests that were scheduled",
"availability_coverage": "Percentage of week covered by availability",
"available_days_count": "Number of days with availability set"
}
},
"user_appointment_stats": {
"description": "Get appointment statistics for a specific user",
"url": request.build_absolute_uri("/api/meetings/user/appointments/stats/"),
"methods": ["GET"],
"authentication": "Required",
"response_fields": {
"total_requests": "Total number of appointment requests",
"pending_review": "Number of pending review requests",
"scheduled": "Number of scheduled appointments",
"rejected": "Number of rejected requests",
"completed": "Number of completed appointments",
"completion_rate": "Percentage of requests that were scheduled",
"email": "User email address"
}
}
},
"availability_system": {
"description": "Flexible day-time availability management",
"features": [
"Different time slots for each day of the week",
"Real-time availability validation",
"Matching preference detection",
"Weekly availability overview"
],
"time_slots": {
"morning": "Morning (9AM - 12PM)",
"afternoon": "Afternoon (1PM - 5PM)",
"evening": "Evening (6PM - 9PM)"
},
"days_of_week": {
"0": "Monday",
"1": "Tuesday",
"2": "Wednesday",
"3": "Thursday",
"4": "Friday",
"5": "Saturday",
"6": "Sunday"
}
},
"jitsi_integration": {
"description": "Automatic Jitsi video meeting integration",
"features": [
"Automatic meeting room generation when appointment is scheduled",
"Unique room IDs for each therapy session",
"No setup required for clients - just click and join",
"Meeting availability based on scheduled time",
"Secure, encrypted video sessions"
],
"meeting_lifecycle": {
"pending": "No Jitsi meeting created",
"scheduled": "Jitsi meeting automatically generated with unique URL",
"active": "Meeting can be joined 10 minutes before scheduled time",
"completed": "Meeting ends 15 minutes after scheduled duration"
},
"join_conditions": [
"Appointment must be in 'scheduled' status",
"Current time must be within 10 minutes before to 15 minutes after scheduled end",
"Both client and therapist can join using the same URL"
]
}
}
}
return Response({
'message': 'Therapy Appointment API with Enhanced Availability System',
'version': '2.0.0',
'base_url': base_url,
'new_features': [
'Flexible day-time availability management',
'Real-time availability validation',
'Matching preference detection',
'Enhanced scheduling options',
'Availability statistics and coverage metrics'
],
'project_structure': {
'admin': '/admin/ - Django admin interface',
'authentication': '/api/auth/ - User authentication and management',
'appointments': '/api/meetings/ - Enhanced appointment booking system'
},
'endpoints': endpoints,
'appointment_workflows': {
'client_booking_flow': [
'1. GET /api/meetings/availability/weekly/ - Check weekly availability',
'2. POST /api/meetings/availability/check/ - Check specific date availability',
'3. GET /api/meetings/appointments/available-dates/ - See next available dates',
'4. POST /api/meetings/appointments/create/ - Submit appointment request',
'5. GET /api/meetings/user/appointments/ - Track request status',
'6. GET /api/meetings/appointments/{id}/matching-availability/ - See matching options',
'7. Receive email notification when scheduled/rejected'
],
'admin_management_flow': [
'1. PUT /api/meetings/admin/availability/ - Set flexible day-time availability',
'2. GET /api/meetings/appointments/ - Review pending requests',
'3. GET /api/meetings/appointments/stats/ - Check availability coverage',
'4. POST /api/meetings/appointments/{id}/schedule/ - Schedule with date+slot OR direct datetime',
'5. POST /api/meetings/appointments/{id}/reject/ - Reject with reason'
],
'status_lifecycle': [
'pending_review → scheduled (with datetime)',
'pending_review → rejected (with optional reason)',
'scheduled → completed (after meeting)',
'scheduled → cancelled (if needed)'
]
},
'availability_examples': {
'monday_evening_only': {
"availability_schedule": {
"0": ["evening"]
}
},
'weekday_mornings_afternoons': {
"availability_schedule": {
"0": ["morning", "afternoon"],
"1": ["morning", "afternoon"],
"2": ["morning", "afternoon"],
"3": ["morning", "afternoon"],
"4": ["morning", "afternoon"]
}
},
'flexible_schedule': {
"availability_schedule": {
"0": ["morning", "evening"],
"1": ["afternoon"],
"3": ["morning", "afternoon"],
"5": ["morning"]
}
}
},
'quick_start': {
'for_users': [
'1. Register: POST /api/auth/register/',
'2. Verify email: POST /api/auth/verify-otp/',
'3. Login: POST /api/auth/login/',
'4. Check weekly availability: GET /api/meetings/availability/weekly/',
'5. Check specific date: POST /api/meetings/availability/check/',
'6. Book appointment: POST /api/meetings/appointments/create/'
],
'for_admins': [
'1. Login to Django admin: /admin/',
'2. Set flexible availability: PUT /api/meetings/admin/availability/',
'3. Check availability coverage: GET /api/meetings/appointments/stats/',
'4. Manage appointments: GET /api/meetings/appointments/',
'5. Schedule/Reject: Use specific appointment endpoints'
]
},
'data_specifications': {
'appointment': {
'status_choices': [
'pending_review - Initial state, awaiting admin action',
'scheduled - Approved with specific date/time',
'rejected - Not accepted, with optional reason',
'completed - Meeting has been completed',
'cancelled - Appointment was cancelled'
],
'time_slot_choices': [
'morning - 9AM to 12PM',
'afternoon - 1PM to 5PM',
'evening - 6PM to 9PM'
],
'preferred_dates_format': 'YYYY-MM-DD (array of strings)',
'encrypted_fields': [
'first_name', 'last_name', 'email', 'phone',
'reason', 'rejection_reason'
]
},
'availability': {
'day_format': '0=Monday, 1=Tuesday, ..., 6=Sunday',
'time_slot_format': 'morning, afternoon, evening',
'schedule_format': 'Dictionary: {"0": ["morning", "evening"], "1": ["afternoon"]}'
}
},
'authentication_notes': {
'token_usage': 'Include JWT token in Authorization header: Bearer <token>',
'token_refresh': 'Use refresh token to get new access token when expired',
'permissions': {
'public_endpoints': 'No authentication required (availability checks, overview)',
'user_endpoints': 'Valid JWT token required',
'admin_endpoints': 'Staff user with valid JWT token required'
}
}
})