- Certificate model: serial_number (unique), status (pending/rendering/completed/failed),
pdf_path, pdf_hash (SHA-256), verification_url, render_attempts, training_record FK
- renderer.py: LaTeX template → pdflatex subprocess → PDF; _escape_latex for XSS safety;
compute_pdf_hash for immutable verification metadata
- services.py: issue_certificate() generates serial, creates record, enqueues Celery task
- tasks.py: render_certificate_task (bind=True, autoretry 3x with 60s backoff);
sets RENDERING → COMPLETED with hash; FAILED with error on all retries exhausted
- API: /certificates/ (own list), /certificates/{id}/ (own detail)
- 15 unit + integration tests: hash consistency, LaTeX escaping, mocked render, retry behavior
Co-Authored-By: Paperclip <noreply@paperclip.ing>
13 lines
461 B
Python
13 lines
461 B
Python
from django.contrib import admin
|
|
|
|
from .models import Certificate
|
|
|
|
|
|
@admin.register(Certificate)
|
|
class CertificateAdmin(admin.ModelAdmin):
|
|
list_display = ("serial_number", "user", "course", "status", "issued_at", "render_attempts")
|
|
list_filter = ("status",)
|
|
search_fields = ("serial_number", "user__email", "course__title")
|
|
readonly_fields = ("pdf_hash", "pdf_path", "issued_at", "render_attempts", "render_error")
|
|
raw_id_fields = ("user",)
|