Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions django_email_learning/personalised/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
QuestionResponse,
)
from django_email_learning.services import jwt_service
from django.utils.translation import gettext as _
from django_email_learning.models import (
ContentDelivery,
QuizSubmission,
Expand Down Expand Up @@ -79,7 +80,7 @@ def post(self, request, *args, **kwargs): # type: ignore[no-untyped-def]
delivery.update_hash()

if passed:
message = "Congratulations! You have passed the quiz."
message = _("Congratulations! You have passed the quiz.")
delivery = delivery.schedule_next_delivery()
if not delivery:
enrolment.graduate()
Expand All @@ -91,14 +92,18 @@ def post(self, request, *args, **kwargs): # type: ignore[no-untyped-def]
).count()

if failed_submissions_count > 1:
message = "You have failed the quiz twice. Unfortunatly you can not continue the course on this enrollment. But you can enroll again to retake the course."
message = _(
"You have failed the quiz twice. Unfortunatly you can not continue the course on this enrollment. But you can enroll again to retake the course."
)
logger.info(
f"Learner ID {enrolment.learner.id} has failed the quiz twice for Course {enrolment.course.title}. "
f"Marking enrollment as failed."
)
enrolment.fail()
else:
message = "You have failed the quiz. You will receive another chance to retake it tomorrow."
message = _(
"You have failed the quiz. You will receive another chance to retake it tomorrow."
)
logger.info(
f"Learner ID {enrolment.learner.id} has failed the quiz for Course {enrolment.course.title}. "
f"Scheduling a retry for the next day."
Expand Down
54 changes: 40 additions & 14 deletions django_email_learning/personalised/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.views import View
from django.views.generic.base import TemplateResponseMixin
from django.http import HttpResponse
from django.utils.translation import gettext as _
from django.urls import reverse
from django_email_learning.models import ContentDelivery, EnrollmentStatus
from django_email_learning.services import jwt_service
Expand All @@ -14,7 +15,11 @@

class ErrrorLoggingMixin(TemplateResponseMixin):
def errr_response(
self, message: str, exception: Exception | None, status_code: int = 500
self,
message: str,
exception: Exception | None,
status_code: int = 500,
title: str = _("Error"),
) -> HttpResponse:
error_ref = uuid.uuid4().hex
if exception:
Expand All @@ -26,7 +31,8 @@ def errr_response(
f"{message} - Ref: {error_ref}", extra={"error_ref": error_ref}
)
return self.render_to_response(
context={"ref": error_ref, "error_message": message}, status=status_code
context={"ref": error_ref, "error_message": message, "page_title": title},
status=status_code,
)


Expand All @@ -44,18 +50,22 @@ def get(self, request, *args, **kwargs) -> HttpResponse: # type: ignore[no-unty
enrolment = delivery.enrollment
if enrolment.status != EnrollmentStatus.ACTIVE:
return self.errr_response(
message="Quiz is not valid anymore",
message=_("Quiz is not valid anymore"),
exception=ValueError("Enrolment is not active"),
title=_("Invalid Quiz"),
)
quiz = delivery.course_content.quiz
if not quiz:
return self.errr_response(
message="No quiz associated with this link", exception=None
message=_("No quiz associated with this link"),
exception=None,
title=_("Invalid Quiz"),
)
if not delivery.course_content.is_published:
return self.errr_response(
message="No valid quiz associated with this link",
message=_("No valid quiz associated with this link"),
exception=ValueError("Quiz is not published"),
title=_("Invalid Quiz"),
)
quiz_data = PublicQuizSerializer.model_validate(quiz).model_dump()
if question_ids:
Expand All @@ -75,19 +85,30 @@ def get(self, request, *args, **kwargs) -> HttpResponse: # type: ignore[no-unty

except ContentDelivery.DoesNotExist as e:
return self.errr_response(
message="An error occurred while retrieving the quiz", exception=e
message=_("An error occurred while retrieving the quiz"),
exception=e,
title=_("Error"),
)
except KeyError as e:
return self.errr_response(
message="The link is not valid", exception=e, status_code=400
message=_("The link is not valid"),
exception=e,
status_code=400,
title=_("Invalid Link"),
)
except jwt_service.InvalidTokenException as e:
return self.errr_response(
message="The link is not valid", exception=e, status_code=400
message=_("The link is not valid"),
exception=e,
status_code=400,
title=_("Invalid Link"),
)
except jwt_service.ExpiredTokenException as e:
return self.errr_response(
message="The link has expired", exception=e, status_code=410
message=_("The link has expired"),
exception=e,
status_code=410,
title=_("Expired Link"),
)


Expand All @@ -99,23 +120,26 @@ def get(self, request, *args, **kwargs) -> HttpResponse: # type: ignore[no-unty
token = request.GET["token"]
except KeyError as e:
return self.errr_response(
message="The verification link is not valid.",
message=_("The verification link is not valid."),
exception=e,
status_code=400,
title=_("Invalid Link"),
)
try:
decoded = jwt_service.decode_jwt(token=token)
except jwt_service.InvalidTokenException as e:
return self.errr_response(
message="The verification link is not valid.",
message=_("The verification link is not valid."),
exception=e,
status_code=400,
title=_("Invalid Link"),
)
except jwt_service.ExpiredTokenException as e:
return self.errr_response(
message="The verification link has expired.",
message=_("The verification link has expired."),
exception=e,
status_code=410,
title=_("Expired Link"),
)

enrollment_id = decoded["enrollment_id"]
Expand All @@ -130,7 +154,9 @@ def get(self, request, *args, **kwargs) -> HttpResponse: # type: ignore[no-unty
command.execute()
except Exception as e:
return self.errr_response(
message="An error occurred during enrollment verification.", exception=e
message=_("An error occurred during enrollment verification."),
exception=e,
title=_("Verification Error"),
)

return self.render_to_response(context={"page_title": "Enrollment Verified"})
return self.render_to_response(context={"page_title": _("Enrollment Verified")})
9 changes: 5 additions & 4 deletions django_email_learning/platform/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.views.generic import TemplateView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.utils.translation import gettext as _
from django.urls import reverse
from django_email_learning.models import Organization, OrganizationUser, Course
from django_email_learning.decorators import (
Expand Down Expand Up @@ -70,7 +71,7 @@ class Courses(BasePlatformView):

def get_context_data(self, **kwargs) -> dict: # type: ignore[no-untyped-def]
context = super().get_context_data(**kwargs)
context["page_title"] = "Courses"
context["page_title"] = _("Courses")
return context


Expand All @@ -83,7 +84,7 @@ def get_context_data(self, **kwargs) -> dict: # type: ignore[no-untyped-def]
context = super().get_context_data(**kwargs)
course = Course.objects.get(pk=self.kwargs["course_id"])
context["course"] = course
context["page_title"] = f"Course: {course.title}"
context["page_title"] = _("Course: %(title)s") % {"title": course.title}
return context


Expand All @@ -94,7 +95,7 @@ class Organizations(BasePlatformView):

def get_context_data(self, **kwargs): # type: ignore[no-untyped-def]
context = super().get_context_data(**kwargs)
context["page_title"] = "Organizations"
context["page_title"] = _("Organizations")
return context


Expand All @@ -105,5 +106,5 @@ class Learners(BasePlatformView):

def get_context_data(self, **kwargs): # type: ignore[no-untyped-def]
context = super().get_context_data(**kwargs)
context["page_title"] = "Learners"
context["page_title"] = _("Learners")
return context
5 changes: 3 additions & 2 deletions django_email_learning/public/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django_email_learning.models import Organization, Course
from django.http import Http404
from django.urls import reverse
from django.utils.translation import gettext as _
from django.conf import settings
from django_email_learning.public.serializers import (
OrganizationSerializer,
Expand All @@ -29,7 +30,7 @@ def get_context_data(self, **kwargs) -> dict: # type: ignore[no-untyped-def]
if organization_details.exists():
organization = organization_details.first()
if not organization:
raise Http404("Organization does not exist")
raise Http404(_("Organization does not exist"))
courses = []
for course in organization.courses:
course_data = PublicCourseSerializer(
Expand Down Expand Up @@ -59,4 +60,4 @@ def get_context_data(self, **kwargs) -> dict: # type: ignore[no-untyped-def]
return context

# If organization not found, raise 404
raise Http404("Organization does not exist")
raise Http404(_("Organization does not exist"))
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django_email_learning.services import jwt_service
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.translation import gettext as _
from django.conf import settings
from django.urls import reverse
from typing import Literal
Expand Down Expand Up @@ -106,7 +107,7 @@ def execute(self) -> None:
else None,
}
email_service = EmailSenderService()
subject = "Verify your enrollment"
subject = _("Verify your enrollment")
body = render_to_string(
"emails/enrolment_verification.txt",
template_context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django_email_learning.services.email_sender_service import EmailSenderService
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.translation import gettext as _
from typing import Literal


Expand Down Expand Up @@ -59,7 +60,7 @@ def execute(self) -> None:

# Send confirmation email
email_service = EmailSenderService()
subject = "Enrollment Verified"
subject = _("Enrollment Verified")
body = render_to_string(
"emails/enrollment_verified.txt",
{
Expand Down
13 changes: 12 additions & 1 deletion django_email_learning/templates/emails/base.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{% load i18n %}
{% with brand_color="#7c86ff" %}
<html>
<head>
Expand All @@ -24,6 +25,16 @@
background-color: #f9f9f9;
}

.locale {
{% get_current_language_bidi as IS_RTL %}
{% if IS_RTL %}
direction: rtl;
text-align: right;
{% else %}
direction: ltr;
text-align: left;
{% endif %}
}

@media screen and (max-width: 480px) {
.mobile-content {
Expand Down Expand Up @@ -56,7 +67,7 @@
</head>
<body>
<div class="background">
<div class="mobile-content" style="background-color: #ffffff">
<div class="mobile-content locale" style="background-color: #ffffff">
{% block content %}{% endblock %}
</div>
</div>
Expand Down
21 changes: 11 additions & 10 deletions django_email_learning/templates/emails/enrollment_verified.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
{% extends "emails/base.html" %}
{% load i18n %}

{% block content %}
<P>Hello there,<br /></P>
<P>{% translate "Hello there," %}<br /></P>

<p><strong>Congratulations!</strong> Your enrollment for "<strong style="color: {{ brand_color }};">{{ course_title }}</strong>" has been successfully verified and confirmed.</p>
<p>{% blocktranslate %}Congratulations! Your enrollment for <strong style="color: {{ brand_color }}">{{ course_title }}</strong> has been successfully verified and confirmed.{% endblocktranslate %}</p>

<p>We're excited to have you join our learning community. Here's what you can expect:</p>
<p>{% translate "We're excited to have you join our learning community. Here's what you can expect:" %}</p>

<ul>
<li>Course materials will be delivered directly to this email address</li>
<li>You'll receive structured lessons and assignments on a regular schedule</li>
<li>Interactive content and assessments will help track your progress</li>
<li>{% translate "Course materials will be delivered directly to this email address" %}</li>
<li>{% translate "You'll receive structured lessons and assignments on a regular schedule" %}</li>
<li>{% translate "Interactive content and assessments will help track your progress" %}</li>
</ul>

<p>Your learning adventure begins soon! Keep an eye on your inbox for the first lesson and welcome materials.</p>
<p>{% translate "Your learning adventure begins soon! Keep an eye on your inbox for the first lesson and welcome materials." %}</p>

<h3>Welcome aboard!</h3>
<h3>{% translate "Welcome aboard!" %}</h3>

<p>Best regards,<br>
The <strong>{{ organization_name }}</strong> Team</p>
<p>{% translate "Best regards," %}<br>
{% blocktranslate %}The {{ organization_name }} Team{% endblocktranslate %}</p>
{% endblock %}
21 changes: 11 additions & 10 deletions django_email_learning/templates/emails/enrollment_verified.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
Hello there,
{% load i18n %}
{% translate "Hello there" %},

Congratulations! Your enrollment for "{{ course_title }}" has been successfully verified and confirmed.
{% blocktranslate %}Congratulations! Your enrollment for "{{ course_title }}" has been successfully verified and confirmed.{% endblocktranslate %}

We're excited to have you join our learning community. Here's what you can expect:
{% translate "We're excited to have you join our learning community. Here's what you can expect:" %}

• Course materials will be delivered directly to this email address
• You'll receive structured lessons and assignments on a regular schedule
• Interactive content and assessments will help track your progress
{% translate "Course materials will be delivered directly to this email address" %}
{% translate "You'll receive structured lessons and assignments on a regular schedule" %}
{% translate "Interactive content and assessments will help track your progress" %}

Your learning adventure begins soon! Keep an eye on your inbox for the first lesson and welcome materials.
{% translate "Your learning adventure begins soon! Keep an eye on your inbox for the first lesson and welcome materials." %}

Welcome aboard!
{% translate "Welcome aboard!" %}

Best regards,
The {{ organization_name }} Team
{% translate "Best regards," %}
{% blocktranslate %}The {{ organization_name }} Team{% endblocktranslate %}
Loading