openedx_certificates package#

Subpackages#

Submodules#

openedx_certificates.admin module#

Admin page configuration for the openedx-certificates app.

class openedx_certificates.admin.DocstringOptionsMixin#

Bases: object

A mixin to add the docstring of the function to the help text of the function field.

class openedx_certificates.admin.ExternalCertificateAdmin(model, admin_site)#

Bases: ModelAdmin

get_form(request: HttpRequest, obj: ExternalCertificate | None = None, **kwargs) forms.ModelForm#

Hide the download_url field.

list_display = ('user_id', 'user_full_name', 'course_id', 'certificate_type', 'status', 'url', 'created', 'modified')#
property media#
readonly_fields = ('user_id', 'created', 'modified', 'user_full_name', 'course_id', 'certificate_type', 'status', 'url', 'legacy_id', 'generation_task_id')#
url(obj: ExternalCertificate) str#

Display the download URL as a clickable link.

class openedx_certificates.admin.ExternalCertificateAssetAdmin(model, admin_site)#

Bases: ModelAdmin

list_display = ('description', 'asset_slug')#
property media#
prepopulated_fields = {'asset_slug': ('description',)}#
class openedx_certificates.admin.ExternalCertificateCourseConfigurationAdmin(model, admin_site)#

Bases: DjangoObjectActions, ReverseModelAdmin

Admin page for the course-specific certificate configuration for each certificate type.

It manages the associations between configuration and its corresponding periodic task. The reverse inline provides a way to manage the periodic task from the configuration page.

change_actions = ('generate_certificates',)#
enabled(obj: ExternalCertificateCourseConfiguration) bool#

Return the ‘enabled’ status of the periodic task.

form#

alias of ExternalCertificateCourseConfigurationForm

generate_certificates(_request: HttpRequest, obj: ExternalCertificateCourseConfiguration)#

Custom action to generate certificates for the current ExternalCertificateCourse instance.

Parameters:
  • _request – The request object.

  • obj – The ExternalCertificateCourse instance.

get_inline_instances(request: HttpRequest, obj: ExternalCertificateCourseConfiguration = None) list[admin.ModelAdmin]#

Hide inlines on the “Add” view in Django admin, and show them on the “Change” view.

It differentiates “add” and change “view” based on the requested path because the obj parameter can be None in the “Change” view when rendering the inlines.

Parameters:
  • request – HttpRequest object

  • obj – The object being changed, None for add view

Returns:

A list of InlineModelAdmin instances to be rendered for add/changing an object

get_readonly_fields(_request: HttpRequest, obj: ExternalCertificateCourseConfiguration = None) tuple#

Make the course_id field read-only.

inline_reverse = [('periodic_task', {'fields': ['enabled', 'interval', 'crontab', 'clocked', 'start_time', 'expires', 'one_off']})]#
inline_type = 'stacked'#
interval(obj: ExternalCertificateCourseConfiguration) IntervalSchedule#

Return the interval of the certificate generation task.

list_display = ('course_id', 'certificate_type', 'enabled', 'interval')#
list_filter = ('course_id', 'certificate_type')#
property media#
search_fields = ('course_id', 'certificate_type__name')#
class openedx_certificates.admin.ExternalCertificateCourseConfigurationForm(*args, **kwargs)#

Bases: ModelForm, DocstringOptionsMixin

class Meta#

Bases: object

fields = ('course_id', 'certificate_type', 'custom_options')#
model#

alias of ExternalCertificateCourseConfiguration

base_fields = {'certificate_type': <django.forms.models.ModelChoiceField object>, 'course_id': <django.forms.fields.CharField object>, 'custom_options': <jsonfield.forms.JSONField object>}#
clean_course_id() CourseKey#

Validate the course_id field.

declared_fields = {}#
property media#

Return all media required to render the widgets on this form.

class openedx_certificates.admin.ExternalCertificateTypeAdmin(model, admin_site)#

Bases: ModelAdmin

form#

alias of ExternalCertificateTypeAdminForm

list_display = ('name', 'retrieval_func', 'generation_func')#
property media#
class openedx_certificates.admin.ExternalCertificateTypeAdminForm(*args, **kwargs)#

Bases: ModelForm, DocstringOptionsMixin

Generate a list of available functions for the function fields.

class Meta#

Bases: object

fields = '__all__'#
model#

alias of ExternalCertificateType

base_fields = {'custom_options': <jsonfield.forms.JSONField object>, 'generation_func': <django.forms.fields.ChoiceField object>, 'name': <django.forms.fields.CharField object>, 'retrieval_func': <django.forms.fields.ChoiceField object>}#
declared_fields = {'generation_func': <django.forms.fields.ChoiceField object>, 'retrieval_func': <django.forms.fields.ChoiceField object>}#
property media#

Return all media required to render the widgets on this form.

openedx_certificates.apps module#

openedx_certificates Django application initialization.

class openedx_certificates.apps.OpenedxCertificatesConfig(app_name, app_module)#

