Files
training-software/certificates/tasks.py
Paperclip CTO 7e7e094fb7
Some checks failed
CI / lint (push) Successful in 6s
CI / test (push) Failing after 26s
CI / build-container (push) Has been skipped
fix(tests): unblock sqlite CI failures in mocks, helpers, and legacy cms route
2026-05-18 15:05:47 +02:00

57 lines
2.0 KiB
Python

from celery import shared_task
from .models import Certificate, CertificateStatus
from .renderer import RenderError, compute_pdf_hash, render_certificate_pdf
from .services import get_pdf_storage_path
@shared_task(
name="certificates.render_certificate",
bind=True,
autoretry_for=(Exception,),
retry_kwargs={"max_retries": 3, "countdown": 60},
)
def render_certificate_task(self, certificate_id: str):
"""
Async task: render a certificate PDF, compute its hash, and persist the result.
Retried up to 3 times on failure with 60s delay.
"""
from django.utils.timezone import now
try:
cert = Certificate.objects.select_related("user", "course").get(pk=certificate_id)
except Certificate.DoesNotExist:
return {"error": f"Certificate {certificate_id} not found"}
cert.status = CertificateStatus.RENDERING
cert.render_attempts += 1
cert.save(update_fields=["status", "render_attempts", "updated_at"])
context = {
"recipient_name": getattr(cert.user, "display_name", "") or cert.user.email,
"course_title": cert.course.title,
"issued_date": now().strftime("%B %d, %Y"),
"serial_number": cert.serial_number,
"verification_url": cert.verification_url,
}
output_path = get_pdf_storage_path(cert)
try:
render_certificate_pdf(context, output_path)
pdf_hash = compute_pdf_hash(output_path)
except RenderError as exc:
cert.status = CertificateStatus.FAILED
cert.render_error = str(exc)
cert.save(update_fields=["status", "render_error", "updated_at"])
raise # triggers Celery retry
cert.status = CertificateStatus.COMPLETED
cert.pdf_path = output_path
cert.pdf_hash = pdf_hash
cert.issued_at = now()
cert.render_error = ""
cert.save(update_fields=["status", "pdf_path", "pdf_hash", "issued_at", "render_error", "updated_at"])
return {"certificate_id": certificate_id, "serial": cert.serial_number, "hash": pdf_hash}