Merge pull request #16359 from edx/aj/LEARNER-2661
Added Entitlement API
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import CourseEntitlement
|
||||
|
||||
|
||||
|
||||
0
common/djangoapps/entitlements/api/__init__.py
Normal file
0
common/djangoapps/entitlements/api/__init__.py
Normal file
5
common/djangoapps/entitlements/api/urls.py
Normal file
5
common/djangoapps/entitlements/api/urls.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.conf.urls import include, url
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^v1/', include('entitlements.api.v1.urls', namespace='v1')),
|
||||
]
|
||||
0
common/djangoapps/entitlements/api/v1/__init__.py
Normal file
0
common/djangoapps/entitlements/api/v1/__init__.py
Normal file
41
common/djangoapps/entitlements/api/v1/filters.py
Normal file
41
common/djangoapps/entitlements/api/v1/filters.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from django_filters import rest_framework as filters
|
||||
|
||||
from entitlements.models import CourseEntitlement
|
||||
|
||||
|
||||
class CharListFilter(filters.CharFilter):
|
||||
""" Filters a field via a comma-delimited list of values. """
|
||||
|
||||
def filter(self, qs, value): # pylint: disable=method-hidden
|
||||
if value not in (None, ''):
|
||||
value = value.split(',')
|
||||
|
||||
return super(CharListFilter, self).filter(qs, value)
|
||||
|
||||
|
||||
class UUIDListFilter(CharListFilter):
|
||||
""" Filters a field via a comma-delimited list of UUIDs. """
|
||||
|
||||
def __init__(self, name='uuid', label=None, widget=None, method=None, lookup_expr='in', required=False,
|
||||
distinct=False, exclude=False, **kwargs):
|
||||
super(UUIDListFilter, self).__init__(
|
||||
name=name,
|
||||
label=label,
|
||||
widget=widget,
|
||||
method=method,
|
||||
lookup_expr=lookup_expr,
|
||||
required=required,
|
||||
distinct=distinct,
|
||||
exclude=exclude,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class CourseEntitlementFilter(filters.FilterSet):
|
||||
|
||||
uuid = UUIDListFilter()
|
||||
course_uuid = UUIDListFilter()
|
||||
|
||||
class Meta:
|
||||
model = CourseEntitlement
|
||||
fields = ('uuid',)
|
||||
21
common/djangoapps/entitlements/api/v1/serializers.py
Normal file
21
common/djangoapps/entitlements/api/v1/serializers.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework import serializers
|
||||
|
||||
from entitlements.models import CourseEntitlement
|
||||
|
||||
|
||||
class CourseEntitlementSerializer(serializers.ModelSerializer):
|
||||
user = serializers.SlugRelatedField(slug_field='username', queryset=get_user_model().objects.all())
|
||||
|
||||
class Meta:
|
||||
model = CourseEntitlement
|
||||
fields = (
|
||||
'user',
|
||||
'uuid',
|
||||
'course_uuid',
|
||||
'expired_at',
|
||||
'created',
|
||||
'modified',
|
||||
'mode',
|
||||
'order_number'
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
import unittest
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import RequestFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
from entitlements.api.v1.serializers import CourseEntitlementSerializer
|
||||
from entitlements.tests.factories import CourseEntitlementFactory
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
class EntitlementsSerializerTests(ModuleStoreTestCase):
|
||||
def setUp(self):
|
||||
super(EntitlementsSerializerTests, self).setUp()
|
||||
|
||||
def test_data(self):
|
||||
entitlement = CourseEntitlementFactory()
|
||||
request = RequestFactory().get('')
|
||||
serializer = CourseEntitlementSerializer(entitlement, context={'request': request})
|
||||
|
||||
expected = {
|
||||
'user': entitlement.user.username,
|
||||
'uuid': str(entitlement.uuid),
|
||||
'expired_at': entitlement.expired_at,
|
||||
'course_uuid': str(entitlement.course_uuid),
|
||||
'mode': entitlement.mode,
|
||||
'order_number': entitlement.order_number,
|
||||
'created': entitlement.created.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
||||
'modified': entitlement.modified.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
||||
}
|
||||
|
||||
assert serializer.data == expected
|
||||
139
common/djangoapps/entitlements/api/v1/tests/test_views.py
Normal file
139
common/djangoapps/entitlements/api/v1/tests/test_views.py
Normal file
@@ -0,0 +1,139 @@
|
||||
import json
|
||||
import unittest
|
||||
import uuid
|
||||
|
||||
from django.conf import settings
|
||||
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
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
class EntitlementViewSetTest(ModuleStoreTestCase):
|
||||
ENTITLEMENTS_DETAILS_PATH = 'entitlements_api:v1:entitlements-detail'
|
||||
|
||||
def setUp(self):
|
||||
super(EntitlementViewSetTest, self).setUp()
|
||||
self.user = UserFactory(is_staff=True)
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
self.course = CourseFactory()
|
||||
self.entitlements_list_url = reverse('entitlements_api:v1:entitlements-list')
|
||||
|
||||
def _get_data_set(self, user, course_uuid):
|
||||
"""
|
||||
Get a basic data set for an entitlement
|
||||
"""
|
||||
return {
|
||||
"user": user.username,
|
||||
"mode": "verified",
|
||||
"course_uuid": course_uuid,
|
||||
"order_number": "EDX-1001"
|
||||
}
|
||||
|
||||
def test_auth_required(self):
|
||||
self.client.logout()
|
||||
response = self.client.get(self.entitlements_list_url)
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_staff_user_required(self):
|
||||
not_staff_user = UserFactory()
|
||||
self.client.login(username=not_staff_user.username, password=UserFactory._DEFAULT_PASSWORD)
|
||||
response = self.client.get(self.entitlements_list_url)
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_add_entitlement_with_missing_data(self):
|
||||
entitlement_data_missing_parts = self._get_data_set(self.user, str(uuid.uuid4()))
|
||||
entitlement_data_missing_parts.pop('mode')
|
||||
entitlement_data_missing_parts.pop('course_uuid')
|
||||
|
||||
response = self.client.post(
|
||||
self.entitlements_list_url,
|
||||
data=json.dumps(entitlement_data_missing_parts),
|
||||
content_type='application/json',
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_add_entitlement(self):
|
||||
course_uuid = uuid.uuid4()
|
||||
entitlement_data = self._get_data_set(self.user, str(course_uuid))
|
||||
|
||||
response = self.client.post(
|
||||
self.entitlements_list_url,
|
||||
data=json.dumps(entitlement_data),
|
||||
content_type='application/json',
|
||||
)
|
||||
assert response.status_code == 201
|
||||
results = response.data
|
||||
|
||||
course_entitlement = CourseEntitlement.objects.get(
|
||||
user=self.user,
|
||||
course_uuid=course_uuid
|
||||
)
|
||||
assert results == CourseEntitlementSerializer(course_entitlement).data
|
||||
|
||||
def test_get_entitlements(self):
|
||||
entitlements = CourseEntitlementFactory.create_batch(2)
|
||||
|
||||
response = self.client.get(
|
||||
self.entitlements_list_url,
|
||||
content_type='application/json',
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
results = response.data.get('results', [])
|
||||
assert results == CourseEntitlementSerializer(entitlements, many=True).data
|
||||
|
||||
def test_get_entitlement_by_uuid(self):
|
||||
entitlement = CourseEntitlementFactory()
|
||||
CourseEntitlementFactory.create_batch(2)
|
||||
|
||||
CourseEntitlementFactory()
|
||||
url = reverse(self.ENTITLEMENTS_DETAILS_PATH, args=[str(entitlement.uuid)])
|
||||
|
||||
response = self.client.get(
|
||||
url,
|
||||
content_type='application/json',
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
results = response.data
|
||||
assert results == CourseEntitlementSerializer(entitlement).data
|
||||
|
||||
def test_delete_and_revoke_entitlement(self):
|
||||
course_entitlement = CourseEntitlementFactory()
|
||||
url = reverse(self.ENTITLEMENTS_DETAILS_PATH, args=[str(course_entitlement.uuid)])
|
||||
|
||||
response = self.client.delete(
|
||||
url,
|
||||
content_type='application/json',
|
||||
)
|
||||
assert response.status_code == 204
|
||||
course_entitlement.refresh_from_db()
|
||||
assert course_entitlement.expired_at is not None
|
||||
|
||||
def test_revoke_unenroll_entitlement(self):
|
||||
course_entitlement = CourseEntitlementFactory()
|
||||
url = reverse(self.ENTITLEMENTS_DETAILS_PATH, args=[str(course_entitlement.uuid)])
|
||||
|
||||
enrollment = CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
|
||||
|
||||
course_entitlement.refresh_from_db()
|
||||
course_entitlement.enrollment_course_run = enrollment
|
||||
course_entitlement.save()
|
||||
|
||||
assert course_entitlement.enrollment_course_run is not None
|
||||
|
||||
response = self.client.delete(
|
||||
url,
|
||||
content_type='application/json',
|
||||
)
|
||||
assert response.status_code == 204
|
||||
|
||||
course_entitlement.refresh_from_db()
|
||||
assert course_entitlement.expired_at is not None
|
||||
assert course_entitlement.enrollment_course_run is None
|
||||
11
common/djangoapps/entitlements/api/v1/urls.py
Normal file
11
common/djangoapps/entitlements/api/v1/urls.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.conf.urls import url, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from .views import EntitlementViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'entitlements', EntitlementViewSet, base_name='entitlements')
|
||||
|
||||
urlpatterns = [
|
||||
url(r'', include(router.urls)),
|
||||
]
|
||||
53
common/djangoapps/entitlements/api/v1/views.py
Normal file
53
common/djangoapps/entitlements/api/v1/views.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import logging
|
||||
|
||||
from django.utils import timezone
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from edx_rest_framework_extensions.authentication import JwtAuthentication
|
||||
from rest_framework import permissions, viewsets
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
|
||||
from entitlements.api.v1.filters import CourseEntitlementFilter
|
||||
from entitlements.models import CourseEntitlement
|
||||
from entitlements.api.v1.serializers import CourseEntitlementSerializer
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EntitlementViewSet(viewsets.ModelViewSet):
|
||||
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
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filter_class = CourseEntitlementFilter
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
"""
|
||||
This method is an override and is called by the DELETE method
|
||||
"""
|
||||
save_model = False
|
||||
if instance.expired_at is None:
|
||||
instance.expired_at = timezone.now()
|
||||
log.info('Set expired_at to [%s] for course entitlement [%s]', instance.expired_at, instance.uuid)
|
||||
save_model = True
|
||||
|
||||
if instance.enrollment_course_run is not None:
|
||||
CourseEnrollment.unenroll(
|
||||
user=instance.user,
|
||||
course_id=instance.enrollment_course_run.course_id,
|
||||
skip_refund=True
|
||||
)
|
||||
enrollment = instance.enrollment_course_run
|
||||
instance.enrollment_course_run = None
|
||||
save_model = True
|
||||
log.info(
|
||||
'Unenrolled user [%s] from course run [%s] as part of revocation of course entitlement [%s]',
|
||||
instance.user.username,
|
||||
enrollment.course_id,
|
||||
instance.uuid
|
||||
)
|
||||
if save_model:
|
||||
instance.save()
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""
|
||||
Migration to remove default Mode and to move comments to Help Text
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
('entitlements', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='courseentitlement',
|
||||
name='course_uuid',
|
||||
field=models.UUIDField(help_text=b'UUID for the Course, not the Course Run'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='courseentitlement',
|
||||
name='enrollment_course_run',
|
||||
field=models.ForeignKey(to='student.CourseEnrollment', help_text=b'The current Course enrollment for this entitlement. If NULL the Learner has not enrolled.', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='courseentitlement',
|
||||
name='expired_at',
|
||||
field=models.DateTimeField(help_text=b'The date that an entitlement expired, if NULL the entitlement has not expired.', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='courseentitlement',
|
||||
name='mode',
|
||||
field=models.CharField(help_text=b'The mode of the Course that will be applied on enroll.', max_length=100),
|
||||
),
|
||||
]
|
||||
@@ -1,9 +1,8 @@
|
||||
import uuid as uuid_tools
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from model_utils.models import TimeStampedModel
|
||||
from django.contrib.auth.models import User
|
||||
from course_modes.models import CourseMode
|
||||
|
||||
|
||||
class CourseEntitlement(TimeStampedModel):
|
||||
@@ -11,87 +10,17 @@ class CourseEntitlement(TimeStampedModel):
|
||||
Represents a Student's Entitlement to a Course Run for a given Course.
|
||||
"""
|
||||
|
||||
user = models.ForeignKey(User)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL)
|
||||
uuid = models.UUIDField(default=uuid_tools.uuid4, editable=False)
|
||||
course_uuid = models.UUIDField()
|
||||
|
||||
# The date that an the entitlement expired
|
||||
# if NULL the entitlement has not expired
|
||||
expired_at = models.DateTimeField(null=True)
|
||||
|
||||
# The mode of the Course that will be applied
|
||||
mode = models.CharField(default=CourseMode.DEFAULT_MODE_SLUG, max_length=100)
|
||||
|
||||
# The ID of the course enrollment for this Entitlement
|
||||
# if NULL the entitlement is not in use
|
||||
enrollment_course_run = models.ForeignKey('student.CourseEnrollment', null=True)
|
||||
course_uuid = models.UUIDField(help_text='UUID for the Course, not the Course Run')
|
||||
expired_at = models.DateTimeField(
|
||||
null=True,
|
||||
help_text='The date that an entitlement expired, if NULL the entitlement has not expired.'
|
||||
)
|
||||
mode = models.CharField(max_length=100, help_text='The mode of the Course that will be applied on enroll.')
|
||||
enrollment_course_run = models.ForeignKey(
|
||||
'student.CourseEnrollment',
|
||||
null=True,
|
||||
help_text='The current Course enrollment for this entitlement. If NULL the Learner has not enrolled.'
|
||||
)
|
||||
order_number = models.CharField(max_length=128, null=True)
|
||||
|
||||
@classmethod
|
||||
def entitlements_for_user(cls, user):
|
||||
"""
|
||||
Retrieve all the Entitlements for a User
|
||||
|
||||
Arguments:
|
||||
user: A Django User object identifying the current user
|
||||
|
||||
Returns:
|
||||
All of the Entitlements for the User
|
||||
"""
|
||||
return cls.objects.filter(user=user)
|
||||
|
||||
@classmethod
|
||||
def get_user_course_entitlement(cls, user, course_uuid):
|
||||
"""
|
||||
Retrieve The entitlement for the given parent course id if it exists for the User
|
||||
|
||||
Arguments:
|
||||
user: A Django User object identifying the current user
|
||||
course_uuid(string): The parent course uuid
|
||||
|
||||
Returns:
|
||||
The single entitlement for the requested parent course id
|
||||
"""
|
||||
return cls.objects.filter(user=user, course_uuid=course_uuid).first()
|
||||
|
||||
@classmethod
|
||||
def update_or_create_new_entitlement(cls, user, course_uuid, entitlement_data):
|
||||
"""
|
||||
Updates or creates a new Course Entitlement
|
||||
|
||||
Arguments:
|
||||
user: A Django User object identifying the current user
|
||||
course_uuid(string): The parent course uuid
|
||||
entitlement_data(dict): The dictionary containing all the data for the entitlement
|
||||
e.g. entitlement_data = {
|
||||
'user': user,
|
||||
'course_uuid': course_uuid
|
||||
'enroll_end_date': '2017-09-14 11:47:58.000000',
|
||||
'mode': 'verified',
|
||||
}
|
||||
|
||||
Returns:
|
||||
stored_entitlement: The new or updated CourseEntitlement object
|
||||
is_created (bool): Boolean representing whether or not the Entitlement was created or updated
|
||||
"""
|
||||
stored_entitlement, is_created = cls.objects.update_or_create(
|
||||
user=user,
|
||||
course_uuid=course_uuid,
|
||||
defaults=entitlement_data
|
||||
)
|
||||
return stored_entitlement, is_created
|
||||
|
||||
@classmethod
|
||||
def update_entitlement_enrollment(cls, user, course_uuid, course_run_enrollment):
|
||||
"""
|
||||
Sets the enrollment course for a given entitlement
|
||||
|
||||
Arguments:
|
||||
user: A Django User object identifying the current user
|
||||
course_uuid(string): The parent course uuid
|
||||
course_run_enrollment (CourseEnrollment): The CourseEnrollment object to store, None to clear the Enrollment
|
||||
"""
|
||||
return cls.objects.filter(
|
||||
user=user,
|
||||
course_uuid=course_uuid
|
||||
).update(enrollment_course_run_id=course_run_enrollment)
|
||||
|
||||
0
common/djangoapps/entitlements/tests/__init__.py
Normal file
0
common/djangoapps/entitlements/tests/__init__.py
Normal file
18
common/djangoapps/entitlements/tests/factories.py
Normal file
18
common/djangoapps/entitlements/tests/factories.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import string
|
||||
import uuid
|
||||
|
||||
import factory
|
||||
from factory.fuzzy import FuzzyChoice, FuzzyText
|
||||
|
||||
from entitlements.models import CourseEntitlement
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
|
||||
class CourseEntitlementFactory(factory.django.DjangoModelFactory):
|
||||
class Meta(object):
|
||||
model = CourseEntitlement
|
||||
|
||||
course_uuid = uuid.uuid4()
|
||||
mode = FuzzyChoice(['verified', 'profesional'])
|
||||
user = factory.SubFactory(UserFactory)
|
||||
order_number = FuzzyText(prefix='TEXTX', chars=string.digits)
|
||||
@@ -1,107 +0,0 @@
|
||||
"""
|
||||
Test the Data Aggregation Layer for Course Entitlements.
|
||||
"""
|
||||
import unittest
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
from django.conf import settings
|
||||
|
||||
from entitlements.models import CourseEntitlement
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from student.tests.factories import CourseEnrollmentFactory
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
class EntitlementDataTest(ModuleStoreTestCase):
|
||||
"""
|
||||
Test course entitlement data aggregation.
|
||||
"""
|
||||
USERNAME = "Bob"
|
||||
EMAIL = "bob@example.com"
|
||||
PASSWORD = "edx"
|
||||
|
||||
def setUp(self):
|
||||
"""Create a course and user, then log in. """
|
||||
super(EntitlementDataTest, self).setUp()
|
||||
self.course = CourseFactory.create()
|
||||
self.course_uuid = uuid.uuid4()
|
||||
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
|
||||
self.client.login(username=self.USERNAME, password=self.PASSWORD)
|
||||
|
||||
def _add_entitlement_for_user(self, course, user, parent_uuid):
|
||||
entitlement_data = {
|
||||
'user': user,
|
||||
'course_uuid': parent_uuid,
|
||||
'mode': 'verified',
|
||||
}
|
||||
stored_entitlement, is_created = CourseEntitlement.update_or_create_new_entitlement(
|
||||
user,
|
||||
parent_uuid,
|
||||
entitlement_data
|
||||
)
|
||||
return stored_entitlement, is_created
|
||||
|
||||
def test_get_entitlement_info(self):
|
||||
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
|
||||
self.assertTrue(is_created)
|
||||
|
||||
# Get the Entitlement and verify the data
|
||||
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
|
||||
self.assertEqual(entitlement.course_uuid, self.course_uuid)
|
||||
self.assertEqual(entitlement.mode, 'verified')
|
||||
self.assertIsNone(entitlement.enrollment_course_run)
|
||||
|
||||
def test_get_course_entitlements(self):
|
||||
course2 = CourseFactory.create()
|
||||
|
||||
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
|
||||
self.assertTrue(is_created)
|
||||
|
||||
course2_uuid = uuid.uuid4()
|
||||
stored_entitlement2, is_created2 = self._add_entitlement_for_user(course2, self.user, course2_uuid)
|
||||
self.assertTrue(is_created2)
|
||||
|
||||
# Get the Entitlement and verify the data
|
||||
entitlement_list = CourseEntitlement.entitlements_for_user(self.user)
|
||||
|
||||
self.assertEqual(2, len(entitlement_list))
|
||||
self.assertEqual(self.course_uuid, entitlement_list[0].course_uuid)
|
||||
self.assertEqual(course2_uuid, entitlement_list[1].course_uuid)
|
||||
|
||||
def test_set_enrollment(self):
|
||||
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
|
||||
self.assertTrue(is_created)
|
||||
|
||||
# Entitlement set not enroll the user in the Course run
|
||||
enrollment = CourseEnrollmentFactory(
|
||||
user=self.user,
|
||||
course_id=self.course.id,
|
||||
mode="verified",
|
||||
)
|
||||
CourseEntitlement.update_entitlement_enrollment(self.user, self.course_uuid, enrollment)
|
||||
|
||||
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
|
||||
self.assertIsNotNone(entitlement.enrollment_course_run)
|
||||
|
||||
def test_remove_enrollment(self):
|
||||
stored_entitlement, is_created = self._add_entitlement_for_user(self.course, self.user, self.course_uuid)
|
||||
self.assertTrue(is_created)
|
||||
|
||||
# Entitlement set not enroll the user in the Course run
|
||||
enrollment = CourseEnrollmentFactory(
|
||||
user=self.user,
|
||||
course_id=self.course.id,
|
||||
mode="verified",
|
||||
)
|
||||
CourseEntitlement.update_entitlement_enrollment(self.user, self.course_uuid, enrollment)
|
||||
|
||||
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
|
||||
self.assertIsNotNone(entitlement.enrollment_course_run)
|
||||
|
||||
CourseEntitlement.update_entitlement_enrollment(self.user, self.course_uuid, None)
|
||||
entitlement = CourseEntitlement.get_user_course_entitlement(self.user, self.course_uuid)
|
||||
self.assertIsNone(entitlement.enrollment_course_run)
|
||||
@@ -88,6 +88,9 @@ urlpatterns = [
|
||||
# Enrollment API RESTful endpoints
|
||||
url(r'^api/enrollment/v1/', include('enrollment.urls')),
|
||||
|
||||
# Entitlement API RESTful endpoints
|
||||
url(r'^api/entitlements/', include('entitlements.api.urls', namespace='entitlements_api')),
|
||||
|
||||
# Courseware search endpoints
|
||||
url(r'^search/', include('search.urls')),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user