HH/apps/core/views.py
2026-01-06 18:26:17 +03:00

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)