Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [AXM-1183] adapt OBv3 composition to course credentials #185

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
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
Loading