from __future__ import annotations import json from typing import Any, Dict from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect from django.views import View from django.views.generic.detail import SingleObjectMixin from inertia import render from labs.models import CertificateIssuance from labs.tasks.certificate import generate_certificate_issuance_pdf_task from .base import PermissionRequiredAdminMixin class CertificateIssuanceDetailView( PermissionRequiredAdminMixin, SingleObjectMixin, View ): model = CertificateIssuance permission_required = "labs.view_certificateissuance" component = "certificate-issuances/Detail" def get_queryset(self): return self.model._default_manager.select_related( "cert_type", "recipient", "recipient__user" ) def serialize_issuance(self, issuance: CertificateIssuance) -> Dict[str, Any]: has_file = bool(issuance.file_object_key) return { "id": issuance.id, "cert_number": issuance.cert_number, "issued_at": issuance.issued_at.isoformat(), "source": { "value": issuance.source, "label": CertificateIssuance.Source(issuance.source).name, }, "tlms_course_id": issuance.tlms_course_id, "cert_type": { "id": issuance.cert_type_id, "name": issuance.cert_type.name, "short_name": issuance.cert_type.short_name, }, "cert_type_has_template": bool(issuance.cert_type.template), "recipient": { "id": issuance.recipient_id, "first_name": issuance.recipient.first_name, "last_name": issuance.recipient.last_name, "email": issuance.recipient.email, "email_verified": issuance.recipient.email_verified, "country": issuance.recipient.country, "company_name": issuance.recipient.company_name, "user_id": issuance.recipient.user_id, "external_user_info": issuance.recipient.external_user_info or {}, }, "file": { "storage_provider": issuance.file_storage_provider, "bucket": issuance.file_bucket, "object_key": issuance.file_object_key, "content_type": issuance.file_content_type, "status": "ready" if has_file else "pending", "public_url": issuance.get_file_public_url() if has_file else None, }, "cert_snapshot": issuance.cert_snapshot or {}, "cert_snapshot_pretty": json.dumps( issuance.cert_snapshot or {}, ensure_ascii=False, indent=2, sort_keys=True ), } def get(self, request: HttpRequest, pk: int) -> HttpResponse: self.object = self.get_object() return render( request, self.component, { "issuance": self.serialize_issuance(self.object), }, ) class CertificateIssuanceRegeneratePdfView(PermissionRequiredAdminMixin, View): permission_required = "labs.change_certificateissuance" def post(self, request: HttpRequest, pk: int) -> HttpResponse: issuance = ( CertificateIssuance.objects.select_related("cert_type", "recipient") .filter(id=pk) .first() ) if not issuance: request.session["flash_error"] = "Certificate issuance not found." return redirect("/admin/certificates/") if not issuance.cert_type.template: request.session["flash_error"] = ( "Cannot regenerate PDF: certificate type template is empty." ) return redirect(f"/admin/certificate-issuances/{pk}/") if issuance.source == CertificateIssuance.Source.TLMS: request.session["flash_error"] = ( "Cannot regenerate PDF for TLMS-synced issuances." ) return redirect(f"/admin/certificate-issuances/{pk}/") generate_certificate_issuance_pdf_task.apply_async(args=[issuance.id]) request.session["flash_success"] = "PDF regeneration task queued." next_url = request.POST.get("next", "") if next_url.startswith("/admin/"): return redirect(next_url) return redirect(f"/admin/certificate-issuances/{pk}/")