feat: Created an API to fetch progress details about a learner's program (#29975)
This commit is contained in:
0
lms/djangoapps/learner_dashboard/api/__init__.py
Normal file
0
lms/djangoapps/learner_dashboard/api/__init__.py
Normal file
10
lms/djangoapps/learner_dashboard/api/urls.py
Normal file
10
lms/djangoapps/learner_dashboard/api/urls.py
Normal file
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
Learner Dashboard API URLs.
|
||||
"""
|
||||
|
||||
from django.urls import include, path
|
||||
|
||||
app_name = 'learner_dashboard'
|
||||
urlpatterns = [
|
||||
path('v0/', include('lms.djangoapps.learner_dashboard.api.v0.urls')),
|
||||
]
|
||||
0
lms/djangoapps/learner_dashboard/api/v0/__init__.py
Normal file
0
lms/djangoapps/learner_dashboard/api/v0/__init__.py
Normal file
118
lms/djangoapps/learner_dashboard/api/v0/tests/test_views.py
Normal file
118
lms/djangoapps/learner_dashboard/api/v0/tests/test_views.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
Unit tests for Learner Dashboard REST APIs and Views
|
||||
"""
|
||||
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory as ModuleStoreCourseFactory
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from openedx.core.djangoapps.catalog.constants import PathwayType
|
||||
from openedx.core.djangoapps.catalog.tests.factories import (
|
||||
CourseFactory,
|
||||
CourseRunFactory,
|
||||
PathwayFactory,
|
||||
ProgramFactory
|
||||
)
|
||||
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
|
||||
PROGRAMS_UTILS_MODULE = 'openedx.core.djangoapps.programs.utils'
|
||||
|
||||
|
||||
@skip_unless_lms
|
||||
@mock.patch(PROGRAMS_UTILS_MODULE + '.get_pathways')
|
||||
@mock.patch(PROGRAMS_UTILS_MODULE + '.get_programs')
|
||||
class TestProgramProgressDetailView(ProgramsApiConfigMixin, SharedModuleStoreTestCase):
|
||||
"""Unit tests for the program progress detail page."""
|
||||
program_uuid = str(uuid4())
|
||||
password = 'test'
|
||||
url = reverse_lazy('learner_dashboard:v0:program_progress_detail', kwargs={'program_uuid': program_uuid})
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
modulestore_course = ModuleStoreCourseFactory()
|
||||
course_run = CourseRunFactory(key=str(modulestore_course.id)) # lint-amnesty, pylint: disable=no-member
|
||||
course = CourseFactory(course_runs=[course_run])
|
||||
|
||||
cls.program_data = ProgramFactory(uuid=cls.program_uuid, courses=[course])
|
||||
cls.pathway_data = PathwayFactory()
|
||||
cls.program_data['pathway_ids'] = [cls.pathway_data['id']]
|
||||
cls.pathway_data['program_uuids'] = [cls.program_data['uuid']]
|
||||
del cls.pathway_data['programs'] # lint-amnesty, pylint: disable=unsupported-delete-operation
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.user = UserFactory()
|
||||
self.client.login(username=self.user.username, password=self.password)
|
||||
|
||||
def assert_program_data_present(self, response):
|
||||
"""Verify that program data is present."""
|
||||
self.assertContains(response, 'program_data')
|
||||
self.assertContains(response, 'course_data')
|
||||
self.assertContains(response, 'urls')
|
||||
self.assertContains(response, 'certificate_data')
|
||||
self.assertContains(response, self.program_data['title'])
|
||||
|
||||
def assert_pathway_data_present(self, response):
|
||||
""" Verify that the correct pathway data is present. """
|
||||
self.assertContains(response, 'industry_pathways')
|
||||
self.assertContains(response, 'credit_pathways')
|
||||
|
||||
industry_pathways = response.data['industry_pathways']
|
||||
credit_pathways = response.data['credit_pathways']
|
||||
if self.pathway_data['pathway_type'] == PathwayType.CREDIT.value:
|
||||
credit_pathway, = credit_pathways # Verify that there is only one credit pathway
|
||||
assert self.pathway_data == credit_pathway
|
||||
assert [] == industry_pathways
|
||||
elif self.pathway_data['pathway_type'] == PathwayType.INDUSTRY.value:
|
||||
industry_pathway, = industry_pathways # Verify that there is only one industry pathway
|
||||
assert self.pathway_data == industry_pathway
|
||||
assert [] == credit_pathways
|
||||
|
||||
def test_api_returns_correct_program_data(self, mock_get_programs, mock_get_pathways):
|
||||
"""
|
||||
Verify that API returns program data in the correct format.
|
||||
"""
|
||||
self.create_programs_config()
|
||||
mock_get_programs.return_value = self.program_data
|
||||
mock_get_pathways.return_value = self.pathway_data
|
||||
|
||||
with mock.patch('lms.djangoapps.learner_dashboard.api.v0.views.get_certificates') as certs:
|
||||
certs.return_value = [{'type': 'program', 'url': '/'}]
|
||||
response = self.client.get(self.url)
|
||||
|
||||
assert response.status_code == 200
|
||||
self.assert_program_data_present(response)
|
||||
self.assert_pathway_data_present(response)
|
||||
|
||||
def test_login_required(self, mock_get_programs, mock_get_pathways):
|
||||
"""
|
||||
Verify that API returns 401 to an unauthenticated user.
|
||||
"""
|
||||
self.create_programs_config()
|
||||
mock_get_programs.return_value = self.program_data
|
||||
mock_get_pathways.return_value = self.pathway_data
|
||||
|
||||
self.client.logout()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_404_if_no_program_data(self, mock_get_programs, _mock_get_pathways):
|
||||
"""
|
||||
Verify that the API returns 404 if program data is not available.
|
||||
"""
|
||||
self.create_programs_config()
|
||||
|
||||
mock_get_programs.return_value = {}
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 404
|
||||
assert response.data['error_code'] == 'No program data available.'
|
||||
13
lms/djangoapps/learner_dashboard/api/v0/urls.py
Normal file
13
lms/djangoapps/learner_dashboard/api/v0/urls.py
Normal file
@@ -0,0 +1,13 @@
|
||||
"""
|
||||
Learner Dashboard API v0 URLs.
|
||||
"""
|
||||
|
||||
from django.urls import re_path
|
||||
|
||||
from lms.djangoapps.learner_dashboard.api.v0.views import ProgramProgressDetailView
|
||||
|
||||
app_name = 'v0'
|
||||
urlpatterns = [
|
||||
re_path(r'^programs/(?P<program_uuid>[0-9a-f-]+)/progress_details/$', ProgramProgressDetailView.as_view(),
|
||||
name='program_progress_detail'),
|
||||
]
|
||||
180
lms/djangoapps/learner_dashboard/api/v0/views.py
Normal file
180
lms/djangoapps/learner_dashboard/api/v0/views.py
Normal file
@@ -0,0 +1,180 @@
|
||||
""" API v0 views. """
|
||||
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from openedx.core.djangoapps.programs.utils import (
|
||||
get_certificates,
|
||||
get_industry_and_credit_pathways,
|
||||
get_program_urls,
|
||||
get_program_and_course_data
|
||||
)
|
||||
|
||||
|
||||
class ProgramProgressDetailView(APIView):
|
||||
"""
|
||||
**Use Case**
|
||||
|
||||
* Get progress details of a learner enrolled in a program.
|
||||
|
||||
**Example Request**
|
||||
|
||||
GET api/dashboard/v0/programs/{program_uuid}/progress_details/
|
||||
|
||||
**GET Parameters**
|
||||
|
||||
A GET request must include the following parameters.
|
||||
|
||||
* program_uuid: A string representation of uuid of the program.
|
||||
|
||||
**GET Response Values**
|
||||
|
||||
If the request for information about the program is successful, an HTTP 200 "OK" response
|
||||
is returned.
|
||||
|
||||
The HTTP 200 response has the following values.
|
||||
|
||||
* urls: Urls to enroll/purchase a course or view program record.
|
||||
|
||||
* program_data: Holds meta information about the program.
|
||||
|
||||
* course_data: Learner's progress details for all courses in the program (in-progress/remaining/completed).
|
||||
|
||||
* certificate_data: Details about learner's certificates status for all courses in the program and the
|
||||
program itself.
|
||||
|
||||
* industry_pathways: Industry pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
* credit_pathways: Credit pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
**Example GET Response**
|
||||
|
||||
{
|
||||
"urls": {
|
||||
"program_listing_url": "/dashboard/programs/",
|
||||
"track_selection_url": "/course_modes/choose/",
|
||||
"commerce_api_url": "/api/commerce/v0/baskets/",
|
||||
"buy_button_url": "http://ecommerce.com/basket/add/?",
|
||||
"program_record_url": "https://credentials.example.com/records/programs/121234235525242344"
|
||||
},
|
||||
"program_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"title": "edX Demonstration Program",
|
||||
"subtitle": "",
|
||||
"type": "MicroMasters",
|
||||
"status": "active",
|
||||
"marketing_slug": "demo-program",
|
||||
"marketing_url": "micromasters/demo-program",
|
||||
"authoring_organizations": [],
|
||||
"card_image_url": "http://edx.devstack.lms:18000/asset-v1:edX+DemoX+Demo_Course.jpg",
|
||||
"is_program_eligible_for_one_click_purchase": false,
|
||||
"pathway_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"is_learner_eligible_for_one_click_purchase": false,
|
||||
"skus": ["AUD122342"],
|
||||
},
|
||||
"course_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"completed": [],
|
||||
"in_progress": [],
|
||||
"not_started": [
|
||||
{
|
||||
"key": "edX+DemoX",
|
||||
"uuid": "fe1a9ad4-a452-45cd-80e5-9babd3d43f96",
|
||||
"title": "Demonstration Course",
|
||||
"course_runs": [],
|
||||
"entitlements": [],
|
||||
"owners": [],
|
||||
"image": "",
|
||||
"short_description": "",
|
||||
"type": "457f07ec-a78f-45b4-ba09-5fb176520d8a",
|
||||
}
|
||||
],
|
||||
},
|
||||
"certificate_data": [{
|
||||
"type": "course",
|
||||
"title": "edX Demo Course",
|
||||
'url': "/certificates/6e57d3cce8e34cfcb60bd8e8b04r07e0",
|
||||
}],
|
||||
"industry_pathways": [
|
||||
{
|
||||
"id": 2,
|
||||
"uuid": "1b8fadf1-f6aa-4282-94e3-325b922a027f",
|
||||
"name": "Demo Industry Pathway",
|
||||
"org_name": "edX",
|
||||
"email": "edx@edx.com",
|
||||
"description": "Sample demo industry pathway",
|
||||
"destination_url": "http://rit.edu/online/pathways/gtx-analytics-essential-tools-methods",
|
||||
"pathway_type": "industry",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
],
|
||||
"credit_pathways": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "86b9701a-61e6-48a2-92eb-70a824521c1f",
|
||||
"name": "Demo Credit Pathway",
|
||||
"org_name": "edX",
|
||||
"email": "edx@edx.com",
|
||||
"description": "Sample demo credit pathway!",
|
||||
"destination_url": "http://rit.edu/online/pathways/ritx-design-thinking",
|
||||
"pathway_type": "credit",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
authentication_classes = (
|
||||
JwtAuthentication,
|
||||
SessionAuthentication,
|
||||
)
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, program_uuid):
|
||||
"""
|
||||
Retrieves progress details of a user in a specified program.
|
||||
|
||||
Args:
|
||||
request (Request): Django request object.
|
||||
program_uuid (string): URI element specifying uuid of the program.
|
||||
|
||||
Return:
|
||||
"""
|
||||
user = request.user
|
||||
site = request.site
|
||||
program_data, course_data = get_program_and_course_data(site, user, program_uuid)
|
||||
if not program_data:
|
||||
return Response(
|
||||
status=404,
|
||||
data={'error_code': 'No program data available.'}
|
||||
)
|
||||
|
||||
certificate_data = get_certificates(user, program_data)
|
||||
program_data.pop('courses')
|
||||
|
||||
urls = get_program_urls(program_data)
|
||||
if not certificate_data:
|
||||
urls['program_record_url'] = None
|
||||
|
||||
industry_pathways, credit_pathways = get_industry_and_credit_pathways(program_data, site)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'urls': urls,
|
||||
'program_data': program_data,
|
||||
'course_data': course_data,
|
||||
'certificate_data': certificate_data,
|
||||
'industry_pathways': industry_pathways,
|
||||
'credit_pathways': credit_pathways,
|
||||
}
|
||||
)
|
||||
@@ -9,7 +9,6 @@ from urllib.parse import quote
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.http import Http404
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import get_language
|
||||
from django.utils.translation import gettext_lazy as _ # lint-amnesty, pylint: disable=unused-import
|
||||
from django.utils.translation import to_locale
|
||||
@@ -18,11 +17,8 @@ from web_fragments.fragment import Fragment
|
||||
|
||||
from common.djangoapps.student.models import anonymous_id_for_user
|
||||
from common.djangoapps.student.roles import GlobalStaff
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.learner_dashboard.utils import FAKE_COURSE_KEY, program_tab_view_is_enabled, strip_course_id
|
||||
from openedx.core.djangoapps.catalog.constants import PathwayType
|
||||
from openedx.core.djangoapps.catalog.utils import get_pathways, get_programs
|
||||
from openedx.core.djangoapps.credentials.utils import get_credentials_records_url
|
||||
from lms.djangoapps.learner_dashboard.utils import program_tab_view_is_enabled
|
||||
from openedx.core.djangoapps.catalog.utils import get_programs
|
||||
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
||||
from openedx.core.djangoapps.programs.models import (
|
||||
ProgramDiscussionsConfiguration,
|
||||
@@ -30,10 +26,12 @@ from openedx.core.djangoapps.programs.models import (
|
||||
ProgramsApiConfig
|
||||
)
|
||||
from openedx.core.djangoapps.programs.utils import (
|
||||
ProgramDataExtender,
|
||||
ProgramProgressMeter,
|
||||
get_certificates,
|
||||
get_program_marketing_url
|
||||
get_program_marketing_url,
|
||||
get_industry_and_credit_pathways,
|
||||
get_program_urls,
|
||||
get_program_and_course_data
|
||||
)
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preferences
|
||||
from openedx.core.djangolib.markup import HTML
|
||||
@@ -92,59 +90,28 @@ class ProgramDetailsFragmentView(EdxFragmentView):
|
||||
"""View details about a specific program."""
|
||||
programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current()
|
||||
user = request.user
|
||||
site = request.site
|
||||
if not programs_config.enabled or not request.user.is_authenticated:
|
||||
raise Http404
|
||||
|
||||
meter = ProgramProgressMeter(request.site, user, uuid=program_uuid)
|
||||
program_data = meter.programs[0]
|
||||
|
||||
if not program_data:
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
mobile_only = json.loads(request.GET.get('mobile_only', 'false'))
|
||||
except ValueError:
|
||||
mobile_only = False
|
||||
|
||||
program_data = ProgramDataExtender(program_data, user, mobile_only=mobile_only).extend()
|
||||
course_data = meter.progress(programs=[program_data], count_only=False)[0]
|
||||
program_data, course_data = get_program_and_course_data(site, user, program_uuid, mobile_only)
|
||||
|
||||
if not program_data:
|
||||
raise Http404
|
||||
|
||||
certificate_data = get_certificates(user, program_data)
|
||||
|
||||
program_data.pop('courses')
|
||||
skus = program_data.get('skus')
|
||||
ecommerce_service = EcommerceService()
|
||||
|
||||
# TODO: Don't have business logic of course-certificate==record-available here in LMS.
|
||||
# Eventually, the UI should ask Credentials if there is a record available and get a URL from it.
|
||||
# But this is here for now so that we can gate this URL behind both this business logic and
|
||||
# a waffle flag. This feature is in active developoment.
|
||||
program_record_url = get_credentials_records_url(program_uuid=program_uuid)
|
||||
urls = get_program_urls(program_data)
|
||||
if not certificate_data:
|
||||
program_record_url = None
|
||||
urls['program_record_url'] = None
|
||||
|
||||
industry_pathways = []
|
||||
credit_pathways = []
|
||||
try:
|
||||
for pathway_id in program_data['pathway_ids']:
|
||||
pathway = get_pathways(request.site, pathway_id)
|
||||
if pathway and pathway['email']:
|
||||
if pathway['pathway_type'] == PathwayType.CREDIT.value:
|
||||
credit_pathways.append(pathway)
|
||||
elif pathway['pathway_type'] == PathwayType.INDUSTRY.value:
|
||||
industry_pathways.append(pathway)
|
||||
# if pathway caching did not complete fully (no pathway_ids)
|
||||
except KeyError:
|
||||
pass
|
||||
industry_pathways, credit_pathways = get_industry_and_credit_pathways(program_data, site)
|
||||
|
||||
urls = {
|
||||
'program_listing_url': reverse('program_listing_view'),
|
||||
'track_selection_url': strip_course_id(
|
||||
reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY})
|
||||
),
|
||||
'commerce_api_url': reverse('commerce_api:v0:baskets:create'),
|
||||
'buy_button_url': ecommerce_service.get_checkout_page_url(*skus),
|
||||
'program_record_url': program_record_url,
|
||||
}
|
||||
program_discussion_lti = ProgramDiscussionLTI(program_uuid, request)
|
||||
program_live_lti = ProgramLiveLTI(program_uuid, request)
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ class TestProgramListing(ProgramsApiConfigMixin, SharedModuleStoreTestCase):
|
||||
|
||||
|
||||
@skip_unless_lms
|
||||
@mock.patch(PROGRAMS_MODULE + '.get_pathways')
|
||||
@mock.patch(PROGRAMS_UTILS_MODULE + '.get_pathways')
|
||||
@mock.patch(PROGRAMS_UTILS_MODULE + '.get_programs')
|
||||
class TestProgramDetails(ProgramsApiConfigMixin, CatalogIntegrationMixin, SharedModuleStoreTestCase):
|
||||
"""Unit tests for the program details page."""
|
||||
|
||||
@@ -195,6 +195,9 @@ urlpatterns = [
|
||||
namespace='api_admin')),
|
||||
|
||||
path('dashboard/', include('lms.djangoapps.learner_dashboard.urls')),
|
||||
# Dashboard REST APIs
|
||||
path('api/dashboard/', include('lms.djangoapps.learner_dashboard.api.urls', namespace='dashboard_api')),
|
||||
|
||||
path(
|
||||
'api/experiments/',
|
||||
include(
|
||||
|
||||
@@ -29,13 +29,15 @@ from lms.djangoapps.certificates.data import CertificateStatuses
|
||||
from lms.djangoapps.certificates.models import GeneratedCertificate
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from openedx.core.djangoapps.catalog.api import get_programs_by_type
|
||||
from openedx.core.djangoapps.catalog.constants import PathwayType
|
||||
from openedx.core.djangoapps.catalog.utils import (
|
||||
get_fulfillable_course_runs_for_entitlement,
|
||||
get_programs,
|
||||
get_pathways
|
||||
)
|
||||
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.credentials.utils import get_credentials
|
||||
from openedx.core.djangoapps.credentials.utils import get_credentials, get_credentials_records_url
|
||||
from openedx.core.djangoapps.enrollments.api import get_enrollments
|
||||
from openedx.core.djangoapps.enrollments.permissions import ENROLL_IN_COURSE
|
||||
from openedx.core.djangoapps.programs import ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER
|
||||
@@ -50,6 +52,60 @@ DEFAULT_ENROLLMENT_START_DATE = datetime.datetime(1900, 1, 1, tzinfo=utc)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_program_and_course_data(site, user, program_uuid, mobile_only=False):
|
||||
"""Returns program and course data associated with the given user."""
|
||||
course_data = {}
|
||||
meter = ProgramProgressMeter(site, user, uuid=program_uuid)
|
||||
program_data = meter.programs[0]
|
||||
if program_data:
|
||||
program_data = ProgramDataExtender(program_data, user, mobile_only=mobile_only).extend()
|
||||
course_data = meter.progress(programs=[program_data], count_only=False)[0]
|
||||
return program_data, course_data
|
||||
|
||||
|
||||
def get_program_urls(program_data):
|
||||
"""Returns important urls of program."""
|
||||
from lms.djangoapps.learner_dashboard.utils import FAKE_COURSE_KEY, strip_course_id
|
||||
program_uuid = program_data.get('uuid')
|
||||
skus = program_data.get('skus')
|
||||
ecommerce_service = EcommerceService()
|
||||
|
||||
# TODO: Don't have business logic of course-certificate==record-available here in LMS.
|
||||
# Eventually, the UI should ask Credentials if there is a record available and get a URL from it.
|
||||
# But this is here for now so that we can gate this URL behind both this business logic and
|
||||
# a waffle flag. This feature is in active developoment.
|
||||
program_record_url = get_credentials_records_url(program_uuid=program_uuid)
|
||||
urls = {
|
||||
'program_listing_url': reverse('program_listing_view'),
|
||||
'track_selection_url': strip_course_id(
|
||||
reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY})
|
||||
),
|
||||
'commerce_api_url': reverse('commerce_api:v0:baskets:create'),
|
||||
'buy_button_url': ecommerce_service.get_checkout_page_url(*skus),
|
||||
'program_record_url': program_record_url,
|
||||
}
|
||||
return urls
|
||||
|
||||
|
||||
def get_industry_and_credit_pathways(program_data, site):
|
||||
"""Returns pathways of a program."""
|
||||
industry_pathways = []
|
||||
credit_pathways = []
|
||||
try:
|
||||
for pathway_id in program_data['pathway_ids']:
|
||||
pathway = get_pathways(site, pathway_id)
|
||||
if pathway and pathway['email']:
|
||||
if pathway['pathway_type'] == PathwayType.CREDIT.value:
|
||||
credit_pathways.append(pathway)
|
||||
elif pathway['pathway_type'] == PathwayType.INDUSTRY.value:
|
||||
industry_pathways.append(pathway)
|
||||
# if pathway caching did not complete fully (no pathway_ids)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return industry_pathways, credit_pathways
|
||||
|
||||
|
||||
def get_program_marketing_url(programs_config, mobile_only=False):
|
||||
"""Build a URL used to link to programs on the marketing site."""
|
||||
if mobile_only:
|
||||
|
||||
Reference in New Issue
Block a user