""" Configuration Console UI views - System configuration management """ import json from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.template.loader import render_to_string from django.conf import settings from django.utils.translation import gettext_lazy as _ from apps.organizations.models import Department, Hospital from apps.px_action_center.models import PXActionSLAConfig, RoutingRule from apps.complaints.models import OnCallAdminSchedule from apps.callcenter.models import CallRecord from apps.notifications.services import NotificationService from apps.accounts.services import PasswordResetTokenService from apps.core.decorators import px_admin_required, admin_required from apps.accounts.models import User @px_admin_required def config_dashboard(request): """Configuration dashboard - overview of system settings - PX Admin only""" # Get counts sla_configs_count = PXActionSLAConfig.objects.filter(is_active=True).count() routing_rules_count = RoutingRule.objects.filter(is_active=True).count() hospitals_count = Hospital.objects.filter(status="active").count() oncall_schedules_count = OnCallAdminSchedule.objects.filter(is_active=True).count() call_records_count = CallRecord.objects.count() provisional_users_count = User.objects.filter(is_provisional=True).count() active_users_count = User.objects.filter(is_active=True, is_superuser=False, is_provisional=False).count() context = { "sla_configs_count": sla_configs_count, "routing_rules_count": routing_rules_count, "hospitals_count": hospitals_count, "oncall_schedules_count": oncall_schedules_count, "call_records_count": call_records_count, "provisional_users_count": provisional_users_count, "active_users_count": active_users_count, } return render(request, "config/dashboard.html", context) @px_admin_required def sla_config_list(request): """SLA configurations list view - PX Admin only""" queryset = PXActionSLAConfig.objects.select_related("hospital", "department") # Apply filters hospital_filter = request.GET.get("hospital") if hospital_filter: queryset = queryset.filter(hospital_id=hospital_filter) is_active = request.GET.get("is_active") if is_active == "true": queryset = queryset.filter(is_active=True) elif is_active == "false": queryset = queryset.filter(is_active=False) # Ordering queryset = queryset.order_by("hospital", "name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get hospitals for filter hospitals = Hospital.objects.filter(status="active") context = { "page_obj": page_obj, "sla_configs": page_obj.object_list, "hospitals": hospitals, "filters": request.GET, } return render(request, "config/sla_config.html", context) @px_admin_required def routing_rules_list(request): """Routing rules list view - PX Admin only""" queryset = RoutingRule.objects.select_related("hospital", "department", "assign_to_user", "assign_to_department") # Apply filters hospital_filter = request.GET.get("hospital") if hospital_filter: queryset = queryset.filter(hospital_id=hospital_filter) is_active = request.GET.get("is_active") if is_active == "true": queryset = queryset.filter(is_active=True) elif is_active == "false": queryset = queryset.filter(is_active=False) # Ordering queryset = queryset.order_by("-priority", "name") # Pagination page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) # Get hospitals for filter hospitals = Hospital.objects.filter(status="active") context = { "page_obj": page_obj, "routing_rules": page_obj.object_list, "hospitals": hospitals, "filters": request.GET, } return render(request, "config/routing_rules.html", context) @admin_required def hospital_users_list(request): """Hospital users list view - PX Admin and Hospital Admin""" queryset = User.objects.select_related("hospital", "department").filter(is_superuser=False, is_provisional=False) if not request.user.is_px_admin(): if request.tenant_hospital: queryset = queryset.filter(hospital=request.tenant_hospital) else: queryset = queryset.none() hospital_filter = request.GET.get("hospital") if hospital_filter: queryset = queryset.filter(hospital_id=hospital_filter) role_filter = request.GET.get("role") if role_filter: queryset = queryset.filter(groups__name=role_filter) is_active = request.GET.get("is_active") if is_active == "true": queryset = queryset.filter(is_active=True) elif is_active == "false": queryset = queryset.filter(is_active=False) search_query = request.GET.get("search") if search_query: queryset = queryset.filter( Q(first_name__icontains=search_query) | Q(last_name__icontains=search_query) | Q(email__icontains=search_query) | Q(employee_id__icontains=search_query) ) queryset = queryset.order_by("-date_joined") page_size = int(request.GET.get("page_size", 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get("page", 1) page_obj = paginator.get_page(page_number) if request.user.is_px_admin(): hospitals = Hospital.objects.filter(status="active").order_by("name") elif request.tenant_hospital: hospitals = Hospital.objects.filter(id=request.tenant_hospital.id) else: hospitals = Hospital.objects.none() from django.contrib.auth.models import Group roles = Group.objects.all().order_by("name") total_users = paginator.count active_count = queryset.filter(is_active=True).count() inactive_count = queryset.filter(is_active=False).count() context = { "page_obj": page_obj, "users": page_obj.object_list, "hospitals": hospitals, "roles": roles, "filters": request.GET, "total_users": total_users, "active_count": active_count, "inactive_count": inactive_count, } return render(request, "config/hospital_users.html", context) @admin_required def user_create(request): """Create a new user from the config console""" from apps.accounts.forms import UserCreateForm if not request.user.is_px_admin() and not request.user.is_hospital_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden(_("You don't have permission to create users.")) if request.method == "POST": form = UserCreateForm(request.POST, request=request) if form.is_valid(): user = form.save() generated_password = getattr(form, '_generated_password', None) staff_id = request.POST.get("staff_id") if staff_id: from apps.organizations.models import Staff try: staff = Staff.objects.get(pk=staff_id, user__isnull=True) staff.user = user staff.save(update_fields=["user"]) messages.success(request, _("User '{}' created and linked to staff '{}'.").format( user.get_full_name(), staff.first_name + " " + staff.last_name )) except Staff.DoesNotExist: messages.success(request, _("User '{}' created successfully.").format(user.get_full_name())) else: messages.success(request, _("User '{}' created successfully.").format(user.get_full_name())) try: base_url = f"{request.scheme}://{request.get_host()}" reset_token = PasswordResetTokenService.create_reset_token(user) reset_url = PasswordResetTokenService.build_reset_url(base_url, reset_token) if generated_password: html_message = render_to_string( "config/emails/user_created_email.html", {"user": user, "reset_url": reset_url, "temp_password": generated_password}, request=request, ) plain_message = ( f"Dear {user.get_full_name()},\n\n" f"An account has been created for you on PX360.\n\n" f"Your temporary password: {generated_password}\n\n" f"For security, please set your own password using the link below:\n{reset_url}\n\n" f"This link expires in 24 hours." ) subject = _("Your PX360 Account Has Been Created") else: html_message = render_to_string( "config/emails/reset_password_email.html", {"user": user, "reset_url": reset_url}, request=request, ) plain_message = ( f"Dear {user.get_full_name()},\n\n" f"An account has been created for you on PX360.\n\n" f"Use the link below to set your password:\n{reset_url}\n\n" f"This link expires in 24 hours." ) subject = _("Your PX360 Account Has Been Created") NotificationService.send_email( email=user.email, subject=subject, message=plain_message, html_message=html_message, user=user, notification_type="system", ) if generated_password: messages.info(request, _("Credentials sent to {}.").format(user.email)) else: messages.info(request, _("Password setup link sent to {}.").format(user.email)) except Exception as e: messages.warning(request, _("User created but email sending failed: {}").format(str(e))) return redirect("config:hospital_users_list") else: form = UserCreateForm(request=request) context = {"form": form} return render(request, "config/user_form.html", context) @admin_required def user_edit(request, user_id): """Edit an existing user from the config console""" from apps.accounts.forms import UserEditForm target_user = get_object_or_404(User, pk=user_id, is_superuser=False, is_provisional=False) if not request.user.is_px_admin(): if request.tenant_hospital and target_user.hospital != request.tenant_hospital: from django.http import HttpResponseForbidden return HttpResponseForbidden(_("You can only edit users in your hospital.")) if request.method == "POST": form = UserEditForm(request.POST, instance=target_user, request=request) if form.is_valid(): form.save() messages.success(request, _("User '{}' updated successfully.").format(target_user.get_full_name())) return redirect("config:hospital_users_list") else: form = UserEditForm(instance=target_user, request=request) context = {"form": form, "edit_user": target_user} return render(request, "config/user_form.html", context) @admin_required def reset_user_password(request, user_id): """Reset a user's password and send them the new credentials via email.""" if request.method != "POST": return JsonResponse({"error": "Method not allowed"}, status=405) target_user = get_object_or_404(User, pk=user_id, is_superuser=False) if not request.user.is_px_admin(): if request.tenant_hospital and target_user.hospital != request.tenant_hospital: return JsonResponse({"error": "You can only reset passwords for users in your hospital."}, status=403) if target_user.is_provisional: return JsonResponse({"error": "Use the onboarding invitation flow for provisional users."}, status=400) base_url = f"{request.scheme}://{request.get_host()}" reset_token = PasswordResetTokenService.create_reset_token(target_user) reset_url = PasswordResetTokenService.build_reset_url(base_url, reset_token) html_message = render_to_string( "config/emails/reset_password_email.html", { "user": target_user, "reset_url": reset_url, }, request=request, ) plain_message = ( f"Dear {target_user.get_full_name()},\n\n" f"Your PX360 password has been reset by an administrator.\n\n" f"For your security, no password is sent by email. Use the link below to set a new password:\n" f"{reset_url}\n\n" f"This link expires in 24 hours. If you did not expect this reset, contact your system administrator." ) NotificationService.send_email( email=target_user.email, subject=_("Your PX360 Password Has Been Reset"), message=plain_message, html_message=html_message, user=target_user, notification_type="system", ) return JsonResponse( { "success": True, "message": f"Password reset link has been sent to {target_user.email}.", "user_name": target_user.get_full_name(), "user_email": target_user.email, } ) from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods from rich import print from django.contrib.auth.hashers import check_password as verify_password @admin_required def toggle_user_active(request, user_id): if request.method != "POST": return JsonResponse({"error": "Method not allowed"}, status=405) target_user = get_object_or_404(User, pk=user_id, is_superuser=False, is_provisional=False) if not request.user.is_px_admin(): return JsonResponse({"error": "Only PX Admins can activate/deactivate users."}, status=403) data = json.loads(request.body) if request.body else {} password = data.get("password", "") if not verify_password(password, request.user.password): return JsonResponse({"error": "Incorrect password. Please try again."}, status=400) target_user.is_active = not target_user.is_active target_user.save(update_fields=["is_active"]) status_label = "activated" if target_user.is_active else "deactivated" return JsonResponse( { "success": True, "is_active": target_user.is_active, "message": f"User {target_user.get_full_name()} has been {status_label}.", "user_name": target_user.get_full_name(), } ) @csrf_exempt @require_http_methods(["POST"]) def test(request): import json from django.http import JsonResponse print(json.loads(request.body)) return JsonResponse({"status": "ok"}) @login_required def deleted_items(request): """View deleted items across all models - PX Admin only""" if not request.user.is_px_admin(): from django.http import HttpResponseForbidden return HttpResponseForbidden(_("You don't have permission to view deleted items.")) from apps.complaints.models import Complaint, Inquiry from apps.observations.models import Observation from apps.appreciation.models import Appreciation deleted_complaints = Complaint.all_objects.filter(is_deleted=True).select_related( "hospital", "department", "created_by" ).order_by("-deleted_at") deleted_observations = Observation.all_objects.filter(is_deleted=True).select_related( "hospital", "assigned_department" ).order_by("-deleted_at") deleted_inquiries = Inquiry.all_objects.filter(is_deleted=True).select_related( "hospital", "department" ).order_by("-deleted_at") deleted_appreciations = Appreciation.all_objects.filter(is_deleted=True).select_related( "hospital", "sender" ).order_by("-deleted_at") return render(request, "config/deleted_items.html", { "deleted_complaints": deleted_complaints, "deleted_observations": deleted_observations, "deleted_inquiries": deleted_inquiries, "deleted_appreciations": deleted_appreciations, })