Commit dc280977 by Albert St. Aubin

Updated tests WIP

parent 242e058f
......@@ -7,6 +7,9 @@ from django.core.urlresolvers import reverse
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from entitlements.tests.factories import CourseEntitlementFactory
from entitlements.models import CourseEntitlement
from entitlements.api.v1.serializers import CourseEntitlementSerializer
from student.tests.factories import CourseEnrollmentFactory, UserFactory, TEST_PASSWORD
# Entitlements is not in CMS' INSTALLED_APPS so these imports will error during test collection
......@@ -151,6 +154,7 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
entitlement = CourseEntitlementFactory()
CourseEntitlementFactory.create_batch(2)
CourseEntitlementFactory()
url = reverse(self.ENTITLEMENTS_DETAILS_PATH, args=[str(entitlement.uuid)])
response = self.client.get(
......@@ -195,3 +199,124 @@ class EntitlementViewSetTest(ModuleStoreTestCase):
course_entitlement.refresh_from_db()
assert course_entitlement.expired_at is not None
assert course_entitlement.enrollment_course_run is None
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@patch("openedx.core.djangoapps.catalog.utils.get_course_runs_for_course")
class EntitlementEnrollmentViewSetTest(ModuleStoreTestCase):
ENTITLEMENTS_ENROLLMENT_NAMESPACE = 'entitlements_api:v1:enrollments'
def setUp(self):
super(EntitlementEnrollmentViewSetTest, self).setUp()
self.user = UserFactory()
self.client.login(username=self.user.username, password=TEST_PASSWORD)
self.course = CourseFactory.create(org='edX', number='DemoX', display_name='Demo_Course')
self.course2 = CourseFactory.create(org='edX', number='DemoX2', display_name='Demo_Course 2')
def test_user_can_enroll(self, mock_get_course_runs):
course_entitlement = CourseEntitlementFactory(
user=self.user
)
url = reverse(
self.ENTITLEMENTS_ENROLLMENT_NAMESPACE,
args=[str(course_entitlement.uuid)]
)
assert course_entitlement.enrollment_course_run is None
mock_get_course_runs.method.return_value = [
{'key': str(self.course.id)}
]
data = {
'course_run_id': str(self.course.id)
}
response = self.client.post(
url,
data=json.dumps(data),
content_type='application/json',
)
course_entitlement.refresh_from_db()
assert response.status_code == 201
assert CourseEnrollment.is_enrolled(self.user, self.course.id)
assert course_entitlement.enrollment_course_run is not None
def test_user_can_unenroll(self, mock_get_course_runs):
course_entitlement = CourseEntitlementFactory(
user=self.user
)
url = reverse(
self.ENTITLEMENTS_ENROLLMENT_NAMESPACE,
args=[str(course_entitlement.uuid)]
)
assert course_entitlement.enrollment_course_run is None
mock_get_course_runs.return_value = [
{'key': str(self.course.id)}
]
data = {
'course_run_id': str(self.course.id)
}
response = self.client.post(
url,
data=json.dumps(data),
content_type='application/json',
)
course_entitlement.refresh_from_db()
assert response.status_code == 201
assert CourseEnrollment.is_enrolled(self.user, self.course.id)
response = self.client.delete(
url,
content_type='application/json',
)
assert response.status_code == 204
course_entitlement.refresh_from_db()
assert not CourseEnrollment.is_enrolled(self.user, self.course.id)
assert course_entitlement.enrollment_course_run is None
def test_user_can_switch(self, mock_get_course_runs):
course_entitlement = CourseEntitlementFactory(
user=self.user
)
url = reverse(
self.ENTITLEMENTS_ENROLLMENT_NAMESPACE,
args=[str(course_entitlement.uuid)]
)
assert course_entitlement.enrollment_course_run is None
mock_get_course_runs.return_value = [
{'key': str(self.course.id)},
{'key': str(self.course2.id)}
]
data = {
'course_run_id': str(self.course.id)
}
response = self.client.post(
url,
data=json.dumps(data),
content_type='application/json',
)
course_entitlement.refresh_from_db()
assert response.status_code == 201
assert CourseEnrollment.is_enrolled(self.user, self.course.id)
data = {
'course_run_id': str(self.course2.id)
}
response = self.client.post(
url,
data=json.dumps(data),
content_type='application/json',
)
assert response.status_code == 201
course_entitlement.refresh_from_db()
assert CourseEnrollment.is_enrolled(self.user, self.course2.id)
assert course_entitlement.enrollment_course_run is not None
print course_entitlement.enrollment_course_run.course_id
......@@ -3,9 +3,13 @@ import logging
from django.utils import timezone
from django_filters.rest_framework import DjangoFilterBackend
from edx_rest_framework_extensions.authentication import JwtAuthentication
from opaque_keys.edx.keys import CourseKey
from rest_framework import permissions, viewsets, status
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication
from student.models import CourseEnrollmentException
# from enrollment.errors import CourseEnrollmentError, CourseEnrollmentExistsError, CourseModeNotFoundError
# from openedx.core.lib.exceptions import CourseNotFoundError
from openedx.core.djangoapps.catalog.utils import get_course_runs_for_course
from entitlements.api.v1.filters import CourseEntitlementFilter
......@@ -22,8 +26,9 @@ log = logging.getLogger(__name__)
class EntitlementViewSet(viewsets.ModelViewSet):
authentication_classes = (JwtAuthentication, SessionAuthenticationCrossDomainCsrf,)
permission_classes = (permissions.IsAuthenticated, IsAdminOrAuthenticatedReadOnly,)
authentication_classes = (JwtAuthentication, SessionAuthentication,)
permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser,)
queryset = CourseEntitlement.objects.all().select_related('user')
lookup_value_regex = '[0-9a-f-]+'
lookup_field = 'uuid'
serializer_class = CourseEntitlementSerializer
......@@ -71,12 +76,36 @@ class EntitlementEnrollmentViewSet(viewsets.GenericViewSet):
queryset = CourseEntitlement.objects.all()
serializer_class = CourseEntitlementSerializer
def _verify_course_run_for_entitlement(self, entitlement, course_session_id):
course_run_valid = False
course_runs = get_course_runs_for_course(entitlement.course_uuid)
for run in course_runs:
if course_session_id == run.get('key', ''):
course_run_valid = True
break
return course_run_valid
def _enroll_entitlement(self, entitlement, course_session_key, user):
enrollment = CourseEnrollment.enroll(
user=user,
course_key=course_session_key,
mode=entitlement.mode,
)
try:
enrollment = CourseEnrollment.enroll(
user=user,
course_key=course_session_key,
mode=entitlement.mode,
)
except CourseEnrollmentException:
message = (
'Course Entitlement Enroll for {username} failed for course: {course_id}, '
'mode: {mode}, and entitlement: {entitlement}'
).format(
username=user.username,
course_id=course_session_key,
mode=entitlement.mode,
entitlement=entitlement.uuid
)
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={'message': message}
)
CourseEntitlement.set_enrollment(entitlement, enrollment)
......@@ -103,37 +132,42 @@ class EntitlementEnrollmentViewSet(viewsets.GenericViewSet):
)
# Verify the course run ID is of the same type as the Course entitlement.
course_run_valid = False
course_runs = get_course_runs_for_course(entitlement.course_uuid)
for run in course_runs:
if course_session_id == run.get('key', ''):
course_run_valid = True
course_run_valid = self._verify_course_run_for_entitlement(entitlement, course_session_id)
if not course_run_valid:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data="The Course Run ID is not a match for this Course Entitlement."
data={
'message': "The Course Run ID is not a match for this Course Entitlement."
}
)
# Determine if this is a Switch session or a simple enroll and handle both.
try:
course_run_string = CourseKey.from_string(course_session_id)
except CourseKey.InvalidKeyError:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={
'message': u"Invalid '{course_id}'".format(course_id=course_session_id)
}
)
if entitlement.enrollment_course_run is None:
self._enroll_entitlement(
entitlement=entitlement,
course_session_key=CourseKey.from_string(course_session_id),
course_session_key=course_run_string,
user=request.user
)
elif entitlement.enrollment_course_run.course_id != course_session_id:
self._unenroll_entitlement(
entitlement=entitlement,
course_session_key=entitlement.enrollment_course_run.course_id,
user=request.user
)
self._enroll_entitlement(
entitlement=entitlement,
course_session_key=course_run_string,
user=request.user
)
else:
if entitlement.enrollment_course_run.course_id != course_session_id:
self._unenroll_entitlement(
entitlement=entitlement,
course_session_key=entitlement.enrollment_course_run.course_id,
user=request.user
)
self._enroll_entitlement(
entitlement=entitlement,
course_session_key=CourseKey.from_string(course_session_id),
user=request.user
)
return Response(
status=status.HTTP_201_CREATED,
......@@ -157,7 +191,7 @@ class EntitlementEnrollmentViewSet(viewsets.GenericViewSet):
)
if entitlement.enrollment_course_run is None:
return Response()
return Response(status=status.HTTP_204_NO_CONTENT)
self._unenroll_entitlement(
entitlement=entitlement,
......
......@@ -26,21 +26,6 @@ class CourseEntitlement(TimeStampedModel):
order_number = models.CharField(max_length=128, null=True)
@classmethod
def get_active_user_course_entitlements(cls, user, course_uuid):
"""
Returns all the available sessions for a given course.
"""
try:
entitlement = cls.objects.get(
user=user,
course_uuid=course_uuid,
)
return entitlement
except cls.DoesNotExist:
return None
@classmethod
def set_enrollment(cls, entitlement, enrollment):
"""
Fulfills an entitlement by specifying a session.
......
......@@ -319,7 +319,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
If we remove the prerequisite and access the dashboard again, the prerequisite
should not appear.
"""
self.pre_requisite_course = CourseFactory.create(org='edx', number='999', display_name='Pre requisite Course')
self.pre_requisite_course =CourseFactory.create(org='edx', number='999', display_name='Pre requisite Course')
self.course = CourseFactory.create(
org='edx',
number='998',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment