Merge pull request #17149 from edx/jlajoie/LEARNER-3661
LEARNER-3661: Removes sessions a user has already claimed
This commit is contained in:
@@ -12,24 +12,28 @@ from django.core.urlresolvers import reverse
|
||||
from django.test import RequestFactory, TestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.timezone import now
|
||||
from edx_oauth2_provider.constants import AUTHORIZED_CLIENTS_SESSION_KEY
|
||||
from edx_oauth2_provider.tests.factories import ClientFactory, TrustedClientFactory
|
||||
from milestones.tests.utils import MilestonesTestCaseMixin
|
||||
from mock import patch
|
||||
from opaque_keys import InvalidKeyError
|
||||
from pyquery import PyQuery as pq
|
||||
|
||||
from bulk_email.models import BulkEmailFlag
|
||||
from course_modes.models import CourseMode
|
||||
from edx_oauth2_provider.constants import AUTHORIZED_CLIENTS_SESSION_KEY
|
||||
from edx_oauth2_provider.tests.factories import (ClientFactory,
|
||||
TrustedClientFactory)
|
||||
from entitlements.tests.factories import CourseEntitlementFactory
|
||||
from milestones.tests.utils import MilestonesTestCaseMixin
|
||||
from openedx.core.djangoapps.catalog.tests.factories import ProgramFactory
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
|
||||
from pyquery import PyQuery as pq
|
||||
from student.cookies import get_user_info_cookie_data
|
||||
from student.helpers import DISABLE_UNENROLL_CERT_STATES
|
||||
from student.models import CourseEnrollment, UserProfile
|
||||
from student.signals import REFUND_ORDER
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from util.milestones_helpers import get_course_milestones, remove_prerequisite_course, set_prerequisite_courses
|
||||
from util.milestones_helpers import (get_course_milestones,
|
||||
remove_prerequisite_course,
|
||||
set_prerequisite_courses)
|
||||
from util.testing import UrlResetMixin
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
@@ -350,7 +354,8 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
@patch('student.views.get_visible_sessions_for_entitlement')
|
||||
@patch('student.views.get_pseudo_session_for_entitlement')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
def test_unfulfilled_entitlement(self, mock_course_overview, mock_pseudo_session, mock_course_runs, mock_get_programs):
|
||||
def test_unfulfilled_entitlement(self, mock_course_overview, mock_pseudo_session,
|
||||
mock_course_runs, mock_get_programs):
|
||||
"""
|
||||
When a learner has an unfulfilled entitlement, their course dashboard should have:
|
||||
- a hidden 'View Course' button
|
||||
@@ -359,9 +364,9 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
- a related programs message
|
||||
"""
|
||||
program = ProgramFactory()
|
||||
CourseEntitlementFactory(user=self.user, course_uuid=program['courses'][0]['uuid'])
|
||||
CourseEntitlementFactory.create(user=self.user, course_uuid=program['courses'][0]['uuid'])
|
||||
mock_get_programs.return_value = [program]
|
||||
mock_course_overview.return_value = CourseOverviewFactory(start=self.TOMORROW)
|
||||
mock_course_overview.return_value = CourseOverviewFactory.create(start=self.TOMORROW)
|
||||
mock_course_runs.return_value = [
|
||||
{
|
||||
'key': 'course-v1:FAKE+FA1-MA1.X+3T2017',
|
||||
@@ -380,6 +385,29 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
self.assertIn('<div class="course-entitlement-selection-container ">', response.content)
|
||||
self.assertIn('Related Programs:', response.content)
|
||||
|
||||
# If an entitlement has already been redeemed by the user for a course run, do not let the run be selectable
|
||||
enrollment = CourseEnrollmentFactory(
|
||||
user=self.user, course_id=unicode(mock_course_overview.return_value.id), mode=CourseMode.VERIFIED
|
||||
)
|
||||
CourseEntitlementFactory.create(
|
||||
user=self.user, course_uuid=program['courses'][0]['uuid'], enrollment_course_run=enrollment
|
||||
)
|
||||
|
||||
mock_course_runs.return_value = [
|
||||
{
|
||||
'key': 'course-v1:edX+toy+2012_Fall',
|
||||
'enrollment_end': str(self.TOMORROW),
|
||||
'pacing_type': 'instructor_paced',
|
||||
'type': 'verified'
|
||||
}
|
||||
]
|
||||
response = self.client.get(self.path)
|
||||
# There should be two entitlements on the course page, one prompting for a mandatory session, but no
|
||||
# select option for the courses as there is only the single course run which has already been redeemed
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 2)
|
||||
self.assertIn('You must select a session to access the course.', response.content)
|
||||
self.assertNotIn('To access the course, select a session.', response.content)
|
||||
|
||||
@patch('student.views.get_visible_sessions_for_entitlement')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
def test_unfulfilled_expired_entitlement(self, mock_course_overview, mock_course_runs):
|
||||
|
||||
@@ -8,15 +8,14 @@ from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from edx_rest_api_client.client import EdxRestApiClient
|
||||
from pytz import UTC
|
||||
|
||||
from openedx.core.djangoapps.catalog.cache import (
|
||||
PROGRAM_CACHE_KEY_TPL,
|
||||
SITE_PROGRAM_UUIDS_CACHE_KEY_TPL
|
||||
)
|
||||
from openedx.core.djangoapps.catalog.cache import (PROGRAM_CACHE_KEY_TPL,
|
||||
SITE_PROGRAM_UUIDS_CACHE_KEY_TPL)
|
||||
from openedx.core.djangoapps.catalog.models import CatalogIntegration
|
||||
from openedx.core.lib.edx_api_utils import get_edx_api_data
|
||||
from openedx.core.lib.token_utils import JwtBuilder
|
||||
from pytz import UTC
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -276,12 +275,16 @@ def get_fulfillable_course_runs_for_entitlement(entitlement, course_runs):
|
||||
2) A user can enroll in
|
||||
3) A user can upgrade in
|
||||
4) Are published
|
||||
5) Are not enrolled in already for an active session
|
||||
|
||||
These are the only sessions that can be selected for an entitlement.
|
||||
"""
|
||||
|
||||
enrollable_sessions = []
|
||||
|
||||
enrollments_for_user = CourseEnrollment.enrollments_for_user(entitlement.user).filter(mode=entitlement.mode)
|
||||
enrolled_sessions = frozenset([str(e.course_id) for e in enrollments_for_user])
|
||||
|
||||
# Only show published course runs that can still be enrolled and upgraded
|
||||
now = datetime.datetime.now(UTC)
|
||||
for course_run in course_runs:
|
||||
@@ -295,7 +298,8 @@ def get_fulfillable_course_runs_for_entitlement(entitlement, course_runs):
|
||||
enrollment_start = course_run.get('enrollment_start')
|
||||
enrollment_end = course_run.get('enrollment_end')
|
||||
can_enroll = ((not enrollment_start or datetime_parse(enrollment_start) < now)
|
||||
and (not enrollment_end or datetime_parse(enrollment_end) > now))
|
||||
and (not enrollment_end or datetime_parse(enrollment_end) > now)
|
||||
and course_run.get('key') not in enrolled_sessions)
|
||||
|
||||
# Only upgrade-able courses will be displayed
|
||||
can_upgrade = False
|
||||
|
||||
Reference in New Issue
Block a user