Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
eb5fc311
Commit
eb5fc311
authored
Nov 22, 2017
by
Albert St. Aubin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored the API to be part of the Entitlement API, removed it from
the Enrollment API
parent
b0a19e94
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
143 additions
and
98 deletions
+143
-98
common/djangoapps/enrollment/tests/test_views.py
+1
-95
common/djangoapps/enrollment/views.py
+0
-0
common/djangoapps/entitlements/api/v1/urls.py
+12
-1
common/djangoapps/entitlements/api/v1/views.py
+109
-1
common/djangoapps/entitlements/migrations/0003_auto_20171120_1432.py
+20
-0
common/djangoapps/entitlements/models.py
+1
-1
No files found.
common/djangoapps/enrollment/tests/test_views.py
View file @
eb5fc311
...
...
@@ -5,7 +5,6 @@ import datetime
import
itertools
import
json
import
unittest
import
uuid
import
ddt
import
httpretty
...
...
@@ -25,11 +24,9 @@ from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls
from
course_modes.models
import
CourseMode
from
course_modes.tests.factories
import
CourseModeFactory
from
entitlements.tests.factories
import
CourseEntitlementFactory
from
enrollment
import
api
from
enrollment.errors
import
CourseEnrollmentError
from
enrollment.views
import
EnrollmentUserThrottle
from
entitlements.models
import
CourseEntitlement
from
openedx.core.djangoapps.content.course_overviews.models
import
CourseOverview
from
openedx.core.djangoapps.embargo.models
import
Country
,
CountryAccessRule
,
RestrictedCourse
from
openedx.core.djangoapps.embargo.test_utils
import
restrict_course
...
...
@@ -38,7 +35,7 @@ from openedx.core.lib.django_test_client_utils import get_absolute_url
from
openedx.features.enterprise_support.tests.mixins.enterprise
import
EnterpriseServiceMockMixin
from
student.models
import
CourseEnrollment
from
student.roles
import
CourseStaffRole
from
student.tests.factories
import
AdminFactory
,
UserFactory
,
TEST_PASSWORD
from
student.tests.factories
import
AdminFactory
,
UserFactory
from
util.models
import
RateLimitConfiguration
from
util.testing
import
UrlResetMixin
...
...
@@ -50,7 +47,6 @@ class EnrollmentTestMixin(object):
def
assert_enrollment_status
(
self
,
course_id
=
None
,
course_uuid
=
None
,
username
=
None
,
expected_status
=
status
.
HTTP_200_OK
,
email_opt_in
=
None
,
...
...
@@ -81,9 +77,6 @@ class EnrollmentTestMixin(object):
'enrollment_attributes'
:
enrollment_attributes
}
if
course_uuid
:
data
[
'course_details'
][
'course_uuid'
]
=
course_uuid
if
is_active
is
not
None
:
data
[
'is_active'
]
=
is_active
...
...
@@ -140,93 +133,6 @@ class EnrollmentTestMixin(object):
self
.
assertEqual
(
actual_mode
,
expected_mode
)
# @override_settings(EDX_API_KEY="i am a key")
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
EntitlementEnrollmentTest
(
EnrollmentTestMixin
,
ModuleStoreTestCase
,
APITestCase
):
def
setUp
(
self
):
super
(
EntitlementEnrollmentTest
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
()
self
.
user
=
UserFactory
()
CourseModeFactory
.
create
(
course_id
=
self
.
course
.
id
,
mode_slug
=
CourseMode
.
VERIFIED
,
mode_display_name
=
CourseMode
.
VERIFIED
,
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
TEST_PASSWORD
)
def
test_enroll_entitlement
(
self
):
entitlement
=
CourseEntitlementFactory
.
create
(
user
=
self
.
user
,
mode
=
'verified'
)
resp
=
self
.
assert_enrollment_status
(
course_id
=
unicode
(
self
.
course
.
id
),
course_uuid
=
str
(
entitlement
.
course_uuid
),
is_active
=
True
,
mode
=
None
,
max_mongo_calls
=
4
)
data
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
self
.
course
.
display_name_with_default
,
data
[
'course_details'
][
'course_name'
])
# Verify that the enrollment was created correctly
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course
.
id
))
course_mode
,
is_active
=
CourseEnrollment
.
enrollment_mode_for_user
(
self
.
user
,
self
.
course
.
id
)
self
.
assertTrue
(
is_active
)
self
.
assertEqual
(
course_mode
,
entitlement
.
mode
)
entitlement
.
refresh_from_db
()
# Verify the Entitlement settings are correct
self
.
assertIsNotNone
(
entitlement
.
enrollment_course_run
)
self
.
assertEqual
(
entitlement
.
enrollment_course_run
.
course_id
,
self
.
course
.
id
)
def
test_unenroll_entitlement
(
self
):
entitlement
=
CourseEntitlementFactory
.
create
(
user
=
self
.
user
,
mode
=
'verified'
)
# Enroll user
self
.
assert_enrollment_status
(
course_id
=
unicode
(
self
.
course
.
id
),
course_uuid
=
str
(
entitlement
.
course_uuid
),
is_active
=
True
,
mode
=
None
,
max_mongo_calls
=
4
)
# Unenroll the user
resp
=
self
.
assert_enrollment_status
(
course_id
=
unicode
(
self
.
course
.
id
),
course_uuid
=
str
(
entitlement
.
course_uuid
),
is_active
=
False
,
mode
=
None
,
max_mongo_calls
=
4
)
data
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
self
.
course
.
display_name_with_default
,
data
[
'course_details'
][
'course_name'
])
# Verify that the enrollment was created correctly
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course
.
id
))
course_mode
,
is_active
=
CourseEnrollment
.
enrollment_mode_for_user
(
self
.
user
,
self
.
course
.
id
)
self
.
assertFalse
(
is_active
)
self
.
assertEqual
(
course_mode
,
entitlement
.
mode
)
entitlement
.
refresh_from_db
()
self
.
assertIsNone
(
entitlement
.
enrollment_course_run
)
def
test_enroll_no_entitlement
(
self
):
resp
=
self
.
assert_enrollment_status
(
course_id
=
unicode
(
self
.
course
.
id
),
course_uuid
=
str
(
uuid
.
uuid4
()),
is_active
=
True
,
mode
=
None
,
max_mongo_calls
=
4
,
expected_status
=
status
.
HTTP_400_BAD_REQUEST
)
data
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
self
.
course
.
display_name_with_default
,
data
[
'course_details'
][
'course_name'
])
# Verify that the enrollment was created correctly
self
.
assertFalse
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course
.
id
))
@attr
(
shard
=
3
)
@override_settings
(
EDX_API_KEY
=
"i am a key"
)
@ddt.ddt
...
...
common/djangoapps/enrollment/views.py
View file @
eb5fc311
This diff is collapsed.
Click to expand it.
common/djangoapps/entitlements/api/v1/urls.py
View file @
eb5fc311
from
django.conf.urls
import
url
,
include
from
rest_framework.routers
import
DefaultRouter
from
.views
import
EntitlementViewSet
from
.views
import
EntitlementViewSet
,
EntitlementEnrollmentViewSet
router
=
DefaultRouter
()
router
.
register
(
r'entitlements'
,
EntitlementViewSet
,
base_name
=
'entitlements'
)
enrollments_view
=
EntitlementEnrollmentViewSet
.
as_view
({
'post'
:
'create'
,
'delete'
:
'destroy'
,
})
urlpatterns
=
[
url
(
r''
,
include
(
router
.
urls
)),
url
(
r'entitlements/(?P<uuid>[0-9a-f-]+)/enrollments/$'
,
enrollments_view
,
name
=
'enrollments'
)
]
common/djangoapps/entitlements/api/v1/views.py
View file @
eb5fc311
...
...
@@ -3,13 +3,19 @@ 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
import
permissions
,
viewsets
,
status
from
rest_framework.response
import
Response
from
rest_framework.authentication
import
SessionAuthentication
from
openedx.core.djangoapps.catalog.utils
import
get_course_runs_for_course
from
entitlements.api.v1.filters
import
CourseEntitlementFilter
from
entitlements.api.v1.permissions
import
IsAdminOrAuthenticatedReadOnly
from
entitlements.models
import
CourseEntitlement
from
entitlements.api.v1.serializers
import
CourseEntitlementSerializer
from
entitlements.models
import
CourseEntitlement
from
openedx.core.djangoapps.cors_csrf.authentication
import
SessionAuthenticationCrossDomainCsrf
from
opaque_keys.edx.keys
import
CourseKey
from
student.models
import
CourseEnrollment
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -57,3 +63,105 @@ class EntitlementViewSet(viewsets.ModelViewSet):
)
if
save_model
:
instance
.
save
()
class
EntitlementEnrollmentViewSet
(
viewsets
.
GenericViewSet
):
authentication_classes
=
(
JwtAuthentication
,
SessionAuthentication
,)
permission_classes
=
(
permissions
.
IsAuthenticated
,)
queryset
=
CourseEntitlement
.
objects
.
all
()
serializer_class
=
CourseEntitlementSerializer
def
_enroll_entitlement
(
self
,
entitlement
,
course_session_key
,
user
):
enrollment
=
CourseEnrollment
.
enroll
(
user
=
user
,
course_key
=
course_session_key
,
mode
=
entitlement
.
mode
,
)
CourseEntitlement
.
set_enrollment
(
entitlement
,
enrollment
)
def
_unenroll_entitlement
(
self
,
entitlement
,
course_session_key
,
user
):
CourseEnrollment
.
unenroll
(
user
,
course_session_key
,
skip_refund
=
True
)
CourseEntitlement
.
set_enrollment
(
entitlement
,
None
)
def
create
(
self
,
request
,
uuid
):
course_session_id
=
request
.
data
.
get
(
'course_session_id'
,
None
)
if
not
course_session_id
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
"The Course Run ID was not provided."
)
# Verify that the user has an Entitlement for the provided Course UUID.
try
:
entitlement
=
CourseEntitlement
.
objects
.
get
(
uuid
=
uuid
,
user
=
request
.
user
,
expired_at
=
None
)
except
CourseEntitlement
.
DoesNotExist
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
"The Entitlement for this UUID does not exist or is Expired."
)
# 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
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."
)
# Determine if this is a Switch session or a simple enroll and handle both.
if
entitlement
.
enrollment_course_run
is
None
:
self
.
_enroll_entitlement
(
entitlement
=
entitlement
,
course_session_key
=
CourseKey
.
from_string
(
course_session_id
),
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
,
data
=
{
'uuid'
:
entitlement
.
uuid
,
'course_run_id'
:
course_session_id
,
'is_active'
:
True
}
)
def
destroy
(
self
,
request
,
uuid
):
"""
On DELETE call to this API we will unenroll the course enrollment for the provided uuid
"""
try
:
entitlement
=
CourseEntitlement
.
objects
.
get
(
uuid
=
uuid
,
user
=
request
.
user
,
expired_at
=
None
)
except
CourseEntitlement
.
DoesNotExist
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
"The Entitlement for this UUID does not exist or is Expired."
)
if
entitlement
.
enrollment_course_run
is
None
:
return
Response
()
self
.
_unenroll_entitlement
(
entitlement
=
entitlement
,
course_session_key
=
entitlement
.
enrollment_course_run
.
course_id
,
user
=
request
.
user
)
return
Response
(
status
=
status
.
HTTP_204_NO_CONTENT
)
common/djangoapps/entitlements/migrations/0003_auto_20171120_1432.py
0 → 100644
View file @
eb5fc311
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
uuid
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'entitlements'
,
'0002_auto_20171102_0719'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'courseentitlement'
,
name
=
'uuid'
,
field
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
unique
=
True
,
editable
=
False
),
),
]
common/djangoapps/entitlements/models.py
View file @
eb5fc311
...
...
@@ -11,7 +11,7 @@ class CourseEntitlement(TimeStampedModel):
"""
user
=
models
.
ForeignKey
(
settings
.
AUTH_USER_MODEL
)
uuid
=
models
.
UUIDField
(
default
=
uuid_tools
.
uuid4
,
editable
=
False
)
uuid
=
models
.
UUIDField
(
default
=
uuid_tools
.
uuid4
,
editable
=
False
,
unique
=
True
)
course_uuid
=
models
.
UUIDField
(
help_text
=
'UUID for the Course, not the Course Run'
)
expired_at
=
models
.
DateTimeField
(
null
=
True
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment