From a138c2d80cca487c37e6906184953ee0a730d7ea Mon Sep 17 00:00:00 2001 From: Deborah Kaplan Date: Wed, 26 Feb 2025 21:27:56 +0000 Subject: [PATCH] feat: adding pathway retirement * fixing enum usage * improving tests * fixing the way we hide retired programs --- credentials/apps/catalog/admin.py | 11 ++++++++++- .../catalog/docs/decisions/0002-pathway-status.rst | 14 ++++++++++++++ credentials/apps/catalog/tests/factories.py | 2 +- credentials/apps/catalog/utils.py | 14 +++++++++----- credentials/apps/records/api.py | 2 -- credentials/apps/records/tests/test_views.py | 8 ++++---- credentials/apps/records/views.py | 2 +- 7 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 credentials/apps/catalog/docs/decisions/0002-pathway-status.rst diff --git a/credentials/apps/catalog/admin.py b/credentials/apps/catalog/admin.py index c4c66fa15..31c9e7e6b 100644 --- a/credentials/apps/catalog/admin.py +++ b/credentials/apps/catalog/admin.py @@ -40,7 +40,16 @@ class ProgramAdmin(admin.ModelAdmin): class PathwayAdmin(admin.ModelAdmin): list_display = ("name", "org_name", "pathway_type", "status", "email", "uuid") list_filter = ("site", "status") - readonly_fields = ("name", "org_name", "pathway_type", "email", "uuid", "site", "programs") + readonly_fields = ( + "name", + "org_name", + "pathway_type", + "email", + "uuid", + "site", + "programs", + "status", + ) search_fields = ("name", "uuid") diff --git a/credentials/apps/catalog/docs/decisions/0002-pathway-status.rst b/credentials/apps/catalog/docs/decisions/0002-pathway-status.rst new file mode 100644 index 000000000..ea9f8e9cc --- /dev/null +++ b/credentials/apps/catalog/docs/decisions/0002-pathway-status.rst @@ -0,0 +1,14 @@ +Pathway Status +============== + +Status +------ +Accepted + +Background +---------- +Course discovery is now allowing pathways to be retired. The `course-discovery` API will continue to expose retired pathways, and it will rely on consumers to expose or process retired pathways as appropriate. + +Decision +-------- +The catalog app will now synchronize the `Pathway`'s `status` attribute. In the absence of a populated `status` attribute, a pathway will be considered to have the status of `published`. diff --git a/credentials/apps/catalog/tests/factories.py b/credentials/apps/catalog/tests/factories.py index a8f9fe00e..a486bc552 100644 --- a/credentials/apps/catalog/tests/factories.py +++ b/credentials/apps/catalog/tests/factories.py @@ -91,7 +91,7 @@ class Meta: name = FuzzyText(prefix="Test Pathway ") org_name = FuzzyText() email = factory.Faker("safe_email") - status = PathwayStatus.PUBLISHED + status = PathwayStatus.PUBLISHED.value @factory.post_generation def programs(self, create, extracted): diff --git a/credentials/apps/catalog/utils.py b/credentials/apps/catalog/utils.py index e5ab1aac5..d1decfd67 100644 --- a/credentials/apps/catalog/utils.py +++ b/credentials/apps/catalog/utils.py @@ -5,6 +5,7 @@ from django.db import transaction +from credentials.apps.catalog.data import PathwayStatus from credentials.apps.catalog.models import Course, CourseRun, Organization, Pathway, Program @@ -315,9 +316,11 @@ def _parse_course_run(self, course, data): @transaction.atomic def _parse_pathway(self, data): """ - Creates or updates a pathway and links it to connected programs + Creates or updates a pathway and links it to connected programs. - Assumes that the associated programs were parsed before this is run. + * Assumes that the associated programs were parsed before this is run. + * Always re-creates the foreign keys between Pathway and Program on modification. + If the Pathway is retired or unpublished, no relationship is created Arguments: data (dict): The pathway data pulled from the API @@ -340,8 +343,9 @@ def _parse_pathway(self, data): self.add_item(self.PATHWAY, str(pathway.uuid)) pathway.programs.clear() - for program_data in data["programs"]: - program = Program.objects.get(site=self.site, uuid=program_data["uuid"]) - pathway.programs.add(program) + if pathway.status in ("", PathwayStatus.PUBLISHED.value): + for program_data in data["programs"]: + program = Program.objects.get(site=self.site, uuid=program_data["uuid"]) + pathway.programs.add(program) return pathway diff --git a/credentials/apps/records/api.py b/credentials/apps/records/api.py index 0ae5ea350..cb9d265ca 100644 --- a/credentials/apps/records/api.py +++ b/credentials/apps/records/api.py @@ -9,7 +9,6 @@ from django.utils.translation import gettext as _ from credentials.apps.catalog.api import get_program_and_course_details -from credentials.apps.catalog.data import PathwayStatus from credentials.apps.core.api import get_user_by_username from credentials.apps.credentials.api import ( get_credential_dates, @@ -105,7 +104,6 @@ def _get_transformed_pathway_data(program, user): .filter( user=user, pathway__in=program_pathways_set, - pathway__status__in=("", PathwayStatus.PUBLISHED), ) .all() ) diff --git a/credentials/apps/records/tests/test_views.py b/credentials/apps/records/tests/test_views.py index 2ad7dac53..b97863aea 100644 --- a/credentials/apps/records/tests/test_views.py +++ b/credentials/apps/records/tests/test_views.py @@ -17,6 +17,7 @@ from django.test.utils import override_settings from django.urls import reverse +from credentials.apps.catalog.data import PathwayStatus from credentials.apps.catalog.tests.factories import ( CourseFactory, CourseRunFactory, @@ -34,7 +35,6 @@ UserCredentialFactory, ) from credentials.apps.records.constants import UserCreditPathwayStatus -from credentials.apps.catalog.data import PathwayStatus from credentials.apps.records.models import ProgramCertRecord, UserCreditPathway from credentials.apps.records.tests.factories import ( ProgramCertRecordFactory, @@ -211,9 +211,9 @@ def test_email_content_complete(self): self.assertListEqual([self.pathway.email], email.to) @ddt.data( - (PathwayStatus.PUBLISHED, 200), - (PathwayStatus.UNPUBLISHED, 404), - (PathwayStatus.RETIRED, 404), + (PathwayStatus.PUBLISHED.value, 200), + (PathwayStatus.UNPUBLISHED.value, 404), + (PathwayStatus.RETIRED.value, 404), ("", 200), ) @ddt.unpack diff --git a/credentials/apps/records/views.py b/credentials/apps/records/views.py index ba2faf7ce..67fe9c01d 100644 --- a/credentials/apps/records/views.py +++ b/credentials/apps/records/views.py @@ -151,7 +151,7 @@ def post(self, request, **kwargs): Pathway, id=pathway_id, programs__uuid=program_uuid, - status__in=(PathwayStatus.PUBLISHED, ""), + status__in=(PathwayStatus.PUBLISHED.value, ""), pathway_type=PathwayType.CREDIT.value, ) certificate = get_object_or_404(ProgramCertificate, program_uuid=program_uuid, site=request.site)