from rest_framework.decorators import api_view, permission_classes from rest_framework.response import Response from rest_framework.permissions import AllowAny @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//"), "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//"), "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//"), "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//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//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": "2024-01-15T10:00:00Z", "scheduled_duration": 60} }, "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" } }, "reject_appointment": { "description": "Reject an appointment request (Admin only)", "url": request.build_absolute_uri("/api/meetings/appointments//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" ] }, "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_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' } } })