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
0434c493
Commit
0434c493
authored
Nov 16, 2017
by
Albert St. Aubin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Entitlement enroll and unenroll logic to the Enrollment API
parent
96f35451
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
132 additions
and
61 deletions
+132
-61
common/djangoapps/enrollment/views.py
+109
-61
common/djangoapps/entitlements/models.py
+23
-0
No files found.
common/djangoapps/enrollment/views.py
View file @
0434c493
...
@@ -18,6 +18,7 @@ from rest_framework.views import APIView
...
@@ -18,6 +18,7 @@ from rest_framework.views import APIView
from
course_modes.models
import
CourseMode
from
course_modes.models
import
CourseMode
from
enrollment
import
api
from
enrollment
import
api
from
enrollment.errors
import
CourseEnrollmentError
,
CourseEnrollmentExistsError
,
CourseModeNotFoundError
from
enrollment.errors
import
CourseEnrollmentError
,
CourseEnrollmentExistsError
,
CourseModeNotFoundError
from
entitlements.models
import
CourseEntitlement
from
openedx.core.djangoapps.cors_csrf.authentication
import
SessionAuthenticationCrossDomainCsrf
from
openedx.core.djangoapps.cors_csrf.authentication
import
SessionAuthenticationCrossDomainCsrf
from
openedx.core.djangoapps.cors_csrf.decorators
import
ensure_csrf_cookie_cross_domain
from
openedx.core.djangoapps.cors_csrf.decorators
import
ensure_csrf_cookie_cross_domain
from
openedx.core.djangoapps.embargo
import
api
as
embargo_api
from
openedx.core.djangoapps.embargo
import
api
as
embargo_api
...
@@ -36,6 +37,7 @@ from openedx.features.enterprise_support.api import (
...
@@ -36,6 +37,7 @@ from openedx.features.enterprise_support.api import (
enterprise_enabled
enterprise_enabled
)
)
from
student.auth
import
user_has_role
from
student.auth
import
user_has_role
from
student.models
import
CourseEnrollment
from
student.models
import
User
from
student.models
import
User
from
student.roles
import
CourseStaffRole
,
GlobalStaff
from
student.roles
import
CourseStaffRole
,
GlobalStaff
from
util.disable_rate_limit
import
can_disable_rate_limit
from
util.disable_rate_limit
import
can_disable_rate_limit
...
@@ -528,25 +530,11 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
...
@@ -528,25 +530,11 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
# Get the User, Course ID, and Mode from the request.
# Get the User, Course ID, and Mode from the request.
username
=
request
.
data
.
get
(
'user'
,
request
.
user
.
username
)
username
=
request
.
data
.
get
(
'user'
,
request
.
user
.
username
)
# Note that course_id is actually the Course Run Key
course_id
=
request
.
data
.
get
(
'course_details'
,
{})
.
get
(
'course_id'
)
course_id
=
request
.
data
.
get
(
'course_details'
,
{})
.
get
(
'course_id'
)
course_uuid
=
request
.
data
.
get
(
'course_details'
,
{})
.
get
(
'course_uuid'
)
if
not
course_id
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
u"Course ID must be specified to create a new enrollment."
}
)
try
:
course_id
=
CourseKey
.
from_string
(
course_id
)
except
InvalidKeyError
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
u"No course '{course_id}' found for enrollment"
.
format
(
course_id
=
course_id
)
}
)
mode
=
request
.
data
.
get
(
'mode'
)
mode
=
request
.
data
.
get
(
'mode'
)
is_active
=
request
.
data
.
get
(
'is_active'
)
has_api_key_permissions
=
self
.
has_api_key_permissions
(
request
)
has_api_key_permissions
=
self
.
has_api_key_permissions
(
request
)
...
@@ -579,13 +567,46 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
...
@@ -579,13 +567,46 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
}
}
)
)
course_entitlement
=
None
if
course_uuid
:
course_entitlement
=
CourseEntitlement
.
get_active_user_course_entitlements
(
user
,
course_uuid
)
if
course_entitlement
and
course_entitlement
.
enrollment_course_run
is
not
None
and
is_active
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
u"Entitlement for {course_uuid} already has an enrollment applied"
.
format
(
course_uuid
=
course_uuid
)
}
)
if
not
course_id
:
if
course_entitlement
and
course_entitlement
.
enrollment_course_run
is
not
None
:
course_id
=
course_entitlement
.
enrollment_course_run
.
course_id
else
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
u"Course ID must be specified to create a new enrollment."
}
)
else
:
try
:
course_id
=
CourseKey
.
from_string
(
course_id
)
except
InvalidKeyError
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
u"No course '{course_id}' found for enrollment"
.
format
(
course_id
=
course_id
)
}
)
embargo_response
=
embargo_api
.
get_embargo_response
(
request
,
course_id
,
user
)
embargo_response
=
embargo_api
.
get_embargo_response
(
request
,
course_id
,
user
)
if
embargo_response
:
if
embargo_response
:
return
embargo_response
return
embargo_response
try
:
try
:
is_active
=
request
.
data
.
get
(
'is_active'
)
# Check if the requested activation status is None or a Boolean
# Check if the requested activation status is None or a Boolean
if
is_active
is
not
None
and
not
isinstance
(
is_active
,
bool
):
if
is_active
is
not
None
and
not
isinstance
(
is_active
,
bool
):
return
Response
(
return
Response
(
...
@@ -612,60 +633,87 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
...
@@ -612,60 +633,87 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
}
}
consent_client
.
provide_consent
(
**
kwargs
)
consent_client
.
provide_consent
(
**
kwargs
)
enrollment_attributes
=
request
.
data
.
get
(
'enrollment_attributes'
)
# Add Enrollment for the Entitlement user with the correct Mode
enrollment
=
api
.
get_enrollment
(
username
,
unicode
(
course_id
))
# This should only occur if the User has a Course Entitlement in place.
mode_changed
=
enrollment
and
mode
is
not
None
and
enrollment
[
'mode'
]
!=
mode
# As a reault the api_key_permissions do not apply the User may enroll themselves based on the entitlement.
active_changed
=
enrollment
and
is_active
is
not
None
and
enrollment
[
'is_active'
]
!=
is_active
if
course_entitlement
and
is_active
:
missing_attrs
=
[]
mode
=
course_entitlement
.
mode
if
enrollment_attributes
:
response
=
api
.
add_enrollment
(
actual_attrs
=
[
u"{namespace}:{name}"
.
format
(
**
attr
)
for
attr
in
enrollment_attributes
]
missing_attrs
=
set
(
REQUIRED_ATTRIBUTES
.
get
(
mode
,
[]))
-
set
(
actual_attrs
)
if
has_api_key_permissions
and
(
mode_changed
or
active_changed
):
if
mode_changed
and
active_changed
and
not
is_active
:
# if the requester wanted to deactivate but specified the wrong mode, fail
# the request (on the assumption that the requester had outdated information
# about the currently active enrollment).
msg
=
u"Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate."
.
format
(
enrollment
[
"mode"
],
mode
)
log
.
warning
(
msg
)
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
msg
})
if
len
(
missing_attrs
)
>
0
:
msg
=
u"Missing enrollment attributes: requested mode={} required attributes={}"
.
format
(
mode
,
REQUIRED_ATTRIBUTES
.
get
(
mode
)
)
log
.
warning
(
msg
)
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
msg
})
response
=
api
.
update_enrollment
(
username
,
username
,
unicode
(
course_id
),
unicode
(
course_id
),
mode
=
mode
,
mode
=
mode
,
is_active
=
is_active
,
is_active
=
True
,
enrollment_attributes
=
enrollment_attributes
,
# If we are updating enrollment by authorized api caller, we should allow expired modes
include_expired
=
has_api_key_permissions
)
)
else
:
CourseEntitlement
.
set_enrollment
(
# Will reactivate inactive enrollments.
entitlement
=
course_entitlement
,
response
=
api
.
add_enrollment
(
enrollment
=
CourseEnrollment
.
get_enrollment
(
user
,
course_id
)
)
log
.
info
(
'Enrolling [
%
s] entitlement for run [
%
s] of Course [
%
s].'
,
username
,
course_id
,
course_uuid
)
elif
course_entitlement
and
not
is_active
:
# Unenroll the course as part of the entitlement
response
=
api
.
update_enrollment
(
username
,
username
,
unicode
(
course_id
),
unicode
(
course_id
),
mode
=
mode
,
mode
=
mode
,
is_active
=
is_active
,
is_active
=
is_active
,
enrollment_attributes
=
enrollment_attributes
)
)
CourseEntitlement
.
set_enrollment
(
course_entitlement
,
None
)
log
.
info
(
'Unenrolling [
%
s] entitlement for run [
%
s] of Course [
%
s].'
,
username
,
course_id
,
course_uuid
)
else
:
enrollment_attributes
=
request
.
data
.
get
(
'enrollment_attributes'
)
enrollment
=
api
.
get_enrollment
(
username
,
unicode
(
course_id
))
mode_changed
=
enrollment
and
mode
is
not
None
and
enrollment
[
'mode'
]
!=
mode
active_changed
=
enrollment
and
is_active
is
not
None
and
enrollment
[
'is_active'
]
!=
is_active
missing_attrs
=
[]
if
enrollment_attributes
:
actual_attrs
=
[
u"{namespace}:{name}"
.
format
(
**
attr
)
for
attr
in
enrollment_attributes
]
missing_attrs
=
set
(
REQUIRED_ATTRIBUTES
.
get
(
mode
,
[]))
-
set
(
actual_attrs
)
if
has_api_key_permissions
and
(
mode_changed
or
active_changed
):
if
mode_changed
and
active_changed
and
not
is_active
:
# if the requester wanted to deactivate but specified the wrong mode, fail
# the request (on the assumption that the requester had outdated information
# about the currently active enrollment).
msg
=
u"Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate."
.
format
(
enrollment
[
"mode"
],
mode
)
log
.
warning
(
msg
)
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
msg
})
if
len
(
missing_attrs
)
>
0
:
msg
=
u"Missing enrollment attributes: requested mode={} required attributes={}"
.
format
(
mode
,
REQUIRED_ATTRIBUTES
.
get
(
mode
)
)
log
.
warning
(
msg
)
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
{
"message"
:
msg
})
response
=
api
.
update_enrollment
(
username
,
unicode
(
course_id
),
mode
=
mode
,
is_active
=
is_active
,
enrollment_attributes
=
enrollment_attributes
,
# If we are updating enrollment by authorized api caller, we should allow expired modes
include_expired
=
has_api_key_permissions
)
else
:
# Will reactivate inactive enrollments.
response
=
api
.
add_enrollment
(
username
,
unicode
(
course_id
),
mode
=
mode
,
is_active
=
is_active
,
enrollment_attributes
=
enrollment_attributes
)
email_opt_in
=
request
.
data
.
get
(
'email_opt_in'
,
None
)
email_opt_in
=
request
.
data
.
get
(
'email_opt_in'
,
None
)
if
email_opt_in
is
not
None
:
if
email_opt_in
is
not
None
:
org
=
course_id
.
org
org
=
course_id
.
org
update_email_opt_in
(
request
.
user
,
org
,
email_opt_in
)
update_email_opt_in
(
request
.
user
,
org
,
email_opt_in
)
log
.
info
(
'The user [
%
s] has already been enrolled in course run [
%
s].'
,
username
,
course_id
)
log
.
info
(
'The user [
%
s] has already been enrolled in course run [
%
s].'
,
username
,
course_id
)
return
Response
(
response
)
return
Response
(
response
)
except
CourseModeNotFoundError
as
error
:
except
CourseModeNotFoundError
as
error
:
return
Response
(
return
Response
(
...
...
common/djangoapps/entitlements/models.py
View file @
0434c493
...
@@ -24,3 +24,26 @@ class CourseEntitlement(TimeStampedModel):
...
@@ -24,3 +24,26 @@ class CourseEntitlement(TimeStampedModel):
help_text
=
'The current Course enrollment for this entitlement. If NULL the Learner has not enrolled.'
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
)
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
,
expired_at
=
None
,
)
return
entitlement
except
cls
.
DoesNotExist
:
return
None
@classmethod
def
set_enrollment
(
cls
,
entitlement
,
enrollment
):
"""
Fulfills an entitlement by specifying a session.
"""
cls
.
objects
.
filter
(
id
=
entitlement
.
id
)
.
update
(
enrollment_course_run
=
enrollment
)
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