Skip to content

Commit a2ee6c1

Browse files
Add certificate download button to course view (#157)
* Initial plan * Add certificate download button to course view Co-authored-by: alexeygrigorev <875246+alexeygrigorev@users.noreply.github.com> * Address code review feedback: add is_authenticated check and test for unauthenticated users Co-authored-by: alexeygrigorev <875246+alexeygrigorev@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: alexeygrigorev <875246+alexeygrigorev@users.noreply.github.com>
1 parent aecf1e1 commit a2ee6c1

3 files changed

Lines changed: 53 additions & 0 deletions

File tree

courses/templates/courses/course.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ <h2>{{ course.title }}</h2>
2323
{% if is_authenticated %}
2424
<a class="btn btn-info" href="{% url 'enrollment' course.slug %}" role="button">Edit course profile</a>
2525
{% endif %}
26+
{% if is_authenticated and certificate_url %}
27+
<a class="btn btn-success" href="{{ certificate_url }}" target="_blank" role="button"><i class="fas fa-certificate"></i> Download Certificate</a>
28+
{% endif %}
2629
</p>
2730
{% if user.is_staff %}
2831
<p>

courses/tests/test_course.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,53 @@ def test_course_view_without_completed_projects(self):
545545
self.assertFalse(response.context["has_completed_projects"])
546546
self.assertNotContains(response, "See all submitted projects")
547547

548+
def test_course_view_with_certificate(self):
549+
"""Test that the course view shows the certificate download button when a certificate is available"""
550+
# Set a certificate URL for the enrollment
551+
self.enrollment.certificate_url = "https://example.com/certificate.pdf"
552+
self.enrollment.save()
553+
554+
self.client.login(**credentials)
555+
response = self.client.get(
556+
reverse("course", args=[self.course.slug])
557+
)
558+
self.assertEqual(response.status_code, 200)
559+
self.assertTemplateUsed(response, "courses/course.html")
560+
self.assertEqual(response.context["certificate_url"], "https://example.com/certificate.pdf")
561+
self.assertContains(response, "Download Certificate")
562+
self.assertContains(response, 'href="https://example.com/certificate.pdf"')
563+
564+
def test_course_view_without_certificate(self):
565+
"""Test that the course view doesn't show the certificate download button when no certificate is available"""
566+
# Ensure no certificate URL is set
567+
self.enrollment.certificate_url = None
568+
self.enrollment.save()
569+
570+
self.client.login(**credentials)
571+
response = self.client.get(
572+
reverse("course", args=[self.course.slug])
573+
)
574+
self.assertEqual(response.status_code, 200)
575+
self.assertTemplateUsed(response, "courses/course.html")
576+
self.assertIsNone(response.context["certificate_url"])
577+
self.assertNotContains(response, "Download Certificate")
578+
579+
def test_course_view_certificate_not_shown_when_not_authenticated(self):
580+
"""Test that the certificate button is not shown to unauthenticated users even if certificate exists"""
581+
# Set a certificate URL for the enrollment
582+
self.enrollment.certificate_url = "https://example.com/certificate.pdf"
583+
self.enrollment.save()
584+
585+
# Don't login - access as unauthenticated user
586+
response = self.client.get(
587+
reverse("course", args=[self.course.slug])
588+
)
589+
self.assertEqual(response.status_code, 200)
590+
self.assertTemplateUsed(response, "courses/course.html")
591+
# certificate_url should be None for unauthenticated users
592+
self.assertIsNone(response.context["certificate_url"])
593+
self.assertNotContains(response, "Download Certificate")
594+
548595
def test_list_all_submissions_view(self):
549596
"""Test the list all submissions view shows submissions in correct order"""
550597
self.client.login(**credentials)

courses/views/course.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,15 @@ def course_view(request: HttpRequest, course_slug: str) -> HttpResponse:
176176
has_completed_projects = True
177177

178178
total_score = None
179+
certificate_url = None
179180
if user.is_authenticated:
180181
try:
181182
enrollment = Enrollment.objects.get(
182183
student=user,
183184
course=course,
184185
)
185186
total_score = enrollment.total_score
187+
certificate_url = enrollment.certificate_url
186188
except Enrollment.DoesNotExist:
187189
pass
188190

@@ -193,6 +195,7 @@ def course_view(request: HttpRequest, course_slug: str) -> HttpResponse:
193195
"has_completed_projects": has_completed_projects,
194196
"is_authenticated": user.is_authenticated,
195197
"total_score": total_score,
198+
"certificate_url": certificate_url,
196199
}
197200

198201
return render(request, "courses/course.html", context)

0 commit comments

Comments
 (0)