Bases: AppConfig

Configuration for the openedx_certificates Django application.

name = 'openedx_certificates'#
plugin_app: ClassVar[dict[str, dict[str, dict]]] = {'settings_config': {'lms.djangoapp': {'common': {'relative_path': 'settings.common'}, 'production': {'relative_path': 'settings.production'}}}}#

openedx_certificates.compat module#

Proxies and compatibility code for edx-platform features.

This module moderates access to all edx-platform features allowing for cross-version compatibility code. It also simplifies running tests outside edx-platform’s environment by stubbing these functions in unit tests.

openedx_certificates.compat.get_celery_app() Celery#

Get Celery app to reuse configuration and queues.

openedx_certificates.compat.get_course_enrollments(course_id: CourseKey) list[User]#

Get the course enrollments from Open edX.

openedx_certificates.compat.get_course_grade_factory()#

Get the course grade factory from Open edX.

openedx_certificates.compat.get_course_grading_policy(course_id: CourseKey) dict#

Get the course grading policy from Open edX.

openedx_certificates.compat.get_course_name(course_id: CourseKey) str#

Get the course name from Open edX.

openedx_certificates.compat.get_localized_certificate_date() str#

Get the localized date from Open edX.

openedx_certificates.compat.prefetch_course_grades(course_id: CourseKey, users: list[User])#

Prefetch the course grades from Open edX.

openedx_certificates.exceptions module#

Custom exceptions for the openedx-certificates app.

exception openedx_certificates.exceptions.AssetNotFoundError#

Bases: Exception

Raised when the asset_slug is not found in the ExternalCertificateAsset model.

exception openedx_certificates.exceptions.CertificateGenerationError#

Bases: Exception

Raised when the certificate generation Celery task fails.

openedx_certificates.generators module#

This module provides functions to generate certificates.

The functions prefixed with generate_ are automatically detected by the admin page and are used to generate the certificates for the users.

We will move this module to an external repository (a plugin).

openedx_certificates.generators.generate_pdf_certificate(course_id: CourseKey, user: User, certificate_uuid: UUID, options: dict[str, Any]) str#

Generate a PDF certificate.

Parameters:
  • course_id – The ID of the course the learner completed.

  • user – The user to generate the certificate for.

  • certificate_uuid – The UUID of the certificate to generate.

  • options – The custom options for the certificate.

Returns:

The URL of the saved certificate.

Options:
  • template: The path to the PDF template file.

  • template_two_lines: The path to the PDF template file for two-line course names. A two-line course name is specified by using a semicolon as a separator.

  • font: The name of the font to use.

  • name_y: The Y coordinate of the name on the certificate (vertical position on the template).

  • name_color: The color of the name on the certificate (hexadecimal color code).

  • course_name: Specify the course name to use instead of the course Display Name retrieved from Open edX.

  • course_name_y: The Y coordinate of the course name on the certificate (vertical position on the template).

  • course_name_color: The color of the course name on the certificate (hexadecimal color code).

  • issue_date_y: The Y coordinate of the issue date on the certificate (vertical position on the template).

  • issue_date_color: The color of the issue date on the certificate (hexadecimal color code).

openedx_certificates.models module#

Database models for openedx_certificates.

class openedx_certificates.models.ExternalCertificate(*args, **kwargs)#

Bases: TimeStampedModel

Model to represent each individual certificate awarded to a user for a course.

This model contains information about the related course, the user who earned the certificate, the download URL for the certificate PDF, and the associated certificate generation task.

Note

The ID field is not a conventional auto-incrementing integer, but a value that allows for old certificates with custom IDs.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

class Status(value)#

Bases: TextChoices

Status of the certificate generation task.

AVAILABLE = 'available'#
ERROR = 'error'#
GENERATING = 'generating'#
INVALIDATED = 'invalidated'#
certificate_type#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

course_id#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

download_url#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

generation_task_id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
get_status_display(*, field=<django.db.models.fields.CharField: status>)#
legacy_id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
send_email()#

Send a certificate link to the student.

status#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user_full_name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user_id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

uuid#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class openedx_certificates.models.ExternalCertificateAsset(*args, **kwargs)#

Bases: TimeStampedModel

A set of assets to be used in custom certificate templates.

This model stores assets used during certificate generation process, such as PDF templates, images, fonts.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

asset#

The descriptor for the file attribute on the model instance. Return a FieldFile when accessed so you can write code like:

>>> from myapp.models import MyModel
>>> instance = MyModel.objects.get(pk=1)
>>> instance.file.size

Assign a file object on assignment so you can do:

>>> with open('/path/to/hello.world') as f:
...     instance.file = File(f)
asset_slug#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

description#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

classmethod get_asset_by_slug(asset_slug: str) File#

Fetch a certificate template asset by its slug from the database.

Parameters:

asset_slug – The slug of the asset to be retrieved.

Returns:

The file associated with the asset slug.

