Skip to content

Commit

Permalink
feat: [AXM-1183] adapt OBv3 composition to course credentials (#185)
Browse files Browse the repository at this point in the history
* feat: [AXM-1183] adapt OBv3 composition to course credentials

* refactor: [AXM-1183] move credential types to enum
  • Loading branch information
kyrylo-kh authored Dec 17, 2024
1 parent cd8b1bf commit da2b598
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from rest_framework import serializers

from ..constants import CredentialsType


class EducationalOccupationalProgramSchema(serializers.Serializer): # pylint: disable=abstract-method
"""
Expand Down Expand Up @@ -52,9 +54,9 @@ def to_representation(self, instance):
"""
representation = super().to_representation(instance)

if instance.user_credential.credential_content_type.model == "programcertificate":
if instance.user_credential.credential_content_type.model == CredentialsType.PROGRAM:
representation["program"] = EducationalOccupationalProgramSchema(instance).data
elif instance.user_credential.credential_content_type.model == "coursecertificate":
elif instance.user_credential.credential_content_type.model == CredentialsType.COURSE:
representation["course"] = EducationalOccupationalCourseSchema(instance).data

return representation
Expand Down
6 changes: 6 additions & 0 deletions credentials/apps/verifiable_credentials/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class CredentialsType:
"""
Enum to define the type of credentials.
"""
PROGRAM = "programcertificate"
COURSE = "coursecertificate"
87 changes: 49 additions & 38 deletions credentials/apps/verifiable_credentials/issuance/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ..composition.utils import get_data_model, get_data_models
from ..settings import vc_settings
from ..storages.utils import get_storage
from ..constants import CredentialsType


User = get_user_model()
Expand Down Expand Up @@ -107,8 +108,8 @@ def credential_verbose_type(self):
Map internal credential types to verbose labels (source models do not provide those).
"""
contenttype_to_verbose_name = {
"programcertificate": _("program certificate"),
"coursecertificate": _("course certificate"),
CredentialsType.PROGRAM: _("program certificate"),
CredentialsType.COURSE: _("course certificate"),
}
return contenttype_to_verbose_name.get(self.credential_content_type)

Expand All @@ -121,10 +122,10 @@ def credential_name(self):
return credential_title

contenttype_to_name = {
"programcertificate": _("program certificate for passing a program {program_title}").format(
CredentialsType.PROGRAM: _("program certificate for passing a program {program_title}").format(
program_title=getattr(self.program, "title", "")
),
"coursecertificate": self.credential_verbose_type,
CredentialsType.COURSE: self.credential_verbose_type,
}
return capitalize_first(contenttype_to_name.get(self.credential_content_type))

Expand All @@ -133,48 +134,58 @@ def credential_description(self):
"""
Verifiable credential achievement description resolution.
"""
effort_portion = (
_(", with total {hours_of_effort} Hours of effort required to complete it").format(
hours_of_effort=self.program.total_hours_of_effort
if self.credential_content_type == CredentialsType.PROGRAM:
effort_portion = (
_(", with total {hours_of_effort} Hours of effort required to complete it").format(
hours_of_effort=self.program.total_hours_of_effort
)
if self.program.total_hours_of_effort
else ""
)
if self.program.total_hours_of_effort
else ""
)

program_certificate_description = _(
"{credential_type} is granted on program {program_title} completion offered by {organizations}, in collaboration with {platform_name}. The {program_title} program includes {course_count} course(s){effort_info}." # pylint: disable=line-too-long
).format(
credential_type=self.credential_verbose_type,
program_title=self.program.title,
organizations=", ".join(list(self.program.authoring_organizations.values_list("name", flat=True))),
platform_name=self.platform_name,
course_count=self.program.course_runs.count(),
effort_info=effort_portion,
)
type_to_description = {
"programcertificate": program_certificate_description,
"coursecertificate": "",
}
return capitalize_first(type_to_description.get(self.credential_content_type))
description = _(
"{credential_type} is granted on program {program_title} completion offered by {organizations}, in collaboration with {platform_name}. The {program_title} program includes {course_count} course(s){effort_info}." # pylint: disable=line-too-long
).format(
credential_type=self.credential_verbose_type,
program_title=self.program.title,
organizations=", ".join(list(self.program.authoring_organizations.values_list("name", flat=True))),
platform_name=self.platform_name,
course_count=self.program.course_runs.count(),
effort_info=effort_portion,
)
elif self.credential_content_type == CredentialsType.COURSE:
description = _("{credential_type} is granted on course {course_title} completion offered by {organization}, in collaboration with {platform_name}").format(
credential_type=self.credential_verbose_type,
course_title=getattr(self.course, "title", ""),
platform_name=self.platform_name,
organization=self.user_credential.credential.course_key.org,
)
return capitalize_first(description)

@property
def credential_narrative(self):
"""
Verifiable credential achievement criteria narrative.
"""
program_certificate_narrative = _(
"{recipient_fullname} successfully completed all courses and received passing grades for a Professional Certificate in {program_title} a program offered by {organizations}, in collaboration with {platform_name}." # pylint: disable=line-too-long
).format(
recipient_fullname=self.subject_fullname or _("recipient"),
program_title=self.program.title,
organizations=", ".join(list(self.program.authoring_organizations.values_list("name", flat=True))),
platform_name=self.platform_name,
)
type_to_narrative = {
"programcertificate": program_certificate_narrative,
"coursecertificate": "",
}
return capitalize_first(type_to_narrative.get(self.credential_content_type))
if self.credential_content_type == CredentialsType.PROGRAM:
narrative = _(
"{recipient_fullname} successfully completed all courses and received passing grades for a Professional Certificate in {program_title} a program offered by {organizations}, in collaboration with {platform_name}." # pylint: disable=line-too-long
).format(
recipient_fullname=self.subject_fullname or _("recipient"),
program_title=self.program.title,
organizations=", ".join(list(self.program.authoring_organizations.values_list("name", flat=True))),
platform_name=self.platform_name,
)
elif self.credential_content_type == CredentialsType.COURSE:
narrative = _(
"{recipient_fullname} successfully completed a course and received a passing grade for a Course Certificate in {course_title} a course offered by {organization}, in collaboration with {platform_name}. " # pylint: disable=line-too-long
).format(
recipient_fullname=self.subject_fullname or _("recipient"),
course_title=getattr(self.course, "title", ""),
organization=self.user_credential.credential.course_key.org,
platform_name=self.platform_name,
)
return capitalize_first(narrative)

@property
def credential_content_type(self):
Expand Down

0 comments on commit da2b598

Please sign in to comment.