""" Core views - Health check and utility views """ from django.contrib.auth.decorators import login_required from django.db import connection from django.http import JsonResponse from django.shortcuts import redirect, render from django.views.decorators.cache import never_cache from django.views.decorators.http import require_GET, require_POST @never_cache @require_GET def health_check(request): """ Health check endpoint for monitoring and load balancers. Returns JSON with status of various services. """ health_status = { 'status': 'ok', 'services': {} } # Check database connection try: with connection.cursor() as cursor: cursor.execute("SELECT 1") health_status['services']['database'] = 'ok' except Exception as e: health_status['status'] = 'error' health_status['services']['database'] = f'error: {str(e)}' # Check Redis/Celery (optional - don't fail if not available) try: from django_celery_beat.models import PeriodicTask PeriodicTask.objects.count() health_status['services']['celery_beat'] = 'ok' except Exception: health_status['services']['celery_beat'] = 'not_configured' # Return appropriate status code status_code = 200 if health_status['status'] == 'ok' else 503 return JsonResponse(health_status, status=status_code) @login_required def select_hospital(request): """ Hospital selection page for PX Admins. Allows PX Admins to switch between hospitals. Stores selected hospital in session. """ # Only PX Admins should access this page if not request.user.is_px_admin(): return redirect('dashboard:dashboard') from apps.organizations.models import Hospital hospitals = Hospital.objects.all().order_by('name') # Handle hospital selection if request.method == 'POST': hospital_id = request.POST.get('hospital_id') if hospital_id: try: hospital = Hospital.objects.get(id=hospital_id) request.session['selected_hospital_id'] = str(hospital.id) # Redirect to referring page or dashboard next_url = request.POST.get('next', request.GET.get('next', '/')) return redirect(next_url) except Hospital.DoesNotExist: pass context = { 'hospitals': hospitals, 'selected_hospital_id': request.session.get('selected_hospital_id'), 'next': request.GET.get('next', '/'), } return render(request, 'core/select_hospital.html', context) @login_required def no_hospital_assigned(request): """ Error page for users without a hospital assigned. Users without a hospital assignment cannot access the system. """ return render(request, 'core/no_hospital_assigned.html', status=403) # ============================================================================ # PUBLIC SUBMISSION VIEWS # ============================================================================ @require_GET def public_submit_landing(request): """ Landing page for public submissions. Allows users to choose between Complaint, Observation, or Inquiry. No authentication required. """ from apps.organizations.models import Hospital hospitals = Hospital.objects.all().order_by('name') context = { 'hospitals': hospitals, } return render(request, 'core/public_submit.html', context) @require_POST def public_inquiry_submit(request): """ Handle public inquiry submissions. Creates an inquiry from public submission. Returns JSON response with reference number. """ from apps.complaints.models import Inquiry from apps.organizations.models import Hospital import uuid # Get form data name = request.POST.get('name', '').strip() email = request.POST.get('email', '').strip() phone = request.POST.get('phone', '').strip() hospital_id = request.POST.get('hospital') category = request.POST.get('category', '').strip() subject = request.POST.get('subject', '').strip() message = request.POST.get('message', '').strip() # Validation errors = [] if not name: errors.append('Name is required') if not email: errors.append('Email is required') if not phone: errors.append('Phone number is required') if not hospital_id: errors.append('Hospital selection is required') if not subject: errors.append('Subject is required') if not message: errors.append('Message is required') if errors: return JsonResponse({ 'success': False, 'errors': errors }, status=400) try: # Validate hospital hospital = Hospital.objects.get(id=hospital_id) # Create inquiry (using correct field names from model) inquiry = Inquiry.objects.create( hospital=hospital, contact_name=name, contact_email=email, contact_phone=phone, subject=subject, message=message, category=category, status='open' ) # Generate a simple reference for display reference_number = f"INQ-{str(inquiry.id)[:8].upper()}" # Send notification email (optional) try: from django.core.mail import send_mail from django.conf import settings send_mail( f'New Public Inquiry - {reference_number}', f'Inquiry from {name}\n\nSubject: {subject}\n\nMessage:\n{message}', settings.DEFAULT_FROM_EMAIL, [settings.DEFAULT_FROM_EMAIL], # Send to admin fail_silently=True, ) except Exception: pass # Don't fail if email doesn't send return JsonResponse({ 'success': True, 'reference_number': reference_number, 'inquiry_id': str(inquiry.id) }) except Hospital.DoesNotExist: return JsonResponse({ 'success': False, 'errors': ['Invalid hospital selected'] }, status=400) except Exception as e: return JsonResponse({ 'success': False, 'errors': [str(e)] }, status=500) @require_GET def api_hospitals(request): """ API endpoint to get hospitals list. Used by public submission forms to populate hospital dropdown. """ from apps.organizations.models import Hospital hospitals = Hospital.objects.all().order_by('name').values('id', 'name') return JsonResponse({ 'success': True, 'hospitals': list(hospitals) }) @require_GET def api_observation_categories(request): """ API endpoint to get observation categories list. Used by public observation form to populate category dropdown. """ from apps.observations.models import ObservationCategory categories = ObservationCategory.objects.filter(is_active=True).order_by('sort_order', 'name_en').values('id', 'name_en', 'name_ar') return JsonResponse({ 'success': True, 'categories': list(categories) }) @require_POST def public_observation_submit(request): """ Handle public observation submissions. Creates an observation from public submission. Returns JSON response with tracking code. """ from apps.observations.models import Observation, ObservationAttachment from apps.observations.services import ObservationService import mimetypes # Get form data category_id = request.POST.get('category') severity = request.POST.get('severity', 'medium') title = request.POST.get('title', '').strip() description = request.POST.get('description', '').strip() location_text = request.POST.get('location_text', '').strip() incident_datetime = request.POST.get('incident_datetime', '') reporter_staff_id = request.POST.get('reporter_staff_id', '').strip() reporter_name = request.POST.get('reporter_name', '').strip() reporter_phone = request.POST.get('reporter_phone', '').strip() reporter_email = request.POST.get('reporter_email', '').strip() # Validation errors = [] if not description: errors.append('Description is required') if severity not in ['low', 'medium', 'high', 'critical']: errors.append('Invalid severity selected') if errors: return JsonResponse({ 'success': False, 'errors': errors }, status=400) try: # Get client info def get_client_ip(req): x_forwarded_for = req.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0].strip() else: ip = req.META.get('REMOTE_ADDR') return ip client_ip = get_client_ip(request) user_agent = request.META.get('HTTP_USER_AGENT', '') # Handle file uploads attachments = request.FILES.getlist('attachments') # Create observation using service observation = ObservationService.create_observation( description=description, severity=severity, category_id=category_id if category_id else None, title=title, location_text=location_text, incident_datetime=incident_datetime if incident_datetime else None, reporter_staff_id=reporter_staff_id, reporter_name=reporter_name, reporter_phone=reporter_phone, reporter_email=reporter_email, client_ip=client_ip, user_agent=user_agent, attachments=attachments, ) return JsonResponse({ 'success': True, 'tracking_code': observation.tracking_code, 'observation_id': str(observation.id) }) except Exception as e: return JsonResponse({ 'success': False, 'errors': [str(e)] }, status=500)