- Certificate: PDF generated on course completion, download from course page - SCORM: upload ZIP packages as lesson type, served in iframe, manifest parsed - QTI 2.1: export selected/all questions as XML, import QTI files into bank - Uses fpdf2 for certificate PDF generation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
"""Generate PDF completion certificates for courses."""
|
|
import os
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from fpdf import FPDF
|
|
|
|
|
|
def generate_certificate(
|
|
student_name: str,
|
|
course_title: str,
|
|
completed_at: datetime,
|
|
upload_dir: str,
|
|
) -> str:
|
|
"""Generate a PDF certificate and return the file path relative to uploads."""
|
|
cert_dir = os.path.join(upload_dir, "certificates")
|
|
os.makedirs(cert_dir, exist_ok=True)
|
|
|
|
filename = f"cert_{uuid.uuid4().hex[:12]}.pdf"
|
|
filepath = os.path.join(cert_dir, filename)
|
|
|
|
pdf = FPDF(orientation="L", unit="mm", format="A4")
|
|
pdf.set_auto_page_break(auto=False)
|
|
pdf.add_page()
|
|
|
|
w, h = 297, 210 # A4 landscape
|
|
|
|
# Border
|
|
pdf.set_draw_color(26, 86, 219)
|
|
pdf.set_line_width(2)
|
|
pdf.rect(10, 10, w - 20, h - 20)
|
|
pdf.set_line_width(0.5)
|
|
pdf.rect(14, 14, w - 28, h - 28)
|
|
|
|
# Header
|
|
pdf.set_font("Helvetica", "B", 32)
|
|
pdf.set_text_color(26, 86, 219)
|
|
pdf.set_y(35)
|
|
pdf.cell(w, 12, "Certificate of Completion", align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# Decorative line
|
|
pdf.set_draw_color(26, 86, 219)
|
|
pdf.set_line_width(0.8)
|
|
pdf.line(w / 2 - 60, 52, w / 2 + 60, 52)
|
|
|
|
# "This certifies that"
|
|
pdf.set_font("Helvetica", "", 14)
|
|
pdf.set_text_color(100, 100, 100)
|
|
pdf.set_y(62)
|
|
pdf.cell(w, 8, "This certifies that", align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# Student name
|
|
pdf.set_font("Helvetica", "B", 28)
|
|
pdf.set_text_color(30, 30, 30)
|
|
pdf.set_y(75)
|
|
pdf.cell(w, 14, student_name, align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# "has successfully completed"
|
|
pdf.set_font("Helvetica", "", 14)
|
|
pdf.set_text_color(100, 100, 100)
|
|
pdf.set_y(96)
|
|
pdf.cell(w, 8, "has successfully completed the course", align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# Course title
|
|
pdf.set_font("Helvetica", "BI", 22)
|
|
pdf.set_text_color(26, 86, 219)
|
|
pdf.set_y(110)
|
|
pdf.cell(w, 12, course_title, align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# Date
|
|
date_str = completed_at.strftime("%B %d, %Y")
|
|
pdf.set_font("Helvetica", "", 12)
|
|
pdf.set_text_color(100, 100, 100)
|
|
pdf.set_y(135)
|
|
pdf.cell(w, 8, f"Completed on {date_str}", align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# Footer — platform name
|
|
pdf.set_font("Helvetica", "B", 11)
|
|
pdf.set_text_color(26, 86, 219)
|
|
pdf.set_y(160)
|
|
pdf.cell(w, 8, "PedsHub", align="C", new_x="LMARGIN", new_y="NEXT")
|
|
pdf.set_font("Helvetica", "", 9)
|
|
pdf.set_text_color(150, 150, 150)
|
|
pdf.cell(w, 5, "Pediatric Medical Learning Platform", align="C", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
pdf.output(filepath)
|
|
return f"/uploads/certificates/{filename}"
|