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
70ec4c5f
Commit
70ec4c5f
authored
Feb 11, 2015
by
Will Daly
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6948 from edx/will/country-access-part-2
Finish Country Access (Part 2 of 3)
parents
ea29bb42
e609f982
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
337 additions
and
24 deletions
+337
-24
common/djangoapps/course_modes/tests/test_views.py
+33
-1
common/djangoapps/course_modes/views.py
+15
-0
common/djangoapps/enrollment/tests/test_views.py
+66
-4
common/djangoapps/enrollment/views.py
+35
-9
common/djangoapps/student/tests/test_enrollment.py
+28
-3
common/djangoapps/student/views.py
+14
-0
lms/djangoapps/shoppingcart/tests/test_views.py
+48
-3
lms/djangoapps/shoppingcart/views.py
+22
-0
lms/djangoapps/verify_student/tests/test_views.py
+19
-2
lms/djangoapps/verify_student/views.py
+14
-0
lms/static/js/spec/student_account/enrollment_spec.js
+23
-1
lms/static/js/student_account/enrollment.js
+20
-1
No files found.
common/djangoapps/course_modes/tests/test_views.py
View file @
70ec4c5f
...
...
@@ -11,6 +11,7 @@ from xmodule.modulestore.tests.django_utils import (
)
from
util.testing
import
UrlResetMixin
from
embargo.test_utils
import
restrict_course
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
course_modes.tests.factories
import
CourseModeFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
...
...
@@ -274,7 +275,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
# Create a verified mode
url
=
reverse
(
'create_mode'
,
args
=
[
unicode
(
self
.
course
.
id
)])
response
=
self
.
client
.
get
(
url
,
parameters
)
self
.
client
.
get
(
url
,
parameters
)
honor_mode
=
Mode
(
u'honor'
,
u'Honor Code Certificate'
,
0
,
''
,
'usd'
,
None
,
None
)
verified_mode
=
Mode
(
u'verified'
,
u'Verified Certificate'
,
10
,
'10,20'
,
'usd'
,
None
,
None
)
...
...
@@ -282,3 +283,34 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
course_modes
=
CourseMode
.
modes_for_course
(
self
.
course
.
id
)
self
.
assertEquals
(
course_modes
,
expected_modes
)
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
TrackSelectionEmbargoTest
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""Test embargo restrictions on the track selection page. """
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
setUp
(
self
):
super
(
TrackSelectionEmbargoTest
,
self
)
.
setUp
(
'embargo'
)
# Create a course and course modes
self
.
course
=
CourseFactory
.
create
()
CourseModeFactory
(
mode_slug
=
'honor'
,
course_id
=
self
.
course
.
id
)
CourseModeFactory
(
mode_slug
=
'verified'
,
course_id
=
self
.
course
.
id
,
min_price
=
10
)
# Create a user and log in
self
.
user
=
UserFactory
.
create
(
username
=
"Bob"
,
email
=
"bob@example.com"
,
password
=
"edx"
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
"edx"
)
# Construct the URL for the track selection page
self
.
url
=
reverse
(
'course_modes_choose'
,
args
=
[
unicode
(
self
.
course
.
id
)])
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_restrict
(
self
):
with
restrict_course
(
self
.
course
.
id
)
as
redirect_url
:
response
=
self
.
client
.
get
(
self
.
url
)
self
.
assertRedirects
(
response
,
redirect_url
)
def
test_embargo_allow
(
self
):
response
=
self
.
client
.
get
(
self
.
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
common/djangoapps/course_modes/views.py
View file @
70ec4c5f
...
...
@@ -3,6 +3,8 @@ Views for the course_mode module
"""
import
decimal
from
ipware.ip
import
get_ip
from
django.core.urlresolvers
import
reverse
from
django.conf
import
settings
from
django.http
import
HttpResponse
,
HttpResponseBadRequest
...
...
@@ -22,6 +24,8 @@ from opaque_keys.edx.keys import CourseKey
from
util.db
import
commit_on_success_with_read_committed
from
xmodule.modulestore.django
import
modulestore
from
embargo
import
api
as
embargo_api
class
ChooseModeView
(
View
):
"""View used when the user is asked to pick a mode.
...
...
@@ -52,6 +56,17 @@ class ChooseModeView(View):
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
# Check whether the user has access to this course
# based on country access rules.
embargo_redirect
=
embargo_api
.
redirect_if_blocked
(
course_key
,
user
=
request
.
user
,
ip_address
=
get_ip
(
request
),
url
=
request
.
path
)
if
embargo_redirect
:
return
redirect
(
embargo_redirect
)
enrollment_mode
,
is_active
=
CourseEnrollment
.
enrollment_mode_for_user
(
request
.
user
,
course_key
)
modes
=
CourseMode
.
modes_for_course_dict
(
course_key
)
...
...
common/djangoapps/enrollment/tests/test_views.py
View file @
70ec4c5f
...
...
@@ -6,19 +6,18 @@ import json
import
unittest
from
mock
import
patch
from
django.test.utils
import
override_settings
from
django.core.urlresolvers
import
reverse
from
rest_framework.test
import
APITestCase
from
rest_framework
import
status
from
django.conf
import
settings
from
xmodule.modulestore.tests.django_utils
import
(
ModuleStoreTestCase
,
mixed_store_config
)
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
util.testing
import
UrlResetMixin
from
enrollment
import
api
from
enrollment.errors
import
CourseEnrollmentError
from
student.tests.factories
import
UserFactory
,
CourseModeFactory
from
student.models
import
CourseEnrollment
from
embargo.test_utils
import
restrict_course
@ddt.ddt
...
...
@@ -245,3 +244,66 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
)
self
.
assertEqual
(
resp
.
status_code
,
status
.
HTTP_400_BAD_REQUEST
)
self
.
assertIn
(
"No course "
,
resp
.
content
)
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
EnrollmentEmbargoTest
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""Test that enrollment is blocked from embargoed countries. """
USERNAME
=
"Bob"
EMAIL
=
"bob@example.com"
PASSWORD
=
"edx"
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
setUp
(
self
):
""" Create a course and user, then log in. """
super
(
EnrollmentEmbargoTest
,
self
)
.
setUp
(
'embargo'
)
self
.
course
=
CourseFactory
.
create
()
self
.
user
=
UserFactory
.
create
(
username
=
self
.
USERNAME
,
email
=
self
.
EMAIL
,
password
=
self
.
PASSWORD
)
self
.
client
.
login
(
username
=
self
.
USERNAME
,
password
=
self
.
PASSWORD
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_change_enrollment_restrict
(
self
):
url
=
reverse
(
'courseenrollments'
)
data
=
json
.
dumps
({
'course_details'
:
{
'course_id'
:
unicode
(
self
.
course
.
id
)
},
'user'
:
self
.
user
.
username
})
# Attempt to enroll from a country embargoed for this course
with
restrict_course
(
self
.
course
.
id
)
as
redirect_url
:
response
=
self
.
client
.
post
(
url
,
data
,
content_type
=
'application/json'
)
# Expect an error response
self
.
assertEqual
(
response
.
status_code
,
403
)
# Expect that the redirect URL is included in the response
resp_data
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
resp_data
[
'user_message_url'
],
redirect_url
)
# Verify that we were not enrolled
self
.
assertEqual
(
self
.
_get_enrollments
(),
[])
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_change_enrollment_allow
(
self
):
url
=
reverse
(
'courseenrollments'
)
data
=
json
.
dumps
({
'course_details'
:
{
'course_id'
:
unicode
(
self
.
course
.
id
)
},
'user'
:
self
.
user
.
username
})
response
=
self
.
client
.
post
(
url
,
data
,
content_type
=
'application/json'
)
self
.
assertEqual
(
response
.
status_code
,
200
)
# Verify that we were enrolled
self
.
assertEqual
(
len
(
self
.
_get_enrollments
()),
1
)
def
_get_enrollments
(
self
):
"""Retrieve the enrollment list for the current user. """
url
=
reverse
(
'courseenrollments'
)
resp
=
self
.
client
.
get
(
url
)
return
json
.
loads
(
resp
.
content
)
common/djangoapps/enrollment/views.py
View file @
70ec4c5f
...
...
@@ -3,15 +3,19 @@ The Enrollment API Views should be simple, lean HTTP endpoints for API access. T
consist primarily of authentication, request validation, and serialization.
"""
from
opaque_keys
import
InvalidKeyError
from
ipware.ip
import
get_ip
from
django.conf
import
settings
from
rest_framework
import
status
from
rest_framework.authentication
import
OAuth2Authentication
from
rest_framework
import
permissions
from
rest_framework.response
import
Response
from
rest_framework.throttling
import
UserRateThrottle
from
rest_framework.views
import
APIView
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys
import
InvalidKeyError
from
enrollment
import
api
from
enrollment.errors
import
CourseNotFoundError
,
CourseEnrollmentError
,
CourseModeNotFoundError
from
embargo
import
api
as
embargo_api
from
util.authentication
import
SessionAuthenticationAllowInactiveUser
from
util.disable_rate_limit
import
can_disable_rate_limit
...
...
@@ -278,7 +282,36 @@ class EnrollmentListView(APIView):
course_id
=
request
.
DATA
[
'course_details'
][
'course_id'
]
try
:
return
Response
(
api
.
add_enrollment
(
user
,
course_id
))
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
)
}
)
# Check whether any country access rules block the user from enrollment
# We do this at the view level (rather than the Python API level)
# because this check requires information about the HTTP request.
redirect_url
=
embargo_api
.
redirect_if_blocked
(
course_id
,
user
=
request
.
user
,
ip_address
=
get_ip
(
request
),
url
=
request
.
path
)
if
redirect_url
:
return
Response
(
status
=
status
.
HTTP_403_FORBIDDEN
,
data
=
{
"message"
:
(
u"Users from this location cannot access the course '{course_id}'."
)
.
format
(
course_id
=
course_id
),
"user_message_url"
:
redirect_url
}
)
try
:
return
Response
(
api
.
add_enrollment
(
user
,
unicode
(
course_id
)))
except
CourseModeNotFoundError
as
error
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
...
...
@@ -305,10 +338,3 @@ class EnrollmentListView(APIView):
)
.
format
(
user
=
user
,
course_id
=
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
)
}
)
common/djangoapps/student/tests/test_enrollment.py
View file @
70ec4c5f
...
...
@@ -5,18 +5,19 @@ import ddt
import
unittest
from
mock
import
patch
from
django.test.utils
import
override_settings
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
util.testing
import
UrlResetMixin
from
embargo.test_utils
import
restrict_course
from
student.tests.factories
import
UserFactory
,
CourseModeFactory
from
student.models
import
CourseEnrollment
@ddt.ddt
@unittest.skipUnless
(
settings
.
ROOT_URLCONF
==
'lms.urls'
,
'Test only valid in lms'
)
class
EnrollmentTest
(
ModuleStoreTestCase
):
class
EnrollmentTest
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""
Test student enrollment, especially with different course modes.
"""
...
...
@@ -25,9 +26,10 @@ class EnrollmentTest(ModuleStoreTestCase):
EMAIL
=
"bob@example.com"
PASSWORD
=
"edx"
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
setUp
(
self
):
""" Create a course and user, then log in. """
super
(
EnrollmentTest
,
self
)
.
setUp
()
super
(
EnrollmentTest
,
self
)
.
setUp
(
'embargo'
)
self
.
course
=
CourseFactory
.
create
()
self
.
user
=
UserFactory
.
create
(
username
=
self
.
USERNAME
,
email
=
self
.
EMAIL
,
password
=
self
.
PASSWORD
)
self
.
client
.
login
(
username
=
self
.
USERNAME
,
password
=
self
.
PASSWORD
)
...
...
@@ -132,6 +134,29 @@ class EnrollmentTest(ModuleStoreTestCase):
else
:
self
.
assertFalse
(
mock_update_email_opt_in
.
called
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_restrict
(
self
):
# When accessing the course from an embargoed country,
# we should be blocked.
with
restrict_course
(
self
.
course
.
id
)
as
redirect_url
:
response
=
self
.
_change_enrollment
(
'enroll'
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
content
,
redirect_url
)
# Verify that we weren't enrolled
is_enrolled
=
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course
.
id
)
self
.
assertFalse
(
is_enrolled
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_allow
(
self
):
response
=
self
.
_change_enrollment
(
'enroll'
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
content
,
''
)
# Verify that we were enrolled
is_enrolled
=
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course
.
id
)
self
.
assertTrue
(
is_enrolled
)
def
test_user_not_authenticated
(
self
):
# Log out, so we're no longer authenticated
self
.
client
.
logout
()
...
...
common/djangoapps/student/views.py
View file @
70ec4c5f
...
...
@@ -9,6 +9,7 @@ import time
import
json
from
collections
import
defaultdict
from
pytz
import
UTC
from
ipware.ip
import
get_ip
from
django.conf
import
settings
from
django.contrib.auth
import
logout
,
authenticate
,
login
...
...
@@ -113,6 +114,8 @@ from xmodule.error_module import ErrorDescriptor
from
shoppingcart.models
import
DonationConfiguration
,
CourseRegistrationCode
from
openedx.core.djangoapps.user_api.api
import
profile
as
profile_api
from
embargo
import
api
as
embargo_api
import
analytics
from
eventtracking
import
tracker
...
...
@@ -901,6 +904,17 @@ def change_enrollment(request, check_access=True):
available_modes
=
CourseMode
.
modes_for_course_dict
(
course_id
)
# Check whether the user is blocked from enrolling in this course
# This can occur if the user's IP is on a global blacklist
# or if the user is enrolling in a country in which the course
# is not available.
redirect_url
=
embargo_api
.
redirect_if_blocked
(
course_id
,
user
=
user
,
ip_address
=
get_ip
(
request
),
url
=
request
.
path
)
if
redirect_url
:
return
HttpResponse
(
redirect_url
)
# Check that auto enrollment is allowed for this course
# (= the course is NOT behind a paywall)
if
CourseMode
.
can_auto_enroll
(
course_id
):
...
...
lms/djangoapps/shoppingcart/tests/test_views.py
View file @
70ec4c5f
...
...
@@ -24,12 +24,11 @@ from datetime import datetime, timedelta
from
mock
import
patch
,
Mock
import
ddt
from
xmodule.modulestore.tests.django_utils
import
(
ModuleStoreTestCase
,
mixed_store_config
)
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
student.roles
import
CourseSalesAdminRole
from
util.date_utils
import
get_default_time_display
from
util.testing
import
UrlResetMixin
from
shoppingcart.views
import
_can_download_report
,
_get_date_from_str
from
shoppingcart.models
import
(
...
...
@@ -42,6 +41,7 @@ from courseware.tests.factories import InstructorFactory
from
student.models
import
CourseEnrollment
from
course_modes.models
import
CourseMode
from
edxmako.shortcuts
import
render_to_response
from
embargo.test_utils
import
restrict_course
from
shoppingcart.processors
import
render_purchase_form_html
from
shoppingcart.admin
import
SoftDeleteCouponAdmin
from
shoppingcart.views
import
initialize_report
...
...
@@ -1579,6 +1579,51 @@ class RegistrationCodeRedemptionCourseEnrollment(ModuleStoreTestCase):
@ddt.ddt
class
RedeemCodeEmbargoTests
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""Test blocking redeem code redemption based on country access rules. """
USERNAME
=
'bob'
PASSWORD
=
'test'
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
setUp
(
self
):
super
(
RedeemCodeEmbargoTests
,
self
)
.
setUp
(
'embargo'
)
self
.
course
=
CourseFactory
.
create
()
self
.
user
=
UserFactory
.
create
(
username
=
self
.
USERNAME
,
password
=
self
.
PASSWORD
)
result
=
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
self
.
PASSWORD
)
self
.
assertTrue
(
result
,
msg
=
"Could not log in"
)
@ddt.data
(
'get'
,
'post'
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_registration_code_redemption_embargo
(
self
,
method
):
# Create a valid registration code
reg_code
=
CourseRegistrationCode
.
objects
.
create
(
code
=
"abcd1234"
,
course_id
=
self
.
course
.
id
,
created_by
=
self
.
user
)
# Try to redeem the code from a restricted country
with
restrict_course
(
self
.
course
.
id
)
as
redirect_url
:
url
=
reverse
(
'register_code_redemption'
,
kwargs
=
{
'registration_code'
:
'abcd1234'
}
)
response
=
getattr
(
self
.
client
,
method
)(
url
)
self
.
assertRedirects
(
response
,
redirect_url
)
# The registration code should NOT be redeemed
is_redeemed
=
RegistrationCodeRedemption
.
objects
.
filter
(
registration_code
=
reg_code
)
.
exists
()
self
.
assertFalse
(
is_redeemed
)
# The user should NOT be enrolled
is_enrolled
=
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course
.
id
)
self
.
assertFalse
(
is_enrolled
)
@ddt.ddt
class
DonationViewTest
(
ModuleStoreTestCase
):
"""Tests for making a donation.
...
...
lms/djangoapps/shoppingcart/views.py
View file @
70ec4c5f
...
...
@@ -2,9 +2,11 @@ import logging
import
datetime
import
decimal
import
pytz
from
ipware.ip
import
get_ip
from
django.db.models
import
Q
from
django.conf
import
settings
from
django.contrib.auth.models
import
Group
from
django.shortcuts
import
redirect
from
django.http
import
(
HttpResponse
,
HttpResponseRedirect
,
HttpResponseNotFound
,
HttpResponseBadRequest
,
HttpResponseForbidden
,
Http404
...
...
@@ -28,6 +30,7 @@ from config_models.decorators import require_config
from
shoppingcart.reports
import
RefundReport
,
ItemizedPurchaseReport
,
UniversityRevenueShareReport
,
CertificateStatusReport
from
student.models
import
CourseEnrollment
,
EnrollmentClosedError
,
CourseFullError
,
\
AlreadyEnrolledError
from
embargo
import
api
as
embargo_api
from
.exceptions
import
(
ItemAlreadyInCartException
,
AlreadyEnrolledInCourseException
,
CourseDoesNotExistException
,
ReportTypeDoesNotExistException
,
...
...
@@ -50,6 +53,7 @@ import json
from
xmodule_django.models
import
CourseKeyField
from
.decorators
import
enforce_shopping_cart_enabled
log
=
logging
.
getLogger
(
"shoppingcart"
)
AUDIT_LOG
=
logging
.
getLogger
(
"audit"
)
...
...
@@ -352,6 +356,15 @@ def register_code_redemption(request, registration_code):
reg_code_is_valid
,
reg_code_already_redeemed
,
course_registration
=
get_reg_code_validity
(
registration_code
,
request
,
limiter
)
course
=
get_course_by_id
(
getattr
(
course_registration
,
'course_id'
),
depth
=
0
)
# Restrict the user from enrolling based on country access rules
embargo_redirect
=
embargo_api
.
redirect_if_blocked
(
course
.
id
,
user
=
request
.
user
,
ip_address
=
get_ip
(
request
),
url
=
request
.
path
)
if
embargo_redirect
is
not
None
:
return
redirect
(
embargo_redirect
)
context
=
{
'reg_code_already_redeemed'
:
reg_code_already_redeemed
,
'reg_code_is_valid'
:
reg_code_is_valid
,
...
...
@@ -365,6 +378,15 @@ def register_code_redemption(request, registration_code):
reg_code_is_valid
,
reg_code_already_redeemed
,
course_registration
=
get_reg_code_validity
(
registration_code
,
request
,
limiter
)
course
=
get_course_by_id
(
getattr
(
course_registration
,
'course_id'
),
depth
=
0
)
# Restrict the user from enrolling based on country access rules
embargo_redirect
=
embargo_api
.
redirect_if_blocked
(
course
.
id
,
user
=
request
.
user
,
ip_address
=
get_ip
(
request
),
url
=
request
.
path
)
if
embargo_redirect
is
not
None
:
return
redirect
(
embargo_redirect
)
context
=
{
'reg_code'
:
registration_code
,
'site_name'
:
site_name
,
...
...
lms/djangoapps/verify_student/tests/test_views.py
View file @
70ec4c5f
...
...
@@ -32,6 +32,8 @@ from student.models import CourseEnrollment
from
course_modes.tests.factories
import
CourseModeFactory
from
course_modes.models
import
CourseMode
from
shoppingcart.models
import
Order
,
CertificateItem
from
embargo.test_utils
import
restrict_course
from
util.testing
import
UrlResetMixin
from
verify_student.views
import
render_to_response
,
PayAndVerifyView
from
verify_student.models
import
SoftwareSecurePhotoVerification
from
reverification.tests.factories
import
MidcourseReverificationWindowFactory
...
...
@@ -60,7 +62,7 @@ class StartView(TestCase):
@ddt.ddt
class
TestPayAndVerifyView
(
ModuleStoreTestCase
):
class
TestPayAndVerifyView
(
UrlResetMixin
,
ModuleStoreTestCase
):
"""
Tests for the payment and verification flow views.
"""
...
...
@@ -72,8 +74,9 @@ class TestPayAndVerifyView(ModuleStoreTestCase):
YESTERDAY
=
NOW
-
timedelta
(
days
=
1
)
TOMORROW
=
NOW
+
timedelta
(
days
=
1
)
@mock.patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
setUp
(
self
):
super
(
TestPayAndVerifyView
,
self
)
.
setUp
()
super
(
TestPayAndVerifyView
,
self
)
.
setUp
(
'embargo'
)
self
.
user
=
UserFactory
.
create
(
username
=
self
.
USERNAME
,
password
=
self
.
PASSWORD
)
result
=
self
.
client
.
login
(
username
=
self
.
USERNAME
,
password
=
self
.
PASSWORD
)
self
.
assertTrue
(
result
,
msg
=
"Could not log in"
)
...
...
@@ -622,6 +625,20 @@ class TestPayAndVerifyView(ModuleStoreTestCase):
self
.
assertContains
(
response
,
"verification deadline"
)
self
.
assertContains
(
response
,
"Jan 02, 1999 at 00:00 UTC"
)
@mock.patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_restrict
(
self
):
course
=
self
.
_create_course
(
"verified"
)
with
restrict_course
(
course
.
id
)
as
redirect_url
:
# Simulate that we're embargoed from accessing this
# course based on our IP address.
response
=
self
.
_get_page
(
'verify_student_start_flow'
,
course
.
id
,
expected_status_code
=
302
)
self
.
assertRedirects
(
response
,
redirect_url
)
@mock.patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_COUNTRY_ACCESS'
:
True
})
def
test_embargo_allow
(
self
):
course
=
self
.
_create_course
(
"verified"
)
self
.
_get_page
(
'verify_student_start_flow'
,
course
.
id
)
def
_create_course
(
self
,
*
course_modes
,
**
kwargs
):
"""Create a new course with the specified course modes. """
course
=
CourseFactory
.
create
()
...
...
lms/djangoapps/verify_student/views.py
View file @
70ec4c5f
...
...
@@ -8,6 +8,7 @@ import decimal
import
datetime
from
collections
import
namedtuple
from
pytz
import
UTC
from
ipware.ip
import
get_ip
from
edxmako.shortcuts
import
render_to_response
,
render_to_string
...
...
@@ -46,6 +47,8 @@ from .exceptions import WindowExpiredException
from
xmodule.modulestore.django
import
modulestore
from
microsite_configuration
import
microsite
from
embargo
import
api
as
embargo_api
from
util.json_request
import
JsonResponse
from
util.date_utils
import
get_default_time_display
...
...
@@ -256,6 +259,17 @@ class PayAndVerifyView(View):
log
.
warn
(
u"No course specified for verification flow request."
)
raise
Http404
# Check whether the user has access to this course
# based on country access rules.
redirect_url
=
embargo_api
.
redirect_if_blocked
(
course_key
,
user
=
request
.
user
,
ip_address
=
get_ip
(
request
),
url
=
request
.
path
)
if
redirect_url
:
return
redirect
(
redirect_url
)
# Check that the course has an unexpired verified mode
course_mode
,
expired_course_mode
=
self
.
_get_verified_modes_for_course
(
course_key
)
...
...
lms/static/js/spec/student_account/enrollment_spec.js
View file @
70ec4c5f
...
...
@@ -6,7 +6,8 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
var
COURSE_KEY
=
'edX/DemoX/Fall'
,
ENROLL_URL
=
'/api/enrollment/v1/enrollment'
,
FORWARD_URL
=
'/course_modes/choose/edX/DemoX/Fall/'
;
FORWARD_URL
=
'/course_modes/choose/edX/DemoX/Fall/'
,
EMBARGO_MSG_URL
=
'/embargo/blocked-message/enrollment/default/'
;
beforeEach
(
function
()
{
// Mock the redirect call
...
...
@@ -49,6 +50,27 @@ define(['js/common_helpers/ajax_helpers', 'js/student_account/enrollment'],
expect
(
EnrollmentInterface
.
redirect
).
toHaveBeenCalledWith
(
FORWARD_URL
);
});
it
(
'redirects the user if blocked by an embargo'
,
function
()
{
// Spy on Ajax requests
var
requests
=
AjaxHelpers
.
requests
(
this
);
// Attempt to enroll the user
EnrollmentInterface
.
enroll
(
COURSE_KEY
);
// Simulate an error response (403) from the server
// with a "user_message_url" parameter for the redirect.
// This will redirect the user to a page with messaging
// explaining why he/she can't enroll.
AjaxHelpers
.
respondWithError
(
requests
,
403
,
{
'user_message_url'
:
EMBARGO_MSG_URL
}
);
// Verify that the user was redirected
expect
(
EnrollmentInterface
.
redirect
).
toHaveBeenCalledWith
(
EMBARGO_MSG_URL
);
});
});
}
);
lms/static/js/student_account/enrollment.js
View file @
70ec4c5f
...
...
@@ -36,7 +36,26 @@ var edx = edx || {};
data
:
data
,
headers
:
this
.
headers
,
context
:
this
}).
always
(
function
()
{
})
.
fail
(
function
(
jqXHR
)
{
var
responseData
=
JSON
.
parse
(
jqXHR
.
responseText
);
if
(
jqXHR
.
status
===
403
&&
responseData
.
user_message_url
)
{
// Check if we've been blocked from the course
// because of country access rules.
// If so, redirect to a page explaining to the user
// why they were blocked.
this
.
redirect
(
responseData
.
user_message_url
);
}
else
{
// Otherwise, go to the track selection page as usual.
// This can occur, for example, when a course does not
// have a free enrollment mode, so we can't auto-enroll.
this
.
redirect
(
this
.
trackSelectionUrl
(
courseKey
)
);
}
})
.
done
(
function
()
{
// If we successfully enrolled, go to the track selection
// page to allow the user to choose a paid enrollment mode.
this
.
redirect
(
this
.
trackSelectionUrl
(
courseKey
)
);
});
},
...
...
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