Raises:

AssetNotFound – If no asset exists with the provided slug in the ExternalCertificateAsset database model.

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
save(*args, **kwargs)#

If the object is being created, save the asset first, then save the object.

template_assets_path(filename: str) str#

Delete the file if it already exists and returns the certificate template asset file path.

Parameters:

filename – File to upload.

Return path:

Path of asset file e.g. certificate_template_assets/1/filename.

class openedx_certificates.models.ExternalCertificateCourseConfiguration(*args, **kwargs)#

Bases: TimeStampedModel

Model to store course-specific certificate configurations for each certificate type.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

certificate_type#

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

certificate_type_id#
course_id#

DO NOT REUSE THIS CLASS. Provided for backwards compatibility only!

A placeholder class that provides a way to set the attribute on the model.

custom_options#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

filter_out_user_ids_with_certificates(user_ids: list[int]) list[int]#

Filter out user IDs that already have a certificate for this course and certificate type.

Parameters:

user_ids – A list of user IDs to filter.

Returns:

A list of user IDs that either: 1. Do not have a certificate for this course and certificate type. 2. Have such a certificate with an error status.

generate_certificate_for_user(user_id: int, celery_task_id: int = 0)#

Celery task for processing a single user’s certificate.

This function retrieves an ExternalCertificateCourse object based on course_id and certificate_type_id, retrieves the data using the retrieval_func specified in the associated ExternalCertificateType object, and passes this data to the function specified in the generation_func field.

Parameters:
  • user_id – The ID of the user to process the certificate for.

  • celery_task_id (optional) – The ID of the Celery task that is running this function.

generate_certificates()#

This method allows manual certificate generation from the Django admin.

get_eligible_user_ids() list[int]#

Get the list of eligible learners for the given course.

Returns:

A list of user IDs.

classmethod get_enabled_configurations() QuerySet[ExternalCertificateCourseConfiguration]#

Get the list of enabled configurations.

Returns:

A list of ExternalCertificateCourseConfiguration objects.

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
periodic_task#

Accessor to the related object on the forward side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Restaurant.place is a ForwardOneToOneDescriptor instance.

periodic_task_id#
save(*args, **kwargs)#

Create a new PeriodicTask every time a new ExternalCertificateCourseConfiguration is created.

class openedx_certificates.models.ExternalCertificateType(*args, **kwargs)#

Bases: TimeStampedModel

Model to store global certificate configurations for each type.

exception DoesNotExist#

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned#

Bases: MultipleObjectsReturned

clean()#

Ensure that the retrieval_func and generation_func exist.

custom_options#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

externalcertificatecourseconfiguration_set#

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

generation_func#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=True, **kwargs)#
get_next_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=True, **kwargs)#
get_previous_by_created(*, field=<model_utils.fields.AutoCreatedField: created>, is_next=False, **kwargs)#
get_previous_by_modified(*, field=<model_utils.fields.AutoLastModifiedField: modified>, is_next=False, **kwargs)#
id#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

name#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>#
retrieval_func#

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

openedx_certificates.models.post_delete_periodic_task(sender, instance, *_args, **_kwargs)#

Delete the associated periodic task when the object is deleted.

openedx_certificates.processors module#

This module contains processors for certificate criteria.

The functions prefixed with retrieve_ are automatically detected by the admin page and are used to retrieve the IDs of the users that meet the criteria for the certificate type.

We will move this module to an external repository (a plugin).

openedx_certificates.processors.retrieve_course_completions(course_id: CourseKey, options: dict[str, Any]) list[int]#

Retrieve the course completions for all users through the Completion Aggregator API.

Options:
  • required_completion: The minimum required completion percentage. The default value is 0.9.

openedx_certificates.processors.retrieve_subsection_grades(course_id: CourseKey, options: dict[str, Any]) list[int]#

Retrieve the users that have passing grades in all required categories.

Parameters:
  • course_id – The course ID.

  • options – The custom options for the certificate.

Options:
  • required_grades: A dictionary of required grades for each category, where the keys are the category names and the values are the minimum required grades. The grades are percentages, so they should be in the range [0, 1]. See the following example:

    {
      "required_grades": {
        "Homework": 0.4,
        "Exam": 0.9,
        "Total": 0.8
      }
    }
    

    It means that the user must receive at least 40% in the Homework category and 90% in the Exam category. The “Total” key is a special value used to specify the minimum required grade for all categories in the course. Let’s assume that we have the following grading policy (the percentages are the weights of each category): 1. Homework: 20% 2. Lab: 10% 3. Exam: 70% The grades for the Total category will be calculated as follows: total_grade = (homework_grade * 0.2) + (lab_grade * 0.1) + (exam_grade * 0.7)

openedx_certificates.tasks module#

Asynchronous Celery tasks.

openedx_certificates.urls module#

URLs for openedx_certificates.

openedx_certificates.views module#

TODO.

Module contents#

A pluggable service for preparing Open edX certificates.