Skip to content

Commit

Permalink
feat: removing visible_date-to-creds updates per-cert (#35113)
Browse files Browse the repository at this point in the history
* feat: removing visible_date-to-creds updates per-cert

The credentials IDA now relies on  the course certificate configuration
and (if present) `certificate_available_date` for displayability. We no
longer need to send `visible_date` updates for every awarded certificate
when a course  overview changes.
  • Loading branch information
deborahgu committed Jul 17, 2024
1 parent 3589d96 commit 58de096
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 250 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* This is a high level diagram visualizing how the `CERTIFICATE_AVAILBLE_DATE` and "visible date" attribute updates
* are updated internally and transmit to the Credentials IDA.
* This is a high level diagram visualizing how the `CERTIFICATE_AVAILBLE_DATE` update is
* updated internally and transmitted to the Credentials IDA.
*
* It is written using Structurizr DSL (https://structurizr.org/).
*/
Expand Down Expand Up @@ -33,9 +33,7 @@ workspace {
co_app -> modulestore "Retrieves course details from Mongo"
co_app -> monolith_db "Updates CourseOverview record"
co_app -> programs_app "Emits COURSE_CERT_DATE_CHANGED signal"
programs_app -> celery "Enqueue UPDATE_CERTIFICATE_VISIBLE_DATE task"
programs_app -> celery "Enqueue UPDATE_CERTIFICATE_AVAILABLE_DATE task"
celery -> credentials "REST requests to update `visible_date` attributes"
celery -> credentials "REST request to update `certificate_available_date` setting"
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
2 changes: 1 addition & 1 deletion lms/djangoapps/certificates/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ def _course_uses_available_date(course):
)


def available_date_for_certificate(course, certificate):
def available_date_for_certificate(course, certificate) -> datetime:
"""
Returns the available date to use with a certificate
Expand Down
2 changes: 0 additions & 2 deletions lms/envs/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -1063,8 +1063,6 @@ def get_env_setting(setting):
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
'openedx.core.djangoapps.programs.tasks.revoke_program_certificates': {
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
'openedx.core.djangoapps.programs.tasks.update_certificate_visible_date_on_course_update': {
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
'openedx.core.djangoapps.programs.tasks.update_certificate_available_date_on_course_update': {
'queue': PROGRAM_CERTIFICATES_ROUTING_KEY},
'openedx.core.djangoapps.programs.tasks.award_course_certificate': {
Expand Down
17 changes: 14 additions & 3 deletions openedx/core/djangoapps/catalog/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import datetime
import logging
import uuid
from typing import TYPE_CHECKING, Any, List, Union

import pycountry
import requests
Expand Down Expand Up @@ -31,6 +32,9 @@
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
from openedx.core.lib.edx_api_utils import get_api_data

if TYPE_CHECKING:
from django.contrib.sites.models import Site

logger = logging.getLogger(__name__)

missing_details_msg_tpl = "Failed to get details for program {uuid} from the cache."
Expand Down Expand Up @@ -98,7 +102,14 @@ def check_catalog_integration_and_get_user(error_message_field):


# pylint: disable=redefined-outer-name
def get_programs(site=None, uuid=None, uuids=None, course=None, catalog_course_uuid=None, organization=None):
def get_programs(
site: "Site" = None,
uuid: str = None,
uuids: List[str] = None,
course: str = None,
catalog_course_uuid: str = None,
organization: str = None,
) -> Union[str, List[str]]:
"""Read programs from the cache.
The cache is populated by a management command, cache_programs.
Expand All @@ -112,7 +123,7 @@ def get_programs(site=None, uuid=None, uuids=None, course=None, catalog_course_u
organization (string): short name for specific organization to read from the cache.
Returns:
list of dict, representing programs.
list of str, representing programs.
dict, if a specific program is requested.
"""
if len([arg for arg in (site, uuid, uuids, course, catalog_course_uuid, organization) if arg is not None]) != 1:
Expand Down Expand Up @@ -194,7 +205,7 @@ def get_programs_by_type_slug(site, program_type_slug):
return get_programs_by_uuids(uuids)


def get_programs_by_uuids(uuids):
def get_programs_by_uuids(uuids: List[Any]) -> List[str]:
"""
Gets a list of programs for the provided uuids
"""
Expand Down
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/credentials/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def get_credentials_records_url(program_uuid=None):
return base_url


def get_credentials_api_client(user):
def get_credentials_api_client(user) -> requests.Session:
"""
Returns an authenticated Credentials API client.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Sync certificate_available_date and visible_date for certificates
Status
------

Review
Superseded by Credentials ADR `0001 Certificate Available Date`_.

.. _0001 Certificate Available Date: https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/docs/decisions/0005-restricted-application-for-SSO.rst

Context
-------
Expand Down
17 changes: 9 additions & 8 deletions openedx/core/djangoapps/programs/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
This module contains signals / handlers related to programs.
"""


import logging

from django.dispatch import receiver
Expand All @@ -14,7 +13,7 @@
COURSE_CERT_AWARDED,
COURSE_CERT_CHANGED,
COURSE_CERT_DATE_CHANGE,
COURSE_CERT_REVOKED
COURSE_CERT_REVOKED,
)

LOGGER = logging.getLogger(__name__)
Expand All @@ -39,11 +38,10 @@ def handle_course_cert_awarded(sender, user, course_key, mode, status, **kwargs)
if not is_credentials_enabled():
return

LOGGER.debug(
f"Handling COURSE_CERT_AWARDED: user={user}, course_key={course_key}, mode={mode}, status={status}"
)
LOGGER.debug(f"Handling COURSE_CERT_AWARDED: user={user}, course_key={course_key}, mode={mode}, status={status}")
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
from openedx.core.djangoapps.programs.tasks import award_program_certificates

award_program_certificates.delay(user.username)


Expand All @@ -68,7 +66,7 @@ def handle_course_cert_changed(sender, user, course_key, mode, status, **kwargs)
Returns:
None
"""
verbose = kwargs.get('verbose', False)
verbose = kwargs.get("verbose", False)
if verbose:
LOGGER.info(
f"Starting handle_course_cert_changed with params: sender [{sender}], user [{user}], course_key "
Expand All @@ -87,6 +85,7 @@ def handle_course_cert_changed(sender, user, course_key, mode, status, **kwargs)
LOGGER.debug(f"Handling COURSE_CERT_CHANGED: user={user}, course_key={course_key}, mode={mode}, status={status}")
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
from openedx.core.djangoapps.programs.tasks import award_course_certificate

award_course_certificate.delay(user.username, str(course_key))


Expand All @@ -112,16 +111,16 @@ def handle_course_cert_revoked(sender, user, course_key, mode, status, **kwargs)
LOGGER.info(f"Handling COURSE_CERT_REVOKED: user={user}, course_key={course_key}, mode={mode}, status={status}")
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
from openedx.core.djangoapps.programs.tasks import revoke_program_certificates

revoke_program_certificates.delay(user.username, str(course_key))


@receiver(COURSE_CERT_DATE_CHANGE, dispatch_uid='course_certificate_date_change_handler')
@receiver(COURSE_CERT_DATE_CHANGE, dispatch_uid="course_certificate_date_change_handler")
def handle_course_cert_date_change(sender, course_key, **kwargs): # pylint: disable=unused-argument
"""
When a course run's configuration has been updated, and the system has detected an update related to the display
behavior or availability date of the certificates issued in that course, we should enqueue celery tasks responsible
for:
- updating the `visible_date` attribute of any previously awarded certificates the Credentials IDA manages
- updating the certificate available date of the course run's course certificate configuration in Credentials
Args:
Expand All @@ -137,6 +136,7 @@ def handle_course_cert_date_change(sender, course_key, **kwargs): # pylint: dis
LOGGER.info(f"Handling COURSE_CERT_DATE_CHANGE for course {course_key}")
# import here, because signal is registered at startup, but items in tasks are not yet loaded
from openedx.core.djangoapps.programs.tasks import update_certificate_available_date_on_course_update

update_certificate_available_date_on_course_update.delay(str(course_key))


Expand All @@ -161,4 +161,5 @@ def handle_course_pacing_change(sender, updated_course_overview, **kwargs): # p
LOGGER.info(f"Handling COURSE_PACING_CHANGED for course {course_id}")
# import here, because signal is registered at startup, but items in tasks are not yet loaded
from openedx.core.djangoapps.programs.tasks import update_certificate_available_date_on_course_update

update_certificate_available_date_on_course_update.delay(course_id)
Loading

0 comments on commit 58de096

Please sign in to comment.