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
b24c2280
Commit
b24c2280
authored
Dec 02, 2016
by
Calen Pennington
Committed by
GitHub
Dec 02, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14047 from cpennington/safer-opaque-keys
Safer opaque keys
parents
d2b6c9eb
42617545
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
133 additions
and
43 deletions
+133
-43
cms/djangoapps/contentstore/views/certificates.py
+25
-0
cms/djangoapps/contentstore/views/preview.py
+2
-2
cms/djangoapps/contentstore/views/tests/test_certificates.py
+90
-31
cms/lib/xblock/tagging/test.py
+6
-3
common/lib/xmodule/setup.py
+1
-1
common/lib/xmodule/xmodule/contentstore/content.py
+3
-0
common/lib/xmodule/xmodule/x_module.py
+3
-3
lms/djangoapps/courseware/model_data.py
+2
-1
pavelib/tests.py
+0
-1
requirements/edx/base.txt
+1
-1
No files found.
cms/djangoapps/contentstore/views/certificates.py
View file @
b24c2280
...
@@ -22,6 +22,7 @@ course.certificates: {
...
@@ -22,6 +22,7 @@ course.certificates: {
}
}
"""
"""
import
json
import
json
import
logging
from
django.conf
import
settings
from
django.conf
import
settings
from
django.contrib.auth.decorators
import
login_required
from
django.contrib.auth.decorators
import
login_required
...
@@ -33,6 +34,7 @@ from django.views.decorators.http import require_http_methods
...
@@ -33,6 +34,7 @@ from django.views.decorators.http import require_http_methods
from
contentstore.utils
import
reverse_course_url
from
contentstore.utils
import
reverse_course_url
from
edxmako.shortcuts
import
render_to_response
from
edxmako.shortcuts
import
render_to_response
from
opaque_keys.edx.keys
import
CourseKey
,
AssetKey
from
opaque_keys.edx.keys
import
CourseKey
,
AssetKey
from
opaque_keys
import
InvalidKeyError
from
eventtracking
import
tracker
from
eventtracking
import
tracker
from
student.auth
import
has_studio_write_access
from
student.auth
import
has_studio_write_access
from
student.roles
import
GlobalStaff
from
student.roles
import
GlobalStaff
...
@@ -49,6 +51,8 @@ from contentstore.utils import get_lms_link_for_certificate_web_view
...
@@ -49,6 +51,8 @@ from contentstore.utils import get_lms_link_for_certificate_web_view
CERTIFICATE_SCHEMA_VERSION
=
1
CERTIFICATE_SCHEMA_VERSION
=
1
CERTIFICATE_MINIMUM_ID
=
100
CERTIFICATE_MINIMUM_ID
=
100
LOGGER
=
logging
.
getLogger
(
__name__
)
def
_get_course_and_check_access
(
course_key
,
user
,
depth
=
0
):
def
_get_course_and_check_access
(
course_key
,
user
,
depth
=
0
):
"""
"""
...
@@ -67,11 +71,32 @@ def _delete_asset(course_key, asset_key_string):
...
@@ -67,11 +71,32 @@ def _delete_asset(course_key, asset_key_string):
remove asset by calling delete_asset method of assets module.
remove asset by calling delete_asset method of assets module.
"""
"""
if
asset_key_string
:
if
asset_key_string
:
try
:
asset_key
=
AssetKey
.
from_string
(
asset_key_string
)
except
InvalidKeyError
:
# remove first slash in asset path
# remove first slash in asset path
# otherwise it generates InvalidKeyError in case of split modulestore
# otherwise it generates InvalidKeyError in case of split modulestore
if
'/'
==
asset_key_string
[
0
]:
if
'/'
==
asset_key_string
[
0
]:
asset_key_string
=
asset_key_string
[
1
:]
asset_key_string
=
asset_key_string
[
1
:]
try
:
asset_key
=
AssetKey
.
from_string
(
asset_key_string
)
asset_key
=
AssetKey
.
from_string
(
asset_key_string
)
except
InvalidKeyError
:
# Unable to parse the asset key, log and return
LOGGER
.
info
(
"In course
%
r, unable to parse asset key
%
r, not attempting to delete signatory."
,
course_key
,
asset_key_string
,
)
return
else
:
# Unable to parse the asset key, log and return
LOGGER
.
info
(
"In course
%
r, unable to parse asset key
%
r, not attempting to delete signatory."
,
course_key
,
asset_key_string
,
)
return
try
:
try
:
delete_asset
(
course_key
,
asset_key
)
delete_asset
(
course_key
,
asset_key
)
# If the asset was not found, it doesn't have to be deleted...
# If the asset was not found, it doesn't have to be deleted...
...
...
cms/djangoapps/contentstore/views/preview.py
View file @
b24c2280
...
@@ -21,7 +21,7 @@ from xmodule.services import SettingsService
...
@@ -21,7 +21,7 @@ from xmodule.services import SettingsService
from
xmodule.modulestore.django
import
modulestore
,
ModuleI18nService
from
xmodule.modulestore.django
import
modulestore
,
ModuleI18nService
from
xmodule.mixin
import
wrap_with_license
from
xmodule.mixin
import
wrap_with_license
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.asides
import
AsideUsageKeyV1
from
opaque_keys.edx.asides
import
AsideUsageKeyV1
,
AsideUsageKeyV2
from
xmodule.x_module
import
ModuleSystem
from
xmodule.x_module
import
ModuleSystem
from
xblock.runtime
import
KvsFieldData
from
xblock.runtime
import
KvsFieldData
from
xblock.django.request
import
webob_to_django_response
,
django_to_webob_request
from
xblock.django.request
import
webob_to_django_response
,
django_to_webob_request
...
@@ -57,7 +57,7 @@ def preview_handler(request, usage_key_string, handler, suffix=''):
...
@@ -57,7 +57,7 @@ def preview_handler(request, usage_key_string, handler, suffix=''):
"""
"""
usage_key
=
UsageKey
.
from_string
(
usage_key_string
)
usage_key
=
UsageKey
.
from_string
(
usage_key_string
)
if
isinstance
(
usage_key
,
AsideUsageKeyV1
):
if
isinstance
(
usage_key
,
(
AsideUsageKeyV1
,
AsideUsageKeyV2
)
):
descriptor
=
modulestore
()
.
get_item
(
usage_key
.
usage_key
)
descriptor
=
modulestore
()
.
get_item
(
usage_key
.
usage_key
)
for
aside
in
descriptor
.
runtime
.
get_asides
(
descriptor
):
for
aside
in
descriptor
.
runtime
.
get_asides
(
descriptor
):
if
aside
.
scope_ids
.
block_type
==
usage_key
.
aside_type
:
if
aside
.
scope_ids
.
block_type
==
usage_key
.
aside_type
:
...
...
cms/djangoapps/contentstore/views/tests/test_certificates.py
View file @
b24c2280
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
"""
"""
Certificates Tests.
Certificates Tests.
"""
"""
import
itertools
import
json
import
json
import
mock
import
mock
import
ddt
import
ddt
...
@@ -11,7 +12,6 @@ from django.conf import settings
...
@@ -11,7 +12,6 @@ from django.conf import settings
from
django.test.utils
import
override_settings
from
django.test.utils
import
override_settings
from
opaque_keys.edx.keys
import
AssetKey
from
opaque_keys.edx.keys
import
AssetKey
from
opaque_keys.edx.locations
import
AssetLocation
from
contentstore.utils
import
reverse_course_url
from
contentstore.utils
import
reverse_course_url
from
contentstore.views.certificates
import
CERTIFICATE_SCHEMA_VERSION
from
contentstore.views.certificates
import
CERTIFICATE_SCHEMA_VERSION
...
@@ -53,6 +53,9 @@ CERTIFICATE_JSON_WITH_SIGNATORIES = {
...
@@ -53,6 +53,9 @@ CERTIFICATE_JSON_WITH_SIGNATORIES = {
]
]
}
}
C4X_SIGNATORY_PATH
=
'/c4x/test/CSS101/asset/Signature{}.png'
SIGNATORY_PATH
=
'asset-v1:test+CSS101+SP2017+type@asset+block@Signature{}.png'
# pylint: disable=no-member
# pylint: disable=no-member
class
HelperMethods
(
object
):
class
HelperMethods
(
object
):
...
@@ -70,7 +73,8 @@ class HelperMethods(object):
...
@@ -70,7 +73,8 @@ class HelperMethods(object):
)
)
contentstore
()
.
save
(
content
)
contentstore
()
.
save
(
content
)
def
_add_course_certificates
(
self
,
count
=
1
,
signatory_count
=
0
,
is_active
=
False
):
def
_add_course_certificates
(
self
,
count
=
1
,
signatory_count
=
0
,
is_active
=
False
,
asset_path_format
=
C4X_SIGNATORY_PATH
):
"""
"""
Create certificate for the course.
Create certificate for the course.
"""
"""
...
@@ -78,18 +82,14 @@ class HelperMethods(object):
...
@@ -78,18 +82,14 @@ class HelperMethods(object):
{
{
'name'
:
'Name '
+
str
(
i
),
'name'
:
'Name '
+
str
(
i
),
'title'
:
'Title '
+
str
(
i
),
'title'
:
'Title '
+
str
(
i
),
'signature_image_path'
:
'/c4x/test/CSS101/asset/Signature{}.png'
.
format
(
i
),
'signature_image_path'
:
asset_path_format
.
format
(
i
),
'id'
:
i
'id'
:
i
}
for
i
in
xrange
(
signatory_count
)
}
for
i
in
xrange
(
signatory_count
)
]
]
# create images for signatory signatures except the last signatory
# create images for signatory signatures except the last signatory
for
idx
,
signatory
in
enumerate
(
signatories
):
self
.
_create_fake_images
(
signatory
[
'signature_image_path'
]
for
signatory
in
signatories
[:
-
1
])
if
len
(
signatories
)
>
2
and
idx
==
len
(
signatories
)
-
1
:
continue
else
:
self
.
_create_fake_images
([
signatory
[
'signature_image_path'
]])
certificates
=
[
certificates
=
[
{
{
...
@@ -557,11 +557,61 @@ class CertificatesDetailHandlerTestCase(
...
@@ -557,11 +557,61 @@ class CertificatesDetailHandlerTestCase(
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
content
,
expected
)
self
.
assertEqual
(
content
,
expected
)
def
test_can_delete_certificate_with_signatories
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_can_delete_certificate_with_signatories
(
self
,
signatory_path
):
"""
Delete certificate
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
asset_path_format
=
signatory_path
)
response
=
self
.
client
.
delete
(
self
.
_url
(
cid
=
1
),
content_type
=
"application/json"
,
HTTP_ACCEPT
=
"application/json"
,
HTTP_X_REQUESTED_WITH
=
"XMLHttpRequest"
,
)
self
.
assertEqual
(
response
.
status_code
,
204
)
self
.
assert_event_emitted
(
'edx.certificate.configuration.deleted'
,
course_id
=
unicode
(
self
.
course
.
id
),
configuration_id
=
'1'
,
)
self
.
reload_course
()
# Verify that certificates are properly updated in the course.
certificates
=
self
.
course
.
certificates
[
'certificates'
]
self
.
assertEqual
(
len
(
certificates
),
1
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'name'
),
'Name 0'
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'description'
),
'Description 0'
)
def
test_can_delete_certificate_with_slash_prefix_signatory
(
self
):
"""
Delete certificate
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
asset_path_format
=
"/"
+
SIGNATORY_PATH
)
response
=
self
.
client
.
delete
(
self
.
_url
(
cid
=
1
),
content_type
=
"application/json"
,
HTTP_ACCEPT
=
"application/json"
,
HTTP_X_REQUESTED_WITH
=
"XMLHttpRequest"
,
)
self
.
assertEqual
(
response
.
status_code
,
204
)
self
.
assert_event_emitted
(
'edx.certificate.configuration.deleted'
,
course_id
=
unicode
(
self
.
course
.
id
),
configuration_id
=
'1'
,
)
self
.
reload_course
()
# Verify that certificates are properly updated in the course.
certificates
=
self
.
course
.
certificates
[
'certificates'
]
self
.
assertEqual
(
len
(
certificates
),
1
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'name'
),
'Name 0'
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'description'
),
'Description 0'
)
@ddt.data
(
"not_a_valid_asset_key{}.png"
,
"/not_a_valid_asset_key{}.png"
)
def
test_can_delete_certificate_with_invalid_signatory
(
self
,
signatory_path
):
"""
"""
Delete certificate
Delete certificate
"""
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
)
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
asset_path_format
=
signatory_path
)
response
=
self
.
client
.
delete
(
response
=
self
.
client
.
delete
(
self
.
_url
(
cid
=
1
),
self
.
_url
(
cid
=
1
),
content_type
=
"application/json"
,
content_type
=
"application/json"
,
...
@@ -581,11 +631,12 @@ class CertificatesDetailHandlerTestCase(
...
@@ -581,11 +631,12 @@ class CertificatesDetailHandlerTestCase(
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'name'
),
'Name 0'
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'name'
),
'Name 0'
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'description'
),
'Description 0'
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'description'
),
'Description 0'
)
def
test_delete_certificate_without_write_permissions
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_delete_certificate_without_write_permissions
(
self
,
signatory_path
):
"""
"""
Tests certificate deletion without write permission on course.
Tests certificate deletion without write permission on course.
"""
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
)
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
asset_path_format
=
signatory_path
)
user
=
UserFactory
()
user
=
UserFactory
()
self
.
client
.
login
(
username
=
user
.
username
,
password
=
'test'
)
self
.
client
.
login
(
username
=
user
.
username
,
password
=
'test'
)
response
=
self
.
client
.
delete
(
response
=
self
.
client
.
delete
(
...
@@ -596,11 +647,12 @@ class CertificatesDetailHandlerTestCase(
...
@@ -596,11 +647,12 @@ class CertificatesDetailHandlerTestCase(
)
)
self
.
assertEqual
(
response
.
status_code
,
403
)
self
.
assertEqual
(
response
.
status_code
,
403
)
def
test_delete_certificate_without_global_staff_permissions
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_delete_certificate_without_global_staff_permissions
(
self
,
signatory_path
):
"""
"""
Tests deletion of an active certificate without global staff permission on course.
Tests deletion of an active certificate without global staff permission on course.
"""
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
is_active
=
True
)
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
is_active
=
True
,
asset_path_format
=
signatory_path
)
user
=
UserFactory
()
user
=
UserFactory
()
for
role
in
[
CourseInstructorRole
,
CourseStaffRole
]:
for
role
in
[
CourseInstructorRole
,
CourseStaffRole
]:
role
(
self
.
course
.
id
)
.
add_users
(
user
)
role
(
self
.
course
.
id
)
.
add_users
(
user
)
...
@@ -613,11 +665,12 @@ class CertificatesDetailHandlerTestCase(
...
@@ -613,11 +665,12 @@ class CertificatesDetailHandlerTestCase(
)
)
self
.
assertEqual
(
response
.
status_code
,
403
)
self
.
assertEqual
(
response
.
status_code
,
403
)
def
test_update_active_certificate_without_global_staff_permissions
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_update_active_certificate_without_global_staff_permissions
(
self
,
signatory_path
):
"""
"""
Tests update of an active certificate without global staff permission on course.
Tests update of an active certificate without global staff permission on course.
"""
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
is_active
=
True
)
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
1
,
is_active
=
True
,
asset_path_format
=
signatory_path
)
cert_data
=
{
cert_data
=
{
u'id'
:
1
,
u'id'
:
1
,
u'version'
:
CERTIFICATE_SCHEMA_VERSION
,
u'version'
:
CERTIFICATE_SCHEMA_VERSION
,
...
@@ -654,14 +707,15 @@ class CertificatesDetailHandlerTestCase(
...
@@ -654,14 +707,15 @@ class CertificatesDetailHandlerTestCase(
)
)
self
.
assertEqual
(
response
.
status_code
,
404
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_can_delete_signatory
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_can_delete_signatory
(
self
,
signatory_path
):
"""
"""
Delete an existing certificate signatory
Delete an existing certificate signatory
"""
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
3
)
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
3
,
asset_path_format
=
signatory_path
)
certificates
=
self
.
course
.
certificates
[
'certificates'
]
certificates
=
self
.
course
.
certificates
[
'certificates'
]
signatory
=
certificates
[
1
]
.
get
(
"signatories"
)[
1
]
signatory
=
certificates
[
1
]
.
get
(
"signatories"
)[
1
]
image_asset_location
=
Asset
Location
.
from_deprecated
_string
(
signatory
[
'signature_image_path'
])
image_asset_location
=
Asset
Key
.
from
_string
(
signatory
[
'signature_image_path'
])
content
=
contentstore
()
.
find
(
image_asset_location
)
content
=
contentstore
()
.
find
(
image_asset_location
)
self
.
assertIsNotNone
(
content
)
self
.
assertIsNotNone
(
content
)
test_url
=
'{}/signatories/1'
.
format
(
self
.
_url
(
cid
=
1
))
test_url
=
'{}/signatories/1'
.
format
(
self
.
_url
(
cid
=
1
))
...
@@ -680,11 +734,12 @@ class CertificatesDetailHandlerTestCase(
...
@@ -680,11 +734,12 @@ class CertificatesDetailHandlerTestCase(
# make sure signatory signature image is deleted too
# make sure signatory signature image is deleted too
self
.
assertRaises
(
NotFoundError
,
contentstore
()
.
find
,
image_asset_location
)
self
.
assertRaises
(
NotFoundError
,
contentstore
()
.
find
,
image_asset_location
)
def
test_deleting_signatory_without_signature
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_deleting_signatory_without_signature
(
self
,
signatory_path
):
"""
"""
Delete an signatory whose signature image is already removed or does not exist
Delete an signatory whose signature image is already removed or does not exist
"""
"""
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
4
)
self
.
_add_course_certificates
(
count
=
2
,
signatory_count
=
4
,
asset_path_format
=
signatory_path
)
test_url
=
'{}/signatories/3'
.
format
(
self
.
_url
(
cid
=
1
))
test_url
=
'{}/signatories/3'
.
format
(
self
.
_url
(
cid
=
1
))
response
=
self
.
client
.
delete
(
response
=
self
.
client
.
delete
(
test_url
,
test_url
,
...
@@ -708,12 +763,13 @@ class CertificatesDetailHandlerTestCase(
...
@@ -708,12 +763,13 @@ class CertificatesDetailHandlerTestCase(
)
)
self
.
assertEqual
(
response
.
status_code
,
404
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_certificate_activation_success
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_certificate_activation_success
(
self
,
signatory_path
):
"""
"""
Activate and Deactivate the course certificate
Activate and Deactivate the course certificate
"""
"""
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
,
asset_path_format
=
signatory_path
)
is_active
=
True
is_active
=
True
for
i
in
range
(
2
):
for
i
in
range
(
2
):
...
@@ -736,14 +792,15 @@ class CertificatesDetailHandlerTestCase(
...
@@ -736,14 +792,15 @@ class CertificatesDetailHandlerTestCase(
course_id
=
unicode
(
self
.
course
.
id
),
course_id
=
unicode
(
self
.
course
.
id
),
)
)
@ddt.data
(
True
,
False
)
@ddt.data
(
*
itertools
.
product
([
True
,
False
],
[
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
]))
def
test_certificate_activation_without_write_permissions
(
self
,
activate
):
@ddt.unpack
def
test_certificate_activation_without_write_permissions
(
self
,
activate
,
signatory_path
):
"""
"""
Tests certificate Activate and Deactivate should not be allowed if user
Tests certificate Activate and Deactivate should not be allowed if user
does not have write permissions on course.
does not have write permissions on course.
"""
"""
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
,
asset_path_format
=
signatory_path
)
user
=
UserFactory
()
user
=
UserFactory
()
self
.
client
.
login
(
username
=
user
.
username
,
password
=
'test'
)
self
.
client
.
login
(
username
=
user
.
username
,
password
=
'test'
)
response
=
self
.
client
.
post
(
response
=
self
.
client
.
post
(
...
@@ -755,14 +812,15 @@ class CertificatesDetailHandlerTestCase(
...
@@ -755,14 +812,15 @@ class CertificatesDetailHandlerTestCase(
)
)
self
.
assertEquals
(
response
.
status_code
,
403
)
self
.
assertEquals
(
response
.
status_code
,
403
)
@ddt.data
(
True
,
False
)
@ddt.data
(
*
itertools
.
product
([
True
,
False
],
[
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
]))
def
test_certificate_activation_without_global_staff_permissions
(
self
,
activate
):
@ddt.unpack
def
test_certificate_activation_without_global_staff_permissions
(
self
,
activate
,
signatory_path
):
"""
"""
Tests certificate Activate and Deactivate should not be allowed if user
Tests certificate Activate and Deactivate should not be allowed if user
does not have global staff permissions on course.
does not have global staff permissions on course.
"""
"""
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
,
asset_path_format
=
signatory_path
)
user
=
UserFactory
()
user
=
UserFactory
()
for
role
in
[
CourseInstructorRole
,
CourseStaffRole
]:
for
role
in
[
CourseInstructorRole
,
CourseStaffRole
]:
role
(
self
.
course
.
id
)
.
add_users
(
user
)
role
(
self
.
course
.
id
)
.
add_users
(
user
)
...
@@ -776,7 +834,8 @@ class CertificatesDetailHandlerTestCase(
...
@@ -776,7 +834,8 @@ class CertificatesDetailHandlerTestCase(
)
)
self
.
assertEquals
(
response
.
status_code
,
403
)
self
.
assertEquals
(
response
.
status_code
,
403
)
def
test_certificate_activation_failure
(
self
):
@ddt.data
(
C4X_SIGNATORY_PATH
,
SIGNATORY_PATH
)
def
test_certificate_activation_failure
(
self
,
signatory_path
):
"""
"""
Certificate activation should fail when user has not read access to course then permission denied exception
Certificate activation should fail when user has not read access to course then permission denied exception
should raised.
should raised.
...
@@ -784,7 +843,7 @@ class CertificatesDetailHandlerTestCase(
...
@@ -784,7 +843,7 @@ class CertificatesDetailHandlerTestCase(
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
test_url
=
reverse_course_url
(
'certificates.certificate_activation_handler'
,
self
.
course
.
id
)
test_user_client
,
test_user
=
self
.
create_non_staff_authed_user_client
()
test_user_client
,
test_user
=
self
.
create_non_staff_authed_user_client
()
CourseEnrollment
.
enroll
(
test_user
,
self
.
course
.
id
)
CourseEnrollment
.
enroll
(
test_user
,
self
.
course
.
id
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
,
asset_path_format
=
signatory_path
)
response
=
test_user_client
.
post
(
response
=
test_user_client
.
post
(
test_url
,
test_url
,
data
=
json
.
dumps
({
"is_active"
:
True
}),
data
=
json
.
dumps
({
"is_active"
:
True
}),
...
...
cms/lib/xblock/tagging/test.py
View file @
b24c2280
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
Tests for the Studio Tagging XBlockAside
Tests for the Studio Tagging XBlockAside
"""
"""
import
ddt
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
...
@@ -17,13 +18,14 @@ from contentstore.utils import reverse_usage_url
...
@@ -17,13 +18,14 @@ from contentstore.utils import reverse_usage_url
from
contentstore.tests.utils
import
AjaxEnabledTestClient
from
contentstore.tests.utils
import
AjaxEnabledTestClient
from
django.test.client
import
RequestFactory
from
django.test.client
import
RequestFactory
from
student.tests.factories
import
UserFactory
from
student.tests.factories
import
UserFactory
from
opaque_keys.edx.asides
import
AsideUsageKeyV1
from
opaque_keys.edx.asides
import
AsideUsageKeyV1
,
AsideUsageKeyV2
from
datetime
import
datetime
from
datetime
import
datetime
from
pytz
import
UTC
from
pytz
import
UTC
from
lxml
import
etree
from
lxml
import
etree
from
StringIO
import
StringIO
from
StringIO
import
StringIO
@ddt.ddt
class
StructuredTagsAsideTestCase
(
ModuleStoreTestCase
):
class
StructuredTagsAsideTestCase
(
ModuleStoreTestCase
):
"""
"""
Base class for tests of StructuredTagsAside (tagging.py)
Base class for tests of StructuredTagsAside (tagging.py)
...
@@ -179,13 +181,14 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
...
@@ -179,13 +181,14 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
video_html
=
get_preview_fragment
(
request
,
self
.
video
,
context
)
.
content
video_html
=
get_preview_fragment
(
request
,
self
.
video
,
context
)
.
content
self
.
assertNotRegexpMatches
(
video_html
,
"<select"
)
self
.
assertNotRegexpMatches
(
video_html
,
"<select"
)
def
test_handle_requests
(
self
):
@ddt.data
(
AsideUsageKeyV1
,
AsideUsageKeyV2
)
def
test_handle_requests
(
self
,
aside_key_class
):
"""
"""
Checks that handler to save tags in StructuredTagsAside works properly
Checks that handler to save tags in StructuredTagsAside works properly
"""
"""
handler_url
=
reverse_usage_url
(
handler_url
=
reverse_usage_url
(
'preview_handler'
,
'preview_handler'
,
'
%
s:
%
s::
%
s'
%
(
AsideUsageKeyV1
.
CANONICAL_NAMESPACE
,
self
.
problem
.
location
,
self
.
aside_name
),
unicode
(
aside_key_class
(
self
.
problem
.
location
,
self
.
aside_name
)
),
kwargs
=
{
'handler'
:
'save_tags'
}
kwargs
=
{
'handler'
:
'save_tags'
}
)
)
...
...
common/lib/xmodule/setup.py
View file @
b24c2280
...
@@ -55,7 +55,7 @@ setup(
...
@@ -55,7 +55,7 @@ setup(
'capa'
,
'capa'
,
'path.py'
,
'path.py'
,
'webob'
,
'webob'
,
'edx-opaque-keys>=0.
3.4
,<1.0.0'
,
'edx-opaque-keys>=0.
4.0
,<1.0.0'
,
],
],
package_data
=
{
package_data
=
{
'xmodule'
:
[
'js/module/*'
],
'xmodule'
:
[
'js/module/*'
],
...
...
common/lib/xmodule/xmodule/contentstore/content.py
View file @
b24c2280
...
@@ -200,6 +200,9 @@ class StaticContent(object):
...
@@ -200,6 +200,9 @@ class StaticContent(object):
if
path
.
startswith
(
'/static/'
):
if
path
.
startswith
(
'/static/'
):
path
=
path
[
len
(
'/static/'
):]
path
=
path
[
len
(
'/static/'
):]
# Old-style asset keys start with `/`, so don't try and strip it
# in that case.
if
not
path
.
startswith
(
'/c4x'
):
path
=
path
.
lstrip
(
'/'
)
path
=
path
.
lstrip
(
'/'
)
try
:
try
:
...
...
common/lib/xmodule/xmodule/x_module.py
View file @
b24c2280
...
@@ -33,7 +33,7 @@ from xmodule.errortracker import exc_info_to_str
...
@@ -33,7 +33,7 @@ from xmodule.errortracker import exc_info_to_str
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.asides
import
AsideUsageKeyV
1
,
AsideDefinitionKeyV1
from
opaque_keys.edx.asides
import
AsideUsageKeyV
2
,
AsideDefinitionKeyV2
from
xmodule.exceptions
import
UndefinedContext
from
xmodule.exceptions
import
UndefinedContext
import
dogstats_wrapper
as
dog_stats_api
import
dogstats_wrapper
as
dog_stats_api
...
@@ -155,8 +155,8 @@ class AsideKeyGenerator(IdGenerator):
...
@@ -155,8 +155,8 @@ class AsideKeyGenerator(IdGenerator):
Returns:
Returns:
(aside_definition_id, aside_usage_id)
(aside_definition_id, aside_usage_id)
"""
"""
def_key
=
AsideDefinitionKeyV
1
(
definition_id
,
aside_type
)
def_key
=
AsideDefinitionKeyV
2
(
definition_id
,
aside_type
)
usage_key
=
AsideUsageKeyV
1
(
usage_id
,
aside_type
)
usage_key
=
AsideUsageKeyV
2
(
usage_id
,
aside_type
)
return
(
def_key
,
usage_key
)
return
(
def_key
,
usage_key
)
def
create_usage
(
self
,
def_id
):
def
create_usage
(
self
,
def_id
):
...
...
lms/djangoapps/courseware/model_data.py
View file @
b24c2280
...
@@ -33,7 +33,7 @@ from .models import (
...
@@ -33,7 +33,7 @@ from .models import (
import
logging
import
logging
from
opaque_keys.edx.keys
import
CourseKey
,
UsageKey
from
opaque_keys.edx.keys
import
CourseKey
,
UsageKey
from
opaque_keys.edx.block_types
import
BlockTypeKeyV1
from
opaque_keys.edx.block_types
import
BlockTypeKeyV1
from
opaque_keys.edx.asides
import
AsideUsageKeyV1
from
opaque_keys.edx.asides
import
AsideUsageKeyV1
,
AsideUsageKeyV2
from
contracts
import
contract
,
new_contract
from
contracts
import
contract
,
new_contract
from
django.db
import
DatabaseError
from
django.db
import
DatabaseError
...
@@ -67,6 +67,7 @@ def _all_usage_keys(descriptors, aside_types):
...
@@ -67,6 +67,7 @@ def _all_usage_keys(descriptors, aside_types):
for
aside_type
in
aside_types
:
for
aside_type
in
aside_types
:
usage_ids
.
add
(
AsideUsageKeyV1
(
descriptor
.
scope_ids
.
usage_id
,
aside_type
))
usage_ids
.
add
(
AsideUsageKeyV1
(
descriptor
.
scope_ids
.
usage_id
,
aside_type
))
usage_ids
.
add
(
AsideUsageKeyV2
(
descriptor
.
scope_ids
.
usage_id
,
aside_type
))
return
usage_ids
return
usage_ids
...
...
pavelib/tests.py
View file @
b24c2280
...
@@ -26,7 +26,6 @@ __test__ = False # do not collect
...
@@ -26,7 +26,6 @@ __test__ = False # do not collect
@cmdopts
([
@cmdopts
([
(
"system="
,
"s"
,
"System to act on"
),
(
"system="
,
"s"
,
"System to act on"
),
(
"test-id="
,
"t"
,
"Test id"
),
(
"test-id="
,
"t"
,
"Test id"
),
(
"failed"
,
"f"
,
"Run only failed tests"
),
(
"fail-fast"
,
"x"
,
"Fail suite on first failed test"
),
(
"fail-fast"
,
"x"
,
"Fail suite on first failed test"
),
(
"fasttest"
,
"a"
,
"Run without collectstatic"
),
(
"fasttest"
,
"a"
,
"Run without collectstatic"
),
make_option
(
make_option
(
...
...
requirements/edx/base.txt
View file @
b24c2280
...
@@ -48,7 +48,7 @@ edx-django-oauth2-provider==1.1.4
...
@@ -48,7 +48,7 @@ edx-django-oauth2-provider==1.1.4
edx-django-sites-extensions==2.1.1
edx-django-sites-extensions==2.1.1
edx-enterprise==0.1.0
edx-enterprise==0.1.0
edx-oauth2-provider==1.2.0
edx-oauth2-provider==1.2.0
edx-opaque-keys==0.
3.4
edx-opaque-keys==0.
4.0
edx-organizations==0.4.1
edx-organizations==0.4.1
edx-rest-api-client==1.2.1
edx-rest-api-client==1.2.1
edx-search==0.1.2
edx-search==0.1.2
...
...
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