Skip to content

Commit

Permalink
Merge pull request openedx#17149 from edx/jlajoie/LEARNER-3661
Browse files Browse the repository at this point in the history
LEARNER-3661: Removes sessions a user has already claimed
  • Loading branch information
jlajoie authored Jan 17, 2018
2 parents f78d5d2 + ed1d33e commit 8623d6e
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 14 deletions.
44 changes: 36 additions & 8 deletions common/djangoapps/student/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,28 @@
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
Expand Down Expand Up @@ -350,7 +354,8 @@ def test_pre_requisites_appear_on_dashboard(self):
@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
Expand All @@ -359,9 +364,9 @@ def test_unfulfilled_entitlement(self, mock_course_overview, mock_pseudo_session
- 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',
Expand All @@ -380,6 +385,29 @@ def test_unfulfilled_entitlement(self, mock_course_overview, mock_pseudo_session
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):
Expand Down
16 changes: 10 additions & 6 deletions openedx/core/djangoapps/catalog/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
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__)

Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down

0 comments on commit 8623d6e

Please sign in to comment.