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
40f270c9
Commit
40f270c9
authored
Sep 24, 2014
by
zubair-arbi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add couse key verification decorator in common for use in both studio and lms
PLAT-88
parent
c57f1c81
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
71 additions
and
33 deletions
+71
-33
cms/djangoapps/contentstore/tests/tests.py
+28
-0
cms/djangoapps/contentstore/views/import_export.py
+4
-0
common/djangoapps/util/views.py
+23
-0
lms/djangoapps/courseware/tests/test_tabs.py
+1
-1
lms/djangoapps/courseware/tests/test_views.py
+5
-4
lms/djangoapps/courseware/views.py
+10
-28
No files found.
cms/djangoapps/contentstore/tests/tests.py
View file @
40f270c9
...
@@ -4,6 +4,7 @@ This test file will test registration, login, activation, and session activity t
...
@@ -4,6 +4,7 @@ This test file will test registration, login, activation, and session activity t
import
time
import
time
import
mock
import
mock
import
unittest
import
unittest
from
ddt
import
ddt
,
data
,
unpack
from
django.test.utils
import
override_settings
from
django.test.utils
import
override_settings
from
django.core.cache
import
cache
from
django.core.cache
import
cache
...
@@ -315,3 +316,30 @@ class ForumTestCase(CourseTestCase):
...
@@ -315,3 +316,30 @@ class ForumTestCase(CourseTestCase):
]
]
self
.
course
.
discussion_blackouts
=
[(
t
.
isoformat
(),
t2
.
isoformat
())
for
t
,
t2
in
times2
]
self
.
course
.
discussion_blackouts
=
[(
t
.
isoformat
(),
t2
.
isoformat
())
for
t
,
t2
in
times2
]
self
.
assertFalse
(
self
.
course
.
forum_posts_allowed
)
self
.
assertFalse
(
self
.
course
.
forum_posts_allowed
)
@ddt
class
CourseKeyVerificationTestCase
(
CourseTestCase
):
def
setUp
(
self
):
"""
Create test course.
"""
super
(
CourseKeyVerificationTestCase
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
(
org
=
'edX'
,
number
=
'test_course_key'
,
display_name
=
'Test Course'
)
@data
((
'edX/test_course_key/Test_Course'
,
200
),
(
'slashes:edX+test_course_key+Test_Course'
,
404
))
@unpack
def
test_course_key_decorator
(
self
,
course_key
,
status_code
):
"""
Tests for the ensure_valid_course_key decorator.
"""
url
=
'/import/{course_key}'
.
format
(
course_key
=
course_key
)
resp
=
self
.
client
.
get_html
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
status_code
)
url
=
'/import_status/{course_key}/{filename}'
.
format
(
course_key
=
course_key
,
filename
=
'xyz.tar.gz'
)
resp
=
self
.
client
.
get_html
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
status_code
)
cms/djangoapps/contentstore/views/import_export.py
View file @
40f270c9
...
@@ -34,6 +34,7 @@ from extract_tar import safetar_extractall
...
@@ -34,6 +34,7 @@ from extract_tar import safetar_extractall
from
student
import
auth
from
student
import
auth
from
student.roles
import
CourseInstructorRole
,
CourseStaffRole
,
GlobalStaff
from
student.roles
import
CourseInstructorRole
,
CourseStaffRole
,
GlobalStaff
from
util.json_request
import
JsonResponse
from
util.json_request
import
JsonResponse
from
util.views
import
ensure_valid_course_key
from
contentstore.utils
import
reverse_course_url
,
reverse_usage_url
from
contentstore.utils
import
reverse_course_url
,
reverse_usage_url
...
@@ -52,6 +53,7 @@ CONTENT_RE = re.compile(r"(?P<start>\d{1,11})-(?P<stop>\d{1,11})/(?P<end>\d{1,11
...
@@ -52,6 +53,7 @@ CONTENT_RE = re.compile(r"(?P<start>\d{1,11})-(?P<stop>\d{1,11})/(?P<end>\d{1,11
@login_required
@login_required
@ensure_csrf_cookie
@ensure_csrf_cookie
@require_http_methods
((
"GET"
,
"POST"
,
"PUT"
))
@require_http_methods
((
"GET"
,
"POST"
,
"PUT"
))
@ensure_valid_course_key
def
import_handler
(
request
,
course_key_string
):
def
import_handler
(
request
,
course_key_string
):
"""
"""
The restful handler for importing a course.
The restful handler for importing a course.
...
@@ -299,6 +301,7 @@ def _save_request_status(request, key, status):
...
@@ -299,6 +301,7 @@ def _save_request_status(request, key, status):
@require_GET
@require_GET
@ensure_csrf_cookie
@ensure_csrf_cookie
@login_required
@login_required
@ensure_valid_course_key
def
import_status_handler
(
request
,
course_key_string
,
filename
=
None
):
def
import_status_handler
(
request
,
course_key_string
,
filename
=
None
):
"""
"""
Returns an integer corresponding to the status of a file import. These are:
Returns an integer corresponding to the status of a file import. These are:
...
@@ -328,6 +331,7 @@ def import_status_handler(request, course_key_string, filename=None):
...
@@ -328,6 +331,7 @@ def import_status_handler(request, course_key_string, filename=None):
@ensure_csrf_cookie
@ensure_csrf_cookie
@login_required
@login_required
@require_http_methods
((
"GET"
,))
@require_http_methods
((
"GET"
,))
@ensure_valid_course_key
def
export_handler
(
request
,
course_key_string
):
def
export_handler
(
request
,
course_key_string
):
"""
"""
The restful handler for exporting a course.
The restful handler for exporting a course.
...
...
common/djangoapps/util/views.py
View file @
40f270c9
import
json
import
json
import
logging
import
logging
import
sys
import
sys
from
functools
import
wraps
from
django.conf
import
settings
from
django.conf
import
settings
from
django.core.validators
import
ValidationError
,
validate_email
from
django.core.validators
import
ValidationError
,
validate_email
...
@@ -16,10 +17,32 @@ from microsite_configuration import microsite
...
@@ -16,10 +17,32 @@ from microsite_configuration import microsite
import
calc
import
calc
import
track.views
import
track.views
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
def
ensure_valid_course_key
(
view_func
):
"""
This decorator should only be used with views which have argument course_key_string (studio) or course_id (lms).
If course_key_string (studio) or course_id (lms) is not valid raise 404.
"""
@wraps
(
view_func
)
def
inner
(
request
,
*
args
,
**
kwargs
):
course_key
=
kwargs
.
get
(
'course_key_string'
)
or
kwargs
.
get
(
'course_id'
)
if
course_key
is
not
None
:
try
:
CourseKey
.
from_string
(
course_key
)
except
InvalidKeyError
:
raise
Http404
response
=
view_func
(
request
,
*
args
,
**
kwargs
)
return
response
return
inner
@requires_csrf_token
@requires_csrf_token
def
jsonable_server_error
(
request
,
template_name
=
'500.html'
):
def
jsonable_server_error
(
request
,
template_name
=
'500.html'
):
"""
"""
...
...
lms/djangoapps/courseware/tests/test_tabs.py
View file @
40f270c9
...
@@ -47,7 +47,7 @@ class StaticTabDateTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
...
@@ -47,7 +47,7 @@ class StaticTabDateTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
def
test_invalid_course_key
(
self
):
def
test_invalid_course_key
(
self
):
request
=
get_request_for_user
(
UserFactory
.
create
())
request
=
get_request_for_user
(
UserFactory
.
create
())
with
self
.
assertRaises
(
Http404
):
with
self
.
assertRaises
(
Http404
):
static_tab
(
request
,
'edX/toy'
,
'new_tab'
)
static_tab
(
request
,
course_id
=
'edX/toy'
,
tab_slug
=
'new_tab'
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
def
test_get_static_tab_contents
(
self
):
def
test_get_static_tab_contents
(
self
):
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
40f270c9
...
@@ -35,6 +35,7 @@ from course_modes.models import CourseMode
...
@@ -35,6 +35,7 @@ from course_modes.models import CourseMode
import
shoppingcart
import
shoppingcart
from
util.tests.test_date_utils
import
fake_ugettext
,
fake_pgettext
from
util.tests.test_date_utils
import
fake_ugettext
,
fake_pgettext
from
util.views
import
ensure_valid_course_key
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
...
@@ -568,9 +569,9 @@ class ProgressPageTests(ModuleStoreTestCase):
...
@@ -568,9 +569,9 @@ class ProgressPageTests(ModuleStoreTestCase):
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
class
TestVerifyCourseIdDecorator
(
TestCase
):
class
VerifyCourseKeyDecoratorTests
(
TestCase
):
"""
"""
Tests for the
verify_course_id
decorator.
Tests for the
ensure_valid_course_key
decorator.
"""
"""
def
setUp
(
self
):
def
setUp
(
self
):
...
@@ -580,12 +581,12 @@ class TestVerifyCourseIdDecorator(TestCase):
...
@@ -580,12 +581,12 @@ class TestVerifyCourseIdDecorator(TestCase):
def
test_decorator_with_valid_course_id
(
self
):
def
test_decorator_with_valid_course_id
(
self
):
mocked_view
=
create_autospec
(
views
.
course_about
)
mocked_view
=
create_autospec
(
views
.
course_about
)
view_function
=
views
.
verify_course_id
(
mocked_view
)
view_function
=
ensure_valid_course_key
(
mocked_view
)
view_function
(
self
.
request
,
course_id
=
self
.
valid_course_id
)
view_function
(
self
.
request
,
course_id
=
self
.
valid_course_id
)
self
.
assertTrue
(
mocked_view
.
called
)
self
.
assertTrue
(
mocked_view
.
called
)
def
test_decorator_with_invalid_course_id
(
self
):
def
test_decorator_with_invalid_course_id
(
self
):
mocked_view
=
create_autospec
(
views
.
course_about
)
mocked_view
=
create_autospec
(
views
.
course_about
)
view_function
=
views
.
verify_course_id
(
mocked_view
)
view_function
=
ensure_valid_course_key
(
mocked_view
)
self
.
assertRaises
(
Http404
,
view_function
,
self
.
request
,
course_id
=
self
.
invalid_course_id
)
self
.
assertRaises
(
Http404
,
view_function
,
self
.
request
,
course_id
=
self
.
invalid_course_id
)
self
.
assertFalse
(
mocked_view
.
called
)
self
.
assertFalse
(
mocked_view
.
called
)
lms/djangoapps/courseware/views.py
View file @
40f270c9
...
@@ -55,6 +55,7 @@ from microsite_configuration import microsite
...
@@ -55,6 +55,7 @@ from microsite_configuration import microsite
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
instructor.enrollment
import
uses_shib
from
instructor.enrollment
import
uses_shib
from
util.views
import
ensure_valid_course_key
log
=
logging
.
getLogger
(
"edx.courseware"
)
log
=
logging
.
getLogger
(
"edx.courseware"
)
template_imports
=
{
'urllib'
:
urllib
}
template_imports
=
{
'urllib'
:
urllib
}
...
@@ -85,25 +86,6 @@ def user_groups(user):
...
@@ -85,25 +86,6 @@ def user_groups(user):
return
group_names
return
group_names
def
verify_course_id
(
view_func
):
"""
This decorator should only be used with views whose kwargs must contain course_id.
If course_id is not valid raise 404.
"""
@wraps
(
view_func
)
def
_decorated
(
request
,
*
args
,
**
kwargs
):
course_id
=
kwargs
.
get
(
"course_id"
)
try
:
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
except
InvalidKeyError
:
raise
Http404
response
=
view_func
(
request
,
*
args
,
**
kwargs
)
return
response
return
_decorated
@ensure_csrf_cookie
@ensure_csrf_cookie
@cache_if_anonymous
@cache_if_anonymous
def
courses
(
request
):
def
courses
(
request
):
...
@@ -265,7 +247,7 @@ def chat_settings(course, user):
...
@@ -265,7 +247,7 @@ def chat_settings(course, user):
@login_required
@login_required
@ensure_csrf_cookie
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@
verify_course_id
@
ensure_valid_course_key
def
index
(
request
,
course_id
,
chapter
=
None
,
section
=
None
,
def
index
(
request
,
course_id
,
chapter
=
None
,
section
=
None
,
position
=
None
):
position
=
None
):
"""
"""
...
@@ -503,7 +485,7 @@ def index(request, course_id, chapter=None, section=None,
...
@@ -503,7 +485,7 @@ def index(request, course_id, chapter=None, section=None,
@ensure_csrf_cookie
@ensure_csrf_cookie
@
verify_course_id
@
ensure_valid_course_key
def
jump_to_id
(
request
,
course_id
,
module_id
):
def
jump_to_id
(
request
,
course_id
,
module_id
):
"""
"""
This entry point allows for a shorter version of a jump to where just the id of the element is
This entry point allows for a shorter version of a jump to where just the id of the element is
...
@@ -562,7 +544,7 @@ def jump_to(request, course_id, location):
...
@@ -562,7 +544,7 @@ def jump_to(request, course_id, location):
@ensure_csrf_cookie
@ensure_csrf_cookie
@
verify_course_id
@
ensure_valid_course_key
def
course_info
(
request
,
course_id
):
def
course_info
(
request
,
course_id
):
"""
"""
Display the course's info.html, or 404 if there is no such course.
Display the course's info.html, or 404 if there is no such course.
...
@@ -610,7 +592,7 @@ def course_info(request, course_id):
...
@@ -610,7 +592,7 @@ def course_info(request, course_id):
@ensure_csrf_cookie
@ensure_csrf_cookie
@
verify_course_id
@
ensure_valid_course_key
def
static_tab
(
request
,
course_id
,
tab_slug
):
def
static_tab
(
request
,
course_id
,
tab_slug
):
"""
"""
Display the courses tab with the given name.
Display the courses tab with the given name.
...
@@ -644,7 +626,7 @@ def static_tab(request, course_id, tab_slug):
...
@@ -644,7 +626,7 @@ def static_tab(request, course_id, tab_slug):
@ensure_csrf_cookie
@ensure_csrf_cookie
@
verify_course_id
@
ensure_valid_course_key
def
syllabus
(
request
,
course_id
):
def
syllabus
(
request
,
course_id
):
"""
"""
Display the course's syllabus.html, or 404 if there is no such course.
Display the course's syllabus.html, or 404 if there is no such course.
...
@@ -756,7 +738,7 @@ def course_about(request, course_id):
...
@@ -756,7 +738,7 @@ def course_about(request, course_id):
@ensure_csrf_cookie
@ensure_csrf_cookie
@cache_if_anonymous
@cache_if_anonymous
@
verify_course_id
@
ensure_valid_course_key
def
mktg_course_about
(
request
,
course_id
):
def
mktg_course_about
(
request
,
course_id
):
"""
"""
This is the button that gets put into an iframe on the Drupal site
This is the button that gets put into an iframe on the Drupal site
...
@@ -814,7 +796,7 @@ def mktg_course_about(request, course_id):
...
@@ -814,7 +796,7 @@ def mktg_course_about(request, course_id):
@login_required
@login_required
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@transaction.commit_manually
@transaction.commit_manually
@
verify_course_id
@
ensure_valid_course_key
def
progress
(
request
,
course_id
,
student_id
=
None
):
def
progress
(
request
,
course_id
,
student_id
=
None
):
"""
"""
Wraps "_progress" with the manual_transaction context manager just in case
Wraps "_progress" with the manual_transaction context manager just in case
...
@@ -895,7 +877,7 @@ def fetch_reverify_banner_info(request, course_key):
...
@@ -895,7 +877,7 @@ def fetch_reverify_banner_info(request, course_key):
@login_required
@login_required
@
verify_course_id
@
ensure_valid_course_key
def
submission_history
(
request
,
course_id
,
student_username
,
location
):
def
submission_history
(
request
,
course_id
,
student_username
,
location
):
"""Render an HTML fragment (meant for inclusion elsewhere) that renders a
"""Render an HTML fragment (meant for inclusion elsewhere) that renders a
history of all state changes made by this user for this problem location.
history of all state changes made by this user for this problem location.
...
@@ -1003,7 +985,7 @@ def get_static_tab_contents(request, course, tab):
...
@@ -1003,7 +985,7 @@ def get_static_tab_contents(request, course, tab):
@require_GET
@require_GET
@
verify_course_id
@
ensure_valid_course_key
def
get_course_lti_endpoints
(
request
,
course_id
):
def
get_course_lti_endpoints
(
request
,
course_id
):
"""
"""
View that, given a course_id, returns the a JSON object that enumerates all of the LTI endpoints for that course.
View that, given a course_id, returns the a JSON object that enumerates all of the LTI endpoints for that course.
...
...
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