Merge pull request #24791 from edx/tuchfarber/refactor_get_programs_by_type
Refactor program type enrollment checks
This commit is contained in:
17
common/djangoapps/course_modes/api.py
Normal file
17
common/djangoapps/course_modes/api.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
Python APIs exposed by the course_modes app to other in-process apps.
|
||||
"""
|
||||
|
||||
from course_modes.models import CourseMode as _CourseMode
|
||||
|
||||
|
||||
def get_paid_modes_for_course(course_run_id):
|
||||
"""
|
||||
Returns a list of non-expired mode slugs for a course run ID that have a set minimum price.
|
||||
|
||||
Params:
|
||||
course_run_id (CourseKey): The course run you want to get the paid modes for
|
||||
Returns:
|
||||
A list of paid modes (strings) that the course has attached to it.
|
||||
"""
|
||||
return _CourseMode.paid_modes_for_course(course_run_id)
|
||||
@@ -1,12 +0,0 @@
|
||||
"""
|
||||
URL definitions for the course_modes API.
|
||||
"""
|
||||
|
||||
|
||||
from django.conf.urls import include, url
|
||||
|
||||
app_name = 'common.djangoapps.course_modes.api'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^v1/', include('course_modes.api.v1.urls', namespace='v1')),
|
||||
]
|
||||
12
common/djangoapps/course_modes/rest_api/urls.py
Normal file
12
common/djangoapps/course_modes/rest_api/urls.py
Normal file
@@ -0,0 +1,12 @@
|
||||
"""
|
||||
URL definitions for the course_modes API.
|
||||
"""
|
||||
|
||||
|
||||
from django.conf.urls import include, url
|
||||
|
||||
app_name = 'common.djangoapps.course_modes.rest_api'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^v1/', include('course_modes.rest_api.v1.urls', namespace='v1')),
|
||||
]
|
||||
@@ -5,7 +5,6 @@ Tests for the course modes API.
|
||||
|
||||
import json
|
||||
import unittest
|
||||
from itertools import product
|
||||
|
||||
import ddt
|
||||
from django.conf import settings
|
||||
@@ -15,7 +14,7 @@ from rest_framework import status
|
||||
from rest_framework.test import APITestCase
|
||||
from six import text_type
|
||||
|
||||
from course_modes.api.v1.views import CourseModesView
|
||||
from course_modes.rest_api.v1.views import CourseModesView
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
|
||||
@@ -79,7 +78,7 @@ class CourseModesViewTestBase(AuthAndScopesTestMixin):
|
||||
"""
|
||||
Required method to implement AuthAndScopesTestMixin.
|
||||
"""
|
||||
pass
|
||||
pass # pylint: disable=unnecessary-pass
|
||||
|
||||
@ddt.data(*JWT_AUTH_TYPES)
|
||||
def test_jwt_on_behalf_of_user(self, auth_type):
|
||||
@@ -6,7 +6,7 @@ URL definitions for the course_modes v1 API.
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
|
||||
from course_modes.api.v1 import views
|
||||
from course_modes.rest_api.v1 import views
|
||||
|
||||
app_name = 'v1'
|
||||
|
||||
@@ -14,7 +14,7 @@ from rest_framework import status
|
||||
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
from course_modes.api.serializers import CourseModeSerializer
|
||||
from course_modes.rest_api.serializers import CourseModeSerializer
|
||||
from course_modes.models import CourseMode
|
||||
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
|
||||
from openedx.core.lib.api.parsers import MergePatchParser
|
||||
@@ -156,8 +156,9 @@ urlpatterns = [
|
||||
|
||||
# Multiple course modes and identity verification
|
||||
url(r'^course_modes/', include('course_modes.urls')),
|
||||
url(r'^api/course_modes/', include(('course_modes.api.urls', 'common.djangoapps.course_mods'),
|
||||
url(r'^api/course_modes/', include(('course_modes.rest_api.urls', 'common.djangoapps.course_mods'),
|
||||
namespace='course_modes_api')),
|
||||
|
||||
url(r'^verify_student/', include('verify_student.urls')),
|
||||
|
||||
# URLs for managing dark launches of languages
|
||||
|
||||
21
openedx/core/djangoapps/catalog/api.py
Normal file
21
openedx/core/djangoapps/catalog/api.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
Python APIs exposed by the catalog app to other in-process apps.
|
||||
"""
|
||||
|
||||
from .utils import get_programs_by_type_slug as _get_programs_by_type_slug
|
||||
|
||||
|
||||
def get_programs_by_type(site, program_type_slug):
|
||||
"""
|
||||
Retrieves a list of programs for the site whose type's slug matches the parameter.
|
||||
Slug is used is used as a consistent value to check since ProgramType.name is
|
||||
a field that gets translated.
|
||||
|
||||
Params:
|
||||
site (Site): The corresponding Site object to fetch programs for.
|
||||
program_type_slug (string): The type slug that matching programs must have.
|
||||
|
||||
Returns:
|
||||
A list of programs (dicts) for the given site with the given type slug
|
||||
"""
|
||||
return _get_programs_by_type_slug(site, program_type_slug)
|
||||
@@ -22,5 +22,9 @@ CATALOG_COURSE_PROGRAMS_CACHE_KEY_TPL = 'catalog-course-programs-{course_uuid}'
|
||||
# that live in the same environment).
|
||||
PROGRAMS_BY_TYPE_CACHE_KEY_TPL = 'programs-by-type-{site_id}-{program_type}'
|
||||
|
||||
# Site-aware cache key template used to locate an item containing
|
||||
# a list of all program UUIDs with a certain program slug
|
||||
PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL = 'programs-by-type-slug-{site_id}-{program_slug}'
|
||||
|
||||
# Template used to create cache keys for organization to program uuids.
|
||||
PROGRAMS_BY_ORGANIZATION_CACHE_KEY_TPL = 'organization-programs-{org_key}'
|
||||
|
||||
@@ -18,6 +18,7 @@ from openedx.core.djangoapps.catalog.cache import (
|
||||
PROGRAM_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_ORGANIZATION_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL,
|
||||
SITE_PATHWAY_IDS_CACHE_KEY_TPL,
|
||||
SITE_PROGRAM_UUIDS_CACHE_KEY_TPL
|
||||
)
|
||||
@@ -64,6 +65,7 @@ class Command(BaseCommand):
|
||||
courses = {}
|
||||
catalog_courses = {}
|
||||
programs_by_type = {}
|
||||
programs_by_type_slug = {}
|
||||
organizations = {}
|
||||
for site in Site.objects.all():
|
||||
site_config = getattr(site, 'configuration', None)
|
||||
@@ -93,6 +95,7 @@ class Command(BaseCommand):
|
||||
courses.update(self.get_courses(new_programs))
|
||||
catalog_courses.update(self.get_catalog_courses(new_programs))
|
||||
programs_by_type.update(self.get_programs_by_type(site, new_programs))
|
||||
programs_by_type_slug.update(self.get_programs_by_type_slug(site, new_programs))
|
||||
organizations.update(self.get_programs_by_organization(new_programs))
|
||||
|
||||
logger.info(u'Caching UUIDs for {total} programs for site {site_name}.'.format(
|
||||
@@ -123,6 +126,9 @@ class Command(BaseCommand):
|
||||
logger.info(text_type('Caching program UUIDs by {} program types.'.format(len(programs_by_type))))
|
||||
cache.set_many(programs_by_type, None)
|
||||
|
||||
logger.info(text_type('Caching program UUIDs by {} program type slugs.'.format(len(programs_by_type_slug))))
|
||||
cache.set_many(programs_by_type_slug, None)
|
||||
|
||||
logger.info(u'Caching programs uuids for {} organizations'.format(len(organizations)))
|
||||
cache.set_many(organizations, None)
|
||||
|
||||
@@ -263,6 +269,18 @@ class Command(BaseCommand):
|
||||
programs_by_type[cache_key].append(program['uuid'])
|
||||
return programs_by_type
|
||||
|
||||
def get_programs_by_type_slug(self, site, programs):
|
||||
"""
|
||||
Returns a dictionary mapping site-aware cache keys corresponding to program types
|
||||
to lists of program uuids with that type.
|
||||
"""
|
||||
programs_by_type_slug = defaultdict(list)
|
||||
for program in programs.values():
|
||||
program_slug = program.get('type_attrs', {}).get('slug')
|
||||
cache_key = PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL.format(site_id=site.id, program_slug=program_slug)
|
||||
programs_by_type_slug[cache_key].append(program['uuid'])
|
||||
return programs_by_type_slug
|
||||
|
||||
def get_programs_by_organization(self, programs):
|
||||
"""
|
||||
Returns a dictionary mapping organization keys to lists of program uuids authored by that org
|
||||
|
||||
@@ -14,6 +14,7 @@ from openedx.core.djangoapps.catalog.cache import (
|
||||
PATHWAY_CACHE_KEY_TPL,
|
||||
PROGRAM_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL,
|
||||
SITE_PATHWAY_IDS_CACHE_KEY_TPL,
|
||||
SITE_PROGRAM_UUIDS_CACHE_KEY_TPL
|
||||
)
|
||||
@@ -199,10 +200,15 @@ class TestCachePrograms(CatalogIntegrationMixin, CacheIsolationTestCase, SiteMix
|
||||
# program UUIDS by program type and a cached list of UUIDs by authoring organization
|
||||
for program in self.programs:
|
||||
program_type = normalize_program_type(program.get('type', 'None'))
|
||||
program_type_slug = program.get('type_attrs', {}).get('slug')
|
||||
program_type_cache_key = PROGRAMS_BY_TYPE_CACHE_KEY_TPL.format(
|
||||
site_id=self.site.id, program_type=program_type
|
||||
)
|
||||
program_type_slug_cache_key = PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL.format(
|
||||
site_id=self.site.id, program_slug=program_type_slug
|
||||
)
|
||||
self.assertIn(program['uuid'], cache.get(program_type_cache_key))
|
||||
self.assertIn(program['uuid'], cache.get(program_type_slug_cache_key))
|
||||
|
||||
for organization in program['authoring_organizations']:
|
||||
organization_cache_key = PROGRAMS_BY_ORGANIZATION_CACHE_KEY_TPL.format(
|
||||
|
||||
@@ -24,6 +24,7 @@ from openedx.core.djangoapps.catalog.cache import (
|
||||
PATHWAY_CACHE_KEY_TPL,
|
||||
PROGRAM_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL,
|
||||
SITE_PATHWAY_IDS_CACHE_KEY_TPL,
|
||||
SITE_PROGRAM_UUIDS_CACHE_KEY_TPL
|
||||
)
|
||||
@@ -33,7 +34,8 @@ from openedx.core.djangoapps.catalog.tests.factories import (
|
||||
CourseRunFactory,
|
||||
PathwayFactory,
|
||||
ProgramFactory,
|
||||
ProgramTypeFactory
|
||||
ProgramTypeFactory,
|
||||
ProgramTypeAttrsFactory
|
||||
)
|
||||
from openedx.core.djangoapps.catalog.tests.mixins import CatalogIntegrationMixin
|
||||
from openedx.core.djangoapps.catalog.utils import (
|
||||
@@ -50,6 +52,7 @@ from openedx.core.djangoapps.catalog.utils import (
|
||||
get_program_types,
|
||||
get_programs,
|
||||
get_programs_by_type,
|
||||
get_programs_by_type_slug,
|
||||
get_visible_sessions_for_entitlement,
|
||||
normalize_program_type,
|
||||
)
|
||||
@@ -830,7 +833,7 @@ class TestProgramCourseRunCrawling(TestCase):
|
||||
|
||||
@skip_unless_lms
|
||||
class TestGetProgramsByType(CacheIsolationTestCase):
|
||||
""" Test for the ``get_programs_by_type()`` function. """
|
||||
""" Test for the ``get_programs_by_type()`` and the ``get_programs_by_type_slug()`` functions. """
|
||||
ENABLED_CACHES = ['default']
|
||||
|
||||
@classmethod
|
||||
@@ -839,11 +842,26 @@ class TestGetProgramsByType(CacheIsolationTestCase):
|
||||
super(TestGetProgramsByType, cls).setUpClass()
|
||||
cls.site = SiteFactory()
|
||||
cls.other_site = SiteFactory()
|
||||
cls.masters_program_1 = ProgramFactory.create(type='Masters')
|
||||
cls.masters_program_2 = ProgramFactory.create(type='Masters')
|
||||
cls.masters_program_other_site = ProgramFactory.create(type='Masters')
|
||||
cls.bachelors_program = ProgramFactory.create(type='Bachelors')
|
||||
cls.no_type_program = ProgramFactory.create(type=None)
|
||||
cls.masters_program_1 = ProgramFactory.create(
|
||||
type='Masters',
|
||||
type_attrs=ProgramTypeAttrsFactory.create(slug="masters")
|
||||
)
|
||||
cls.masters_program_2 = ProgramFactory.create(
|
||||
type='Masters',
|
||||
type_attrs=ProgramTypeAttrsFactory.create(slug="masters")
|
||||
)
|
||||
cls.masters_program_other_site = ProgramFactory.create(
|
||||
type='Masters',
|
||||
type_attrs=ProgramTypeAttrsFactory.create(slug="masters")
|
||||
)
|
||||
cls.bachelors_program = ProgramFactory.create(
|
||||
type='Bachelors',
|
||||
type_attrs=ProgramTypeAttrsFactory.create(slug="bachelors")
|
||||
)
|
||||
cls.no_type_program = ProgramFactory.create(
|
||||
type=None,
|
||||
type_attrs=None
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
""" Loads program data into the cache before each test function. """
|
||||
@@ -865,41 +883,58 @@ class TestGetProgramsByType(CacheIsolationTestCase):
|
||||
cache.set_many(cached_programs, None)
|
||||
|
||||
programs_by_type = defaultdict(list)
|
||||
programs_by_type_slug = defaultdict(list)
|
||||
for program in all_programs:
|
||||
program_type = normalize_program_type(program.get('type'))
|
||||
program_type_slug = (program.get('type_attrs') or {}).get('slug')
|
||||
site_id = self.site.id
|
||||
|
||||
if program == self.masters_program_other_site:
|
||||
site_id = self.other_site.id
|
||||
|
||||
cache_key = PROGRAMS_BY_TYPE_CACHE_KEY_TPL.format(site_id=site_id, program_type=program_type)
|
||||
programs_by_type[cache_key].append(program['uuid'])
|
||||
program_type_cache_key = PROGRAMS_BY_TYPE_CACHE_KEY_TPL.format(
|
||||
site_id=site_id,
|
||||
program_type=program_type
|
||||
)
|
||||
program_type_slug_cache_key = PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL.format(
|
||||
site_id=site_id,
|
||||
program_slug=program_type_slug
|
||||
)
|
||||
programs_by_type[program_type_cache_key].append(program['uuid'])
|
||||
programs_by_type_slug[program_type_slug_cache_key].append(program['uuid'])
|
||||
|
||||
cache.set_many(programs_by_type, None)
|
||||
cache.set_many(programs_by_type_slug, None)
|
||||
|
||||
def test_get_masters_programs(self):
|
||||
expected_programs = [self.masters_program_1, self.masters_program_2]
|
||||
six.assertCountEqual(self, expected_programs, get_programs_by_type(self.site, 'masters'))
|
||||
six.assertCountEqual(self, expected_programs, get_programs_by_type_slug(self.site, 'masters'))
|
||||
|
||||
def test_get_bachelors_programs(self):
|
||||
expected_programs = [self.bachelors_program]
|
||||
self.assertEqual(expected_programs, get_programs_by_type(self.site, 'bachelors'))
|
||||
self.assertEqual(expected_programs, get_programs_by_type_slug(self.site, 'bachelors'))
|
||||
|
||||
def test_get_no_such_type_programs(self):
|
||||
expected_programs = []
|
||||
self.assertEqual(expected_programs, get_programs_by_type(self.site, 'doctorate'))
|
||||
self.assertEqual(expected_programs, get_programs_by_type_slug(self.site, 'doctorate'))
|
||||
|
||||
def test_get_masters_programs_other_site(self):
|
||||
expected_programs = [self.masters_program_other_site]
|
||||
self.assertEqual(expected_programs, get_programs_by_type(self.other_site, 'masters'))
|
||||
self.assertEqual(expected_programs, get_programs_by_type_slug(self.other_site, 'masters'))
|
||||
|
||||
def test_get_programs_null_type(self):
|
||||
expected_programs = [self.no_type_program]
|
||||
self.assertEqual(expected_programs, get_programs_by_type(self.site, None))
|
||||
self.assertEqual(expected_programs, get_programs_by_type_slug(self.site, None))
|
||||
|
||||
def test_get_programs_false_type(self):
|
||||
expected_programs = []
|
||||
self.assertEqual(expected_programs, get_programs_by_type(self.site, False))
|
||||
self.assertEqual(expected_programs, get_programs_by_type_slug(self.site, False))
|
||||
|
||||
def test_normalize_program_type(self):
|
||||
self.assertEqual('none', normalize_program_type(None))
|
||||
|
||||
@@ -23,6 +23,7 @@ from openedx.core.djangoapps.catalog.cache import (
|
||||
PATHWAY_CACHE_KEY_TPL,
|
||||
PROGRAM_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_CACHE_KEY_TPL,
|
||||
PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL,
|
||||
SITE_PATHWAY_IDS_CACHE_KEY_TPL,
|
||||
SITE_PROGRAM_UUIDS_CACHE_KEY_TPL
|
||||
)
|
||||
@@ -163,6 +164,29 @@ def get_programs_by_type(site, program_type):
|
||||
return get_programs_by_uuids(uuids)
|
||||
|
||||
|
||||
def get_programs_by_type_slug(site, program_type_slug):
|
||||
"""
|
||||
Keyword Arguments:
|
||||
site (Site): The corresponding Site object to fetch programs for.
|
||||
program_type_slug (string): The type slug that matching programs must have.
|
||||
|
||||
Returns:
|
||||
A list of programs for the given site with the given type slug.
|
||||
|
||||
Slugs are a consistent identifier whereas type (used in `get_programs_by_type`)
|
||||
may be translated.
|
||||
"""
|
||||
program_type_slug_cache_key = PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL.format(
|
||||
site_id=site.id, program_slug=program_type_slug
|
||||
)
|
||||
uuids = cache.get(program_type_slug_cache_key, [])
|
||||
if not uuids:
|
||||
logger.warning(text_type(
|
||||
'Failed to get program UUIDs from cache for site {} and type slug {}'.format(site.id, program_type_slug)
|
||||
))
|
||||
return get_programs_by_uuids(uuids)
|
||||
|
||||
|
||||
def get_programs_by_uuids(uuids):
|
||||
"""
|
||||
Gets a list of programs for the provided uuids
|
||||
|
||||
30
openedx/core/djangoapps/programs/api.py
Normal file
30
openedx/core/djangoapps/programs/api.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Python APIs exposed by the Programs app to other in-process apps.
|
||||
"""
|
||||
|
||||
from .utils import is_user_enrolled_in_program_type as _is_user_enrolled_in_program_type
|
||||
|
||||
|
||||
def is_user_enrolled_in_program_type(user, program_type_slug, paid_modes=False, enrollments=None, entitlements=None):
|
||||
"""
|
||||
This method will look at the learners Enrollments and Entitlements to determine
|
||||
if a learner is enrolled in a Program of the given type.
|
||||
|
||||
NOTE: This method relies on the Program Cache right now. The goal is to move away from this
|
||||
in the future.
|
||||
|
||||
Arguments:
|
||||
user (User): The user we are looking for.
|
||||
program_type_slug (str): The slug of the Program type we are looking for.
|
||||
paid_modes (bool): Request if the user is enrolled in a Program in a paid mode, False by default.
|
||||
enrollments (List[Dict]): Takes a serialized list of CourseEnrollments linked to the user
|
||||
entitlements (List[CourseEntitlement]): Take a list of CourseEntitlement objects linked to the user
|
||||
|
||||
NOTE: Both enrollments and entitlements will be collected if they are not passed in. They are available
|
||||
as parameters in case they were already collected, to save duplicate queries in high traffic areas.
|
||||
|
||||
Returns:
|
||||
bool: True is the user is enrolled in programs of the requested type
|
||||
"""
|
||||
|
||||
return _is_user_enrolled_in_program_type(user, program_type_slug, paid_modes, enrollments, entitlements)
|
||||
@@ -1587,23 +1587,23 @@ class TestProgramEnrollment(SharedModuleStoreTestCase):
|
||||
|
||||
def test_user_not_in_program(self, mock_get_programs_by_type):
|
||||
mock_get_programs_by_type.return_value = [self.program]
|
||||
self.assertFalse(is_user_enrolled_in_program_type(user=self.user, program_type=self.MICROBACHELORS))
|
||||
self.assertFalse(is_user_enrolled_in_program_type(user=self.user, program_type_slug=self.MICROBACHELORS))
|
||||
|
||||
def test_user_enrolled_in_mb_program(self, mock_get_programs_by_type):
|
||||
CourseEnrollmentFactory.create(user=self.user, course_id=self.course_run.id, mode=CourseMode.VERIFIED)
|
||||
mock_get_programs_by_type.return_value = [self.program]
|
||||
self.assertTrue(is_user_enrolled_in_program_type(user=self.user, program_type=self.MICROBACHELORS))
|
||||
self.assertTrue(is_user_enrolled_in_program_type(user=self.user, program_type_slug=self.MICROBACHELORS))
|
||||
|
||||
def test_user_enrolled_unpaid_in_program(self, mock_get_programs_by_type):
|
||||
CourseEnrollmentFactory.create(user=self.user, course_id=self.course_run.id, mode=CourseMode.AUDIT)
|
||||
mock_get_programs_by_type.return_value = [self.program]
|
||||
self.assertTrue(is_user_enrolled_in_program_type(user=self.user, program_type=self.MICROBACHELORS))
|
||||
self.assertTrue(is_user_enrolled_in_program_type(user=self.user, program_type_slug=self.MICROBACHELORS))
|
||||
|
||||
def test_user_enrolled_unpaid_in_program_paid_only_request(self, mock_get_programs_by_type):
|
||||
CourseEnrollmentFactory.create(user=self.user, course_id=self.course_run.id, mode=CourseMode.AUDIT)
|
||||
mock_get_programs_by_type.return_value = [self.program]
|
||||
self.assertFalse(
|
||||
is_user_enrolled_in_program_type(user=self.user, program_type=self.MICROBACHELORS, paid_modes=True)
|
||||
is_user_enrolled_in_program_type(user=self.user, program_type_slug=self.MICROBACHELORS, paid_modes=True)
|
||||
)
|
||||
|
||||
def test_user_with_entitlement_no_enrollment(self, mock_get_programs_by_type):
|
||||
@@ -1613,4 +1613,4 @@ class TestProgramEnrollment(SharedModuleStoreTestCase):
|
||||
course_uuid=self.program['courses'][0]['uuid']
|
||||
)
|
||||
mock_get_programs_by_type.return_value = [self.program]
|
||||
self.assertTrue(is_user_enrolled_in_program_type(user=self.user, program_type=self.MICROBACHELORS))
|
||||
self.assertTrue(is_user_enrolled_in_program_type(user=self.user, program_type_slug=self.MICROBACHELORS))
|
||||
|
||||
@@ -22,16 +22,17 @@ from pytz import utc
|
||||
from requests.exceptions import ConnectionError, Timeout
|
||||
from six.moves.urllib.parse import urljoin, urlparse, urlunparse # pylint: disable=import-error
|
||||
|
||||
from course_modes.api import get_paid_modes_for_course
|
||||
from course_modes.models import CourseMode
|
||||
from entitlements.api import get_active_entitlement_list_for_user
|
||||
from entitlements.models import CourseEntitlement
|
||||
from lms.djangoapps.certificates import api as certificate_api
|
||||
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.utils import (
|
||||
get_fulfillable_course_runs_for_entitlement,
|
||||
get_programs,
|
||||
get_programs_by_type
|
||||
)
|
||||
from openedx.core.djangoapps.certificates.api import available_date_for_certificate
|
||||
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
|
||||
@@ -901,9 +902,9 @@ class ProgramMarketingDataExtender(ProgramDataExtender):
|
||||
self.instructors.append(instructor)
|
||||
|
||||
|
||||
def is_user_enrolled_in_program_type(user, program_type, paid_modes=False, enrollments=None, entitlements=None):
|
||||
def is_user_enrolled_in_program_type(user, program_type_slug, paid_modes=False, enrollments=None, entitlements=None):
|
||||
"""
|
||||
This method will Look at the learners Enrollments and Entitlements to determine
|
||||
This method will look at the learners Enrollments and Entitlements to determine
|
||||
if a learner is enrolled in a Program of the given type.
|
||||
|
||||
NOTE: This method relies on the Program Cache right now. The goal is to move away from this
|
||||
@@ -911,15 +912,20 @@ def is_user_enrolled_in_program_type(user, program_type, paid_modes=False, enrol
|
||||
|
||||
Arguments:
|
||||
user (User): The user we are looking for.
|
||||
program_type (String): The Program type we are looking for.
|
||||
program_type_slug (str): The slug of the Program type we are looking for.
|
||||
paid_modes (bool): Request if the user is enrolled in a Program in a paid mode, False by default.
|
||||
enrollments (List[Dict]): Takes a serialized list of CourseEnrollments linked to the user
|
||||
entitlements (List[CourseEntitlement]): Take a list of CourseEntitlement objects linked to the user
|
||||
|
||||
NOTE: Both enrollments and entitlements will be collected if they are not passed in. They are available
|
||||
as parameters in case they were already collected, to save duplicate queries in high traffic areas.
|
||||
|
||||
Returns:
|
||||
bool: True is the user is enrolled in programs of the requested Type
|
||||
bool: True is the user is enrolled in programs of the requested type
|
||||
"""
|
||||
course_runs = set()
|
||||
course_uuids = set()
|
||||
programs = get_programs_by_type(Site.objects.get_current(), program_type)
|
||||
programs = get_programs_by_type(Site.objects.get_current(), program_type_slug)
|
||||
if not programs:
|
||||
return False
|
||||
|
||||
@@ -941,7 +947,7 @@ def is_user_enrolled_in_program_type(user, program_type, paid_modes=False, enrol
|
||||
course_run_id = enrollment['course_details']['course_id']
|
||||
if paid_modes:
|
||||
course_run_key = CourseKey.from_string(course_run_id)
|
||||
paid_modes = [mode.slug for mode in CourseMode.paid_modes_for_course(course_run_key)]
|
||||
paid_modes = [mode.slug for mode in get_paid_modes_for_course(course_run_key)]
|
||||
if enrollment['mode'] in paid_modes and course_run_id in course_runs:
|
||||
return True
|
||||
elif course_run_id in course_runs:
|
||||
|
||||
Reference in New Issue
Block a user