Skip to content

Add certificate PDF download to Certificate page#61

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/add-certificate-download-functionality
Draft

Add certificate PDF download to Certificate page#61
Copilot wants to merge 2 commits intomainfrom
copilot/add-certificate-download-functionality

Conversation

Copy link
Contributor

Copilot AI commented Mar 16, 2026

The Certificate page showed only a certificate ID with no way to download or share it. This adds a GET /api/certificates/{certificateId}/download endpoint and a frontend Download PDF button with full loading/error UX.

Backend

  • ICertificateService / CertificateService — new DownloadCertificatePdfAsync(Guid) method; generates a valid PDF using pure C# (no new dependencies) with Latin1-safe escaping, 60-char name truncation, and ISO 8601 UTC timestamps
  • CertificatesController (new) — three endpoints:
    • GET /api/certificates/{id} — fetch by ID
    • GET /api/certificates/search?studentName= — search (already referenced in HomeController HTML)
    • GET /api/certificates/{certificateId}/download — streams application/pdf with Content-Disposition: attachment
  • Program.cs — registers ICertificateService → CertificateService

Frontend

  • certificate.js — adds downloading/downloadError state; handleDownload calls the download endpoint via axios blob response, creates a temporary anchor to trigger browser download, and surfaces 404 vs. network errors distinctly
  • certificate.css (new) — button and error styles; button color (#4c51bf) meets WCAG AA contrast

Tests

Five new xUnit tests in CertificateServiceDownloadTests: valid ID returns bytes, %PDF- header present, invalid/empty GUID returns null, PDF content contains expected student/course details.

// New endpoint
[HttpGet("{certificateId:guid}/download")]
public async Task<IActionResult> DownloadCertificate(Guid certificateId)
{
    var pdfBytes = await _certificateService.DownloadCertificatePdfAsync(certificateId);
    if (pdfBytes == null) return NotFound(new { message = "Certificate not found" });
    return File(pdfBytes, "application/pdf", $"certificate-{certificateId}.pdf");
}
Original prompt

This section details on the original issue you should resolve

<issue_title>Add certificate download functionality to Certificate page</issue_title>
<issue_description>Currently, the Certificate page allows users to view the certificate ID, but there is no feature to download a digital version of the certificate. For a comprehensive user experience and to support verification or sharing, it is important to allow users to download their certificates.

Proposed enhancement:

  • Implement a 'Download PDF' button on the Certificate page.
  • When clicked, the button should initiate a request to a backend endpoint (e.g., /api/certificates/:certificateId/download).
  • The API should return a PDF (or specified file type) of the certificate for the given certificate ID.
  • Initiate a file download on successfully receiving the file from the backend. Show appropriate messaging on errors.
  • Ensure that the certificateId is validated/encoded and error handling is present on the frontend.
  • (Optional) Style the button and error states for better user experience.

Benefits:

  • Improves usability by letting users securely retain or send proof of course completion.
  • Standardizes certificate management for end users.

Acceptance criteria:

  • Button visible when certificate ID is present.
  • Download is successful for valid IDs and appropriate error is shown if the download fails.
  • UI reflects loading and error states.</issue_description>

Comments on the Issue (you are @copilot in this section)


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.


You can also share your feedback on Copilot code review. Take the survey.

Co-authored-by: Hemavathi15sg <224925058+Hemavathi15sg@users.noreply.github.com>
Copilot AI changed the title [WIP] Add certificate download functionality to Certificate page Add certificate PDF download to Certificate page Mar 16, 2026
Copilot AI requested a review from Hemavathi15sg March 16, 2026 05:59
public async Task<ActionResult<IEnumerable<CertificateDto>>> SearchCertificates(
[FromQuery] string studentName = "")
{
_logger.LogInformation("Searching certificates for student name: {StudentName}", studentName);

Check failure

Code scanning / CodeQL

Log entries created from user input High

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 10 days ago

In general, to fix this kind of issue, all user-provided data that is written into log messages should be sanitized to remove or encode characters that could alter the log structure (notably \r and \n). For plain-text logs, removing newline characters is usually sufficient; for HTML logs, HTML-encoding should be used. Since this controller likely writes to plain-text/structured logs, the minimal non-breaking fix is to create a sanitized version of studentName with line breaks removed and use that sanitized variable in the log call, leaving the underlying business logic (GetCertificatesByStudentNameAsync) unchanged.

Concretely, in api/CourseRegistration.API/Controllers/CertificatesController.cs, within the SearchCertificates action, we’ll introduce a local variable (e.g., sanitizedStudentName) that replaces any \r and \n characters with empty strings (or otherwise strips them) before passing it to _logger.LogInformation. The rest of the method will continue to use the original studentName for validation and searching to avoid altering functional behavior. No new using directives or external dependencies are needed; we can use string.Replace from the BCL. The change is localized around line 59: add the sanitization line immediately before the log call and change the log call to use the sanitized variable.

Suggested changeset 1
api/CourseRegistration.API/Controllers/CertificatesController.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/CourseRegistration.API/Controllers/CertificatesController.cs b/api/CourseRegistration.API/Controllers/CertificatesController.cs
--- a/api/CourseRegistration.API/Controllers/CertificatesController.cs
+++ b/api/CourseRegistration.API/Controllers/CertificatesController.cs
@@ -56,8 +56,13 @@
     public async Task<ActionResult<IEnumerable<CertificateDto>>> SearchCertificates(
         [FromQuery] string studentName = "")
     {
-        _logger.LogInformation("Searching certificates for student name: {StudentName}", studentName);
+        var sanitizedStudentName = studentName?
+            .Replace(Environment.NewLine, string.Empty)
+            .Replace("\n", string.Empty)
+            .Replace("\r", string.Empty);
 
+        _logger.LogInformation("Searching certificates for student name: {StudentName}", sanitizedStudentName);
+
         if (string.IsNullOrWhiteSpace(studentName))
         {
             return BadRequest(new { message = "Student name is required" });
EOF
@@ -56,8 +56,13 @@
public async Task<ActionResult<IEnumerable<CertificateDto>>> SearchCertificates(
[FromQuery] string studentName = "")
{
_logger.LogInformation("Searching certificates for student name: {StudentName}", studentName);
var sanitizedStudentName = studentName?
.Replace(Environment.NewLine, string.Empty)
.Replace("\n", string.Empty)
.Replace("\r", string.Empty);

_logger.LogInformation("Searching certificates for student name: {StudentName}", sanitizedStudentName);

if (string.IsNullOrWhiteSpace(studentName))
{
return BadRequest(new { message = "Student name is required" });
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add certificate download functionality to Certificate page

3 participants