329 lines
9.9 KiB
Python
329 lines
9.9 KiB
Python
"""
|
|
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)
|