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
6fa96cf0
Commit
6fa96cf0
authored
Jul 09, 2014
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4339 from edx/nimisha/fix-user-ids
Nimisha/fix user ids and LMS tests branch setting
parents
545cfd84
8855b12b
Show whitespace changes
Inline
Side-by-side
Showing
66 changed files
with
447 additions
and
412 deletions
+447
-412
cms/djangoapps/contentstore/management/commands/clone_course.py
+2
-1
cms/djangoapps/contentstore/management/commands/delete_course.py
+2
-2
cms/djangoapps/contentstore/management/commands/import.py
+2
-1
cms/djangoapps/contentstore/tests/test_contentstore.py
+7
-8
cms/djangoapps/contentstore/tests/test_course_listing.py
+3
-3
cms/djangoapps/contentstore/tests/test_crud.py
+3
-3
cms/djangoapps/contentstore/tests/test_export_git.py
+3
-3
cms/djangoapps/contentstore/tests/test_import.py
+10
-25
cms/djangoapps/contentstore/tests/test_import_draft_order.py
+1
-1
cms/djangoapps/contentstore/tests/test_import_pure_xblock.py
+1
-4
cms/djangoapps/contentstore/tests/test_permissions.py
+2
-15
cms/djangoapps/contentstore/tests/test_users_default_role.py
+3
-3
cms/djangoapps/contentstore/tests/test_utils.py
+2
-1
cms/djangoapps/contentstore/tests/utils.py
+7
-28
cms/djangoapps/contentstore/utils.py
+2
-6
cms/djangoapps/contentstore/views/component.py
+3
-3
cms/djangoapps/contentstore/views/course.py
+1
-0
cms/djangoapps/contentstore/views/item.py
+7
-6
cms/djangoapps/contentstore/views/tabs.py
+3
-2
cms/djangoapps/contentstore/views/tests/test_assets.py
+2
-2
cms/djangoapps/contentstore/views/tests/test_container_page.py
+22
-23
cms/djangoapps/contentstore/views/tests/test_item.py
+1
-3
cms/djangoapps/contentstore/views/tests/test_unit_page.py
+2
-2
cms/djangoapps/models/settings/course_metadata.py
+2
-2
common/djangoapps/contentserver/tests/test.py
+9
-24
common/djangoapps/external_auth/tests/test_shib.py
+35
-14
common/djangoapps/student/tests/test_course_listing.py
+1
-1
common/djangoapps/student/tests/test_login.py
+14
-6
common/djangoapps/util/testing.py
+2
-2
common/lib/xmodule/xmodule/modulestore/__init__.py
+48
-6
common/lib/xmodule/xmodule/modulestore/mixed.py
+5
-18
common/lib/xmodule/xmodule/modulestore/mongo/base.py
+2
-11
common/lib/xmodule/xmodule/modulestore/mongo/draft.py
+13
-1
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+5
-8
common/lib/xmodule/xmodule/modulestore/store_utilities.py
+0
-22
common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
+52
-6
common/lib/xmodule/xmodule/modulestore/tests/factories.py
+22
-9
common/lib/xmodule/xmodule/modulestore/tests/persistent_factories.py
+2
-2
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
+11
-11
common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
+39
-35
common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py
+2
-1
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
+29
-26
common/lib/xmodule/xmodule/modulestore/tests/test_split_w_old_mongo.py
+1
-2
common/lib/xmodule/xmodule/modulestore/xml_importer.py
+4
-1
common/lib/xmodule/xmodule/split_test_module.py
+1
-1
common/lib/xmodule/xmodule/video_module/video_module.py
+1
-1
lms/djangoapps/branding/tests.py
+6
-5
lms/djangoapps/courseware/features/annotatable.py
+1
-5
lms/djangoapps/courseware/features/common.py
+0
-4
lms/djangoapps/courseware/features/conditional.py
+1
-4
lms/djangoapps/courseware/features/gst.py
+1
-1
lms/djangoapps/courseware/management/commands/tests/test_dump_course.py
+2
-1
lms/djangoapps/courseware/tests/__init__.py
+1
-0
lms/djangoapps/courseware/tests/helpers.py
+4
-2
lms/djangoapps/courseware/tests/test_lti_integration.py
+4
-2
lms/djangoapps/courseware/tests/test_submitting_problems.py
+3
-6
lms/djangoapps/courseware/tests/test_video_handlers.py
+3
-1
lms/djangoapps/courseware/tests/test_view_authentication.py
+9
-8
lms/djangoapps/courseware/tests/tests.py
+2
-3
lms/djangoapps/dashboard/management/commands/tests/test_git_add_course.py
+2
-5
lms/djangoapps/dashboard/sysadmin.py
+1
-5
lms/djangoapps/dashboard/tests/test_sysadmin.py
+4
-1
lms/djangoapps/django_comment_client/base/tests.py
+1
-1
lms/djangoapps/instructor_task/tests/test_base.py
+4
-1
lms/djangoapps/instructor_task/tests/test_integration.py
+7
-1
lms/envs/test.py
+0
-1
No files found.
cms/djangoapps/contentstore/management/commands/clone_course.py
View file @
6fa96cf0
...
...
@@ -7,6 +7,7 @@ from student.roles import CourseInstructorRole, CourseStaffRole
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
xmodule.modulestore
import
ModuleStoreEnum
#
...
...
@@ -38,7 +39,7 @@ class Command(BaseCommand):
print
(
"Cloning course {0} to {1}"
.
format
(
source_course_id
,
dest_course_id
))
with
mstore
.
bulk_write_operations
(
dest_course_id
):
if
mstore
.
clone_course
(
source_course_id
,
dest_course_id
,
None
):
if
mstore
.
clone_course
(
source_course_id
,
dest_course_id
,
ModuleStoreEnum
.
UserID
.
mgmt_command
):
print
(
"copying User permissions..."
)
# purposely avoids auth.add_user b/c it doesn't have a caller to authorize
CourseInstructorRole
(
dest_course_id
)
.
add_users
(
...
...
cms/djangoapps/contentstore/management/commands/delete_course.py
View file @
6fa96cf0
...
...
@@ -7,7 +7,7 @@ from contentstore.utils import delete_course_and_groups
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
xmodule.modulestore
import
ModuleStoreEnum
class
Command
(
BaseCommand
):
help
=
'''Delete a MongoDB backed course'''
...
...
@@ -30,4 +30,4 @@ class Command(BaseCommand):
if
query_yes_no
(
"Deleting course {0}. Confirm?"
.
format
(
course_key
),
default
=
"no"
):
if
query_yes_no
(
"Are you sure. This action cannot be undone!"
,
default
=
"no"
):
delete_course_and_groups
(
course_key
,
commit
)
delete_course_and_groups
(
course_key
,
ModuleStoreEnum
.
UserID
.
mgmt_command
)
cms/djangoapps/contentstore/management/commands/import.py
View file @
6fa96cf0
...
...
@@ -6,6 +6,7 @@ from django.core.management.base import BaseCommand, CommandError, make_option
from
django_comment_common.utils
import
(
seed_permissions_roles
,
are_permissions_roles_seeded
)
from
xmodule.modulestore.xml_importer
import
import_from_xml
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.contentstore.django
import
contentstore
...
...
@@ -40,7 +41,7 @@ class Command(BaseCommand):
mstore
=
modulestore
()
_
,
course_items
=
import_from_xml
(
mstore
,
"**replace_user**"
,
data_dir
,
course_dirs
,
load_error_modules
=
False
,
mstore
,
ModuleStoreEnum
.
UserID
.
mgmt_command
,
data_dir
,
course_dirs
,
load_error_modules
=
False
,
static_content_store
=
contentstore
(),
verbose
=
True
,
do_import_static
=
do_import_static
,
create_new_course_if_not_present
=
True
,
...
...
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
6fa96cf0
...
...
@@ -30,7 +30,6 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
from
xmodule.modulestore.inheritance
import
own_metadata
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
,
AssetLocation
from
xmodule.modulestore.store_utilities
import
delete_course
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.xml_exporter
import
export_to_xml
from
xmodule.modulestore.xml_importer
import
import_from_xml
,
perform_xlint
...
...
@@ -632,7 +631,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
self
.
store
.
convert_to_draft
(
vertical
.
location
,
self
.
user
.
id
)
# delete the course
delete_course
(
self
.
store
,
content_store
,
course_id
,
commit
=
True
)
self
.
store
.
delete_course
(
course_id
,
self
.
user
.
id
)
# assert that there's absolutely no non-draft modules in the course
# this should also include all draft items
...
...
@@ -697,7 +696,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
self
.
assertEqual
(
on_disk
[
'course/2012_Fall'
],
own_metadata
(
course
))
# remove old course
delete_course
(
self
.
store
,
content_store
,
course_id
,
commit
=
True
)
self
.
store
.
delete_course
(
course_id
,
self
.
user
.
id
)
# reimport over old course
self
.
check_import
(
root_dir
,
content_store
,
course_id
)
...
...
@@ -909,7 +908,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
# Delete the course from module store and reimport it
delete_course
(
self
.
store
,
content_store
,
course_id
,
commit
=
True
)
self
.
store
.
delete_course
(
course_id
,
self
.
user
.
id
)
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
root_dir
,
[
'test_export_no_content_store'
],
...
...
@@ -997,7 +996,7 @@ class ContentStoreTest(ContentStoreTestCase):
test_course_data
=
self
.
assert_created_course
(
number_suffix
=
uuid4
()
.
hex
)
course_id
=
_get_course_id
(
test_course_data
)
self
.
assertTrue
(
are_permissions_roles_seeded
(
course_id
))
delete_course_and_groups
(
course_id
,
commit
=
True
)
delete_course_and_groups
(
course_id
,
self
.
user
.
id
)
# should raise an exception for checking permissions on deleted course
with
self
.
assertRaises
(
ItemNotFoundError
):
are_permissions_roles_seeded
(
course_id
)
...
...
@@ -1009,7 +1008,7 @@ class ContentStoreTest(ContentStoreTestCase):
# unseed the forums for the first course
course_id
=
_get_course_id
(
test_course_data
)
delete_course_and_groups
(
course_id
,
commit
=
True
)
delete_course_and_groups
(
course_id
,
self
.
user
.
id
)
# should raise an exception for checking permissions on deleted course
with
self
.
assertRaises
(
ItemNotFoundError
):
are_permissions_roles_seeded
(
course_id
)
...
...
@@ -1029,7 +1028,7 @@ class ContentStoreTest(ContentStoreTestCase):
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
course_id
))
self
.
assertTrue
(
self
.
user
.
roles
.
filter
(
name
=
"Student"
,
course_id
=
course_id
))
# pylint: disable=no-member
delete_course_and_groups
(
course_id
,
commit
=
True
)
delete_course_and_groups
(
course_id
,
self
.
user
.
id
)
# check that user's enrollment for this course is not deleted
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
course_id
))
# check that user has form role "Student" for this course even after deleting it
...
...
@@ -1051,7 +1050,7 @@ class ContentStoreTest(ContentStoreTestCase):
self
.
assertTrue
(
len
(
instructor_role
.
users_with_role
())
>
0
)
# Now delete course and check that user not in instructor groups of this course
delete_course_and_groups
(
course_id
,
commit
=
True
)
delete_course_and_groups
(
course_id
,
self
.
user
.
id
)
# Update our cached user since its roles have changed
self
.
user
=
User
.
objects
.
get_by_natural_key
(
self
.
user
.
natural_key
()[
0
])
...
...
cms/djangoapps/contentstore/tests/test_course_listing.py
View file @
6fa96cf0
...
...
@@ -145,7 +145,7 @@ class TestCourseListing(ModuleStoreTestCase):
self
.
assertEqual
(
courses_list
,
courses_list_by_groups
)
# now delete this course and re-add user to instructor group of this course
delete_course_and_groups
(
course_key
,
commit
=
True
)
delete_course_and_groups
(
course_key
,
self
.
user
.
id
)
CourseInstructorRole
(
course_key
)
.
add_users
(
self
.
user
)
...
...
@@ -237,7 +237,7 @@ class TestCourseListing(ModuleStoreTestCase):
self
.
assertEqual
(
len
(
courses_list_by_groups
),
2
)
# now delete first course (course_location_caps) and check that it is no longer accessible
delete_course_and_groups
(
course_location_caps
,
commit
=
True
)
delete_course_and_groups
(
course_location_caps
,
self
.
user
.
id
)
# test that get courses through iterating all courses now returns one course
courses_list
=
_accessible_courses_list
(
self
.
request
)
...
...
@@ -269,7 +269,7 @@ class TestCourseListing(ModuleStoreTestCase):
course_location
=
SlashSeparatedCourseKey
(
'testOrg'
,
'doomedCourse'
,
'RunBabyRun'
)
self
.
_create_course_with_access_groups
(
course_location
,
self
.
user
)
store
.
delete_course
(
course_location
)
store
.
delete_course
(
course_location
,
self
.
user
.
id
)
course_location
=
SlashSeparatedCourseKey
(
'testOrg'
,
'erroredCourse'
,
'RunBabyRun'
)
course
=
self
.
_create_course_with_access_groups
(
course_location
,
self
.
user
)
...
...
cms/djangoapps/contentstore/tests/test_crud.py
View file @
6fa96cf0
...
...
@@ -162,7 +162,7 @@ class TemplateTests(unittest.TestCase):
self
.
assertIsInstance
(
self
.
split_store
.
get_course
(
id_locator
),
CourseDescriptor
)
# and by guid
self
.
assertIsInstance
(
self
.
split_store
.
get_item
(
guid_locator
),
CourseDescriptor
)
self
.
split_store
.
delete_course
(
id_locator
)
self
.
split_store
.
delete_course
(
id_locator
,
ModuleStoreEnum
.
UserID
.
test
)
# test can no longer retrieve by id
self
.
assertRaises
(
ItemNotFoundError
,
self
.
split_store
.
get_course
,
id_locator
)
# but can by guid
...
...
@@ -187,11 +187,11 @@ class TemplateTests(unittest.TestCase):
)
first_problem
.
max_attempts
=
3
first_problem
.
save
()
# decache the above into the kvs
updated_problem
=
self
.
split_store
.
update_item
(
first_problem
,
'**replace_user**'
)
updated_problem
=
self
.
split_store
.
update_item
(
first_problem
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
assertIsNotNone
(
updated_problem
.
previous_version
)
self
.
assertEqual
(
updated_problem
.
previous_version
,
first_problem
.
update_version
)
self
.
assertNotEqual
(
updated_problem
.
update_version
,
first_problem
.
update_version
)
updated_loc
=
self
.
split_store
.
delete_item
(
updated_problem
.
location
,
'**replace_user**'
,
'testbot'
)
updated_loc
=
self
.
split_store
.
delete_item
(
updated_problem
.
location
,
ModuleStoreEnum
.
UserID
.
test
,
'testbot'
)
second_problem
=
persistent_factories
.
ItemFactory
.
create
(
display_name
=
'problem 2'
,
...
...
cms/djangoapps/contentstore/tests/test_export_git.py
View file @
6fa96cf0
...
...
@@ -65,7 +65,7 @@ class TestExportGit(CourseTestCase):
Test failed course export response.
"""
self
.
course_module
.
giturl
=
'foobar'
modulestore
()
.
update_item
(
self
.
course_module
,
'**replace_user**'
)
modulestore
()
.
update_item
(
self
.
course_module
,
self
.
user
.
id
)
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
self
.
assertIn
(
'Export Failed:'
,
response
.
content
)
...
...
@@ -75,7 +75,7 @@ class TestExportGit(CourseTestCase):
Regression test for making sure errors are properly stringified
"""
self
.
course_module
.
giturl
=
'foobar'
modulestore
()
.
update_item
(
self
.
course_module
,
'**replace_user**'
)
modulestore
()
.
update_item
(
self
.
course_module
,
self
.
user
.
id
)
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
self
.
assertNotIn
(
'django.utils.functional.__proxy__'
,
response
.
content
)
...
...
@@ -98,7 +98,7 @@ class TestExportGit(CourseTestCase):
self
.
populate_course
()
self
.
course_module
.
giturl
=
'file://{}'
.
format
(
bare_repo_dir
)
modulestore
()
.
update_item
(
self
.
course_module
,
'**replace_user**'
)
modulestore
()
.
update_item
(
self
.
course_module
,
self
.
user
.
id
)
response
=
self
.
client
.
get
(
'{}?action=push'
.
format
(
self
.
test_url
))
self
.
assertIn
(
'Export Succeeded'
,
response
.
content
)
cms/djangoapps/contentstore/tests/test_import.py
View file @
6fa96cf0
...
...
@@ -33,25 +33,10 @@ class ContentStoreImportTest(ModuleStoreTestCase):
NOTE: refactor using CourseFactory so they do not.
"""
def
setUp
(
self
):
uname
=
'testuser'
email
=
'test+courses@edx.org'
password
=
'foo'
# Create the use so we can log them in.
self
.
user
=
User
.
objects
.
create_user
(
uname
,
email
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self
.
user
.
is_active
=
True
# Staff has access to view all courses
self
.
user
.
is_staff
=
True
# Save the data that we've just changed to the db.
self
.
user
.
save
()
password
=
super
(
ContentStoreImportTest
,
self
)
.
setUp
()
self
.
client
=
Client
()
self
.
client
.
login
(
username
=
u
name
,
password
=
password
)
self
.
client
.
login
(
username
=
self
.
user
.
user
name
,
password
=
password
)
def
tearDown
(
self
):
contentstore
()
.
drop_database
()
...
...
@@ -66,7 +51,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
module_store
=
modulestore
()
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'test_import_course'
],
static_content_store
=
content_store
,
...
...
@@ -86,7 +71,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
module_store
,
__
,
course
=
self
.
load_test_import_course
()
__
,
course_items
=
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data'
,
[
'test_import_course_2'
],
target_course_id
=
course
.
id
,
...
...
@@ -102,7 +87,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
course_id
=
SlashSeparatedCourseKey
(
u'Юникода'
,
u'unicode_course'
,
u'échantillon'
)
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'2014_Uni'
],
target_course_id
=
course_id
...
...
@@ -148,7 +133,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
content_store
=
contentstore
()
module_store
=
modulestore
()
import_from_xml
(
module_store
,
'**replace_user**'
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
content_store
,
do_import_static
=
False
,
verbose
=
True
)
import_from_xml
(
module_store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
content_store
,
do_import_static
=
False
,
verbose
=
True
)
course
=
module_store
.
get_course
(
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'2012_Fall'
))
...
...
@@ -159,7 +144,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
def
test_no_static_link_rewrites_on_import
(
self
):
module_store
=
modulestore
()
_
,
courses
=
import_from_xml
(
module_store
,
'**replace_user**'
,
'common/test/data/'
,
[
'toy'
],
do_import_static
=
False
,
verbose
=
True
)
_
,
courses
=
import_from_xml
(
module_store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
do_import_static
=
False
,
verbose
=
True
)
course_key
=
courses
[
0
]
.
id
handouts
=
module_store
.
get_item
(
course_key
.
make_usage_key
(
'course_info'
,
'handouts'
))
...
...
@@ -178,7 +163,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
target_course_id
=
SlashSeparatedCourseKey
(
'testX'
,
'conditional_copy'
,
'copy_run'
)
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'conditional'
],
target_course_id
=
target_course_id
...
...
@@ -208,7 +193,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
target_course_id
=
SlashSeparatedCourseKey
(
'testX'
,
'peergrading_copy'
,
'copy_run'
)
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'open_ended'
],
target_course_id
=
target_course_id
...
...
@@ -227,7 +212,7 @@ class ContentStoreImportTest(ModuleStoreTestCase):
target_course_id
=
SlashSeparatedCourseKey
(
'testX'
,
'split_test_copy'
,
'copy_run'
)
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'split_test_module'
],
target_course_id
=
target_course_id
...
...
cms/djangoapps/contentstore/tests/test_import_draft_order.py
View file @
6fa96cf0
...
...
@@ -10,7 +10,7 @@ class DraftReorderTestCase(ModuleStoreTestCase):
def
test_order
(
self
):
store
=
modulestore
()
_
,
course_items
=
import_from_xml
(
store
,
'**replace_user**'
,
'common/test/data/'
,
[
'import_draft_order'
])
_
,
course_items
=
import_from_xml
(
store
,
self
.
user
.
id
,
'common/test/data/'
,
[
'import_draft_order'
])
course_key
=
course_items
[
0
]
.
id
sequential
=
store
.
get_item
(
course_key
.
make_usage_key
(
'sequential'
,
'0f4f7649b10141b0bdc9922dcf94515a'
))
verticals
=
sequential
.
children
...
...
cms/djangoapps/contentstore/tests/test_import_pure_xblock.py
View file @
6fa96cf0
...
...
@@ -28,9 +28,6 @@ class StubXBlock(XBlock):
class
XBlockImportTest
(
ModuleStoreTestCase
):
def
setUp
(
self
):
self
.
store
=
modulestore
()
@XBlock.register_temp_plugin
(
StubXBlock
)
def
test_import_public
(
self
):
self
.
_assert_import
(
...
...
@@ -62,7 +59,7 @@ class XBlockImportTest(ModuleStoreTestCase):
"""
_
,
courses
=
import_from_xml
(
self
.
store
,
'**replace_user**'
,
'common/test/data'
,
[
course_dir
]
self
.
store
,
self
.
user
.
id
,
'common/test/data'
,
[
course_dir
]
)
xblock_location
=
courses
[
0
]
.
id
.
make_usage_key
(
'stubxblock'
,
'xblock_test'
)
...
...
cms/djangoapps/contentstore/tests/test_permissions.py
View file @
6fa96cf0
...
...
@@ -24,23 +24,10 @@ class TestCourseAccess(ModuleStoreTestCase):
Create a pool of users w/o granting them any permissions
"""
super
(
TestCourseAccess
,
self
)
.
setUp
()
uname
=
'testuser'
email
=
'test+courses@edx.org'
password
=
'foo'
# Create the use so we can log them in.
self
.
user
=
User
.
objects
.
create_user
(
uname
,
email
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self
.
user
.
is_active
=
True
# Staff has access to view all courses
self
.
user
.
is_staff
=
True
self
.
user
.
save
()
user_password
=
super
(
TestCourseAccess
,
self
)
.
setUp
()
self
.
client
=
AjaxEnabledTestClient
()
self
.
client
.
login
(
username
=
uname
,
password
=
password
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
user_
password
)
# create a course via the view handler which has a different strategy for permissions than the factory
self
.
course_key
=
SlashSeparatedCourseKey
(
'myu'
,
'mydept.mycourse'
,
'myrun'
)
...
...
cms/djangoapps/contentstore/tests/test_users_default_role.py
View file @
6fa96cf0
...
...
@@ -62,7 +62,7 @@ class TestUsersDefaultRole(ModuleStoreTestCase):
# check that user has his default "Student" forum role for this course
self
.
assertTrue
(
self
.
user
.
roles
.
filter
(
name
=
"Student"
,
course_id
=
self
.
course_key
))
# pylint: disable=no-member
delete_course_and_groups
(
self
.
course_key
,
commit
=
True
)
delete_course_and_groups
(
self
.
course_key
,
self
.
user
.
id
)
# check that user's enrollment for this course is not deleted
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course_key
))
...
...
@@ -80,7 +80,7 @@ class TestUsersDefaultRole(ModuleStoreTestCase):
self
.
assertTrue
(
self
.
user
.
roles
.
filter
(
name
=
"Student"
,
course_id
=
self
.
course_key
))
# pylint: disable=no-member
# delete this course and recreate this course with same user
delete_course_and_groups
(
self
.
course_key
,
commit
=
True
)
delete_course_and_groups
(
self
.
course_key
,
self
.
user
.
id
)
resp
=
self
.
_create_course_with_given_location
(
self
.
course_key
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
...
...
@@ -98,7 +98,7 @@ class TestUsersDefaultRole(ModuleStoreTestCase):
# check that user has enrollment and his default "Student" forum role for this course
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
user
,
self
.
course_key
))
# delete this course and recreate this course with same user
delete_course_and_groups
(
self
.
course_key
,
commit
=
True
)
delete_course_and_groups
(
self
.
course_key
,
self
.
user
.
id
)
# now create same course with different name case ('uppercase')
new_course_key
=
self
.
course_key
.
replace
(
course
=
self
.
course_key
.
course
.
upper
())
...
...
cms/djangoapps/contentstore/tests/test_utils.py
View file @
6fa96cf0
...
...
@@ -9,6 +9,7 @@ from django.test import TestCase
from
django.test.utils
import
override_settings
from
contentstore
import
utils
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
,
Location
...
...
@@ -193,7 +194,7 @@ class XBlockVisibilityTestCase(TestCase):
"""Tests for xblock visibility for students."""
def
setUp
(
self
):
self
.
dummy_user
=
123
self
.
dummy_user
=
ModuleStoreEnum
.
UserID
.
test
self
.
past
=
datetime
(
1970
,
1
,
1
)
self
.
future
=
datetime
.
now
(
UTC
)
+
timedelta
(
days
=
1
)
...
...
cms/djangoapps/contentstore/tests/utils.py
View file @
6fa96cf0
...
...
@@ -6,8 +6,8 @@ Utilities for contentstore tests
import
json
import
re
from
django.contrib.auth.models
import
User
from
django.test.client
import
Client
from
django.contrib.auth.models
import
User
from
xmodule.contentstore.django
import
contentstore
from
xmodule.contentstore.content
import
StaticContent
...
...
@@ -68,53 +68,32 @@ class AjaxEnabledTestClient(Client):
class
CourseTestCase
(
ModuleStoreTestCase
):
def
setUp
(
self
):
"""
These tests need a user in the DB so that the django Test Client
can log them in
.
These tests need a user in the DB so that the django Test Client
can log them in.
The test user is created in the ModuleStoreTestCase setUp method
.
They inherit from the ModuleStoreTestCase class so that the mongodb collection
will be cleared out before each test case execution and deleted
afterwards.
"""
uname
=
'testuser'
email
=
'test+courses@edx.org'
password
=
'foo'
# Create the user so we can log them in.
self
.
user
=
User
.
objects
.
create_user
(
uname
,
email
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self
.
user
.
is_active
=
True
# Staff has access to view all courses
self
.
user
.
is_staff
=
True
self
.
user
.
save
()
user_password
=
super
(
CourseTestCase
,
self
)
.
setUp
()
self
.
client
=
AjaxEnabledTestClient
()
self
.
client
.
login
(
username
=
uname
,
password
=
password
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
user_
password
)
self
.
course
=
CourseFactory
.
create
(
org
=
'MITx'
,
number
=
'999'
,
display_name
=
'Robot Super Course'
,
)
self
.
store
=
modulestore
()
def
create_non_staff_authed_user_client
(
self
,
authenticate
=
True
):
"""
Create a non-staff user, log them in (if authenticate=True), and return the client, user to use for testing.
"""
uname
=
'teststudent'
password
=
'foo'
nonstaff
=
User
.
objects
.
create_user
(
uname
,
'test+student@edx.org'
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
nonstaff
.
is_active
=
True
nonstaff
.
is_staff
=
False
nonstaff
.
save
()
nonstaff
,
password
=
self
.
create_non_staff_user
()
client
=
Client
()
if
authenticate
:
client
.
login
(
username
=
u
name
,
password
=
password
)
client
.
login
(
username
=
nonstaff
.
user
name
,
password
=
password
)
return
client
,
nonstaff
def
populate_course
(
self
):
...
...
cms/djangoapps/contentstore/utils.py
View file @
6fa96cf0
...
...
@@ -11,12 +11,10 @@ from django.utils.translation import ugettext as _
from
django.core.urlresolvers
import
reverse
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.contentstore.django
import
contentstore
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
,
Location
from
xmodule.modulestore.store_utilities
import
delete_course
from
student.roles
import
CourseInstructorRole
,
CourseStaffRole
...
...
@@ -28,20 +26,18 @@ NOTES_PANEL = {"name": _("My Notes"), "type": "notes"}
EXTRA_TAB_PANELS
=
dict
([(
p
[
'type'
],
p
)
for
p
in
[
OPEN_ENDED_PANEL
,
NOTES_PANEL
]])
def
delete_course_and_groups
(
course_id
,
commit
=
False
):
def
delete_course_and_groups
(
course_id
,
user_id
):
"""
This deletes the courseware associated with a course_id as well as cleaning update_item
the various user table stuff (groups, permissions, etc.)
"""
module_store
=
modulestore
()
content_store
=
contentstore
()
with
module_store
.
bulk_write_operations
(
course_id
):
if
delete_course
(
module_store
,
content_store
,
course_id
,
commit
):
module_store
.
delete_course
(
course_id
,
user_id
)
print
'removing User permissions from course....'
# in the django layer, we need to remove all the user permissions groups associated with this course
if
commit
:
try
:
staff_role
=
CourseStaffRole
(
course_id
)
staff_role
.
remove_users
(
*
staff_role
.
users_with_role
())
...
...
cms/djangoapps/contentstore/views/component.py
View file @
6fa96cf0
...
...
@@ -449,8 +449,8 @@ def component_handler(request, usage_key_string, handler, suffix=''):
log
.
info
(
"XBlock
%
s attempted to access missing handler
%
r"
,
descriptor
,
handler
,
exc_info
=
True
)
raise
Http404
# unintentional update to handle any side effects of handle call
; so, request user didn't author
#
the change
modulestore
()
.
update_item
(
descriptor
,
None
)
# unintentional update to handle any side effects of handle call
#
could potentially be updating actual course data or simply caching its values
modulestore
()
.
update_item
(
descriptor
,
request
.
user
.
id
)
return
webob_to_django_response
(
resp
)
cms/djangoapps/contentstore/views/course.py
View file @
6fa96cf0
...
...
@@ -337,6 +337,7 @@ def create_new_course(request):
new_course
=
modulestore
()
.
create_course
(
course_key
.
org
,
course_key
.
offering
,
request
.
user
.
id
,
fields
=
fields
,
)
...
...
cms/djangoapps/contentstore/views/item.py
View file @
6fa96cf0
...
...
@@ -140,8 +140,8 @@ def xblock_handler(request, usage_key_string):
dest_usage_key
=
_duplicate_item
(
parent_usage_key
,
duplicate_source_usage_key
,
request
.
json
.
get
(
'display_name'
),
request
.
user
,
request
.
json
.
get
(
'display_name'
),
)
return
JsonResponse
({
"locator"
:
unicode
(
dest_usage_key
),
"courseKey"
:
unicode
(
dest_usage_key
.
course_key
)})
...
...
@@ -193,8 +193,7 @@ def xblock_view_handler(request, usage_key_string, view_name):
log
.
debug
(
"unable to render studio_view for
%
r"
,
xblock
,
exc_info
=
True
)
fragment
=
Fragment
(
render_to_string
(
'html_error.html'
,
{
'message'
:
str
(
exc
)}))
# change not authored by requestor but by xblocks.
store
.
update_item
(
xblock
,
None
)
store
.
update_item
(
xblock
,
request
.
user
.
id
)
elif
view_name
in
(
unit_views
+
container_views
):
is_container_view
=
(
view_name
in
container_views
)
...
...
@@ -432,7 +431,7 @@ def _create_item(request):
return
JsonResponse
({
"locator"
:
unicode
(
created_block
.
location
),
"courseKey"
:
unicode
(
created_block
.
location
.
course_key
)})
def
_duplicate_item
(
parent_usage_key
,
duplicate_source_usage_key
,
display_name
=
None
,
user
=
None
):
def
_duplicate_item
(
parent_usage_key
,
duplicate_source_usage_key
,
user
,
display_name
=
None
):
"""
Duplicate an existing xblock as a child of the supplied parent_usage_key.
"""
...
...
@@ -454,6 +453,8 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, display_name=N
dest_module
=
store
.
create_and_save_xmodule
(
dest_usage_key
,
user
.
id
,
definition_data
=
source_item
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
),
metadata
=
duplicate_metadata
,
...
...
@@ -467,7 +468,7 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, display_name=N
for
child
in
source_item
.
children
:
dupe
=
_duplicate_item
(
dest_module
.
location
,
child
,
user
=
user
)
dest_module
.
children
.
append
(
dupe
)
store
.
update_item
(
dest_module
,
user
.
id
if
user
else
None
)
store
.
update_item
(
dest_module
,
user
.
id
)
if
not
'detached'
in
source_item
.
runtime
.
load_block_type
(
category
)
.
_class_tags
:
parent
=
store
.
get_item
(
parent_usage_key
)
...
...
@@ -478,7 +479,7 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, display_name=N
parent
.
children
.
insert
(
source_index
+
1
,
dest_module
.
location
)
else
:
parent
.
children
.
append
(
dest_module
.
location
)
store
.
update_item
(
parent
,
user
.
id
if
user
else
None
)
store
.
update_item
(
parent
,
user
.
id
)
return
dest_module
.
location
...
...
cms/djangoapps/contentstore/views/tabs.py
View file @
6fa96cf0
...
...
@@ -12,6 +12,7 @@ from django_future.csrf import ensure_csrf_cookie
from
django.views.decorators.http
import
require_http_methods
from
edxmako.shortcuts
import
render_to_response
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.tabs
import
CourseTabList
,
StaticTab
,
CourseTab
,
InvalidTabsException
from
opaque_keys.edx.keys
import
CourseKey
,
UsageKey
...
...
@@ -192,7 +193,7 @@ def primitive_delete(course, num):
# Note for future implementations: if you delete a static_tab, then Chris Dodge
# points out that there's other stuff to delete beyond this element.
# This code happens to not delete static_tab so it doesn't come up.
modulestore
()
.
update_item
(
course
,
'**replace_user**'
)
modulestore
()
.
update_item
(
course
,
ModuleStoreEnum
.
UserID
.
primitive_command
)
def
primitive_insert
(
course
,
num
,
tab_type
,
name
):
...
...
@@ -201,5 +202,5 @@ def primitive_insert(course, num, tab_type, name):
new_tab
=
CourseTab
.
from_json
({
u'type'
:
unicode
(
tab_type
),
u'name'
:
unicode
(
name
)})
tabs
=
course
.
tabs
tabs
.
insert
(
num
,
new_tab
)
modulestore
()
.
update_item
(
course
,
'**replace_user**'
)
modulestore
()
.
update_item
(
course
,
ModuleStoreEnum
.
UserID
.
primitive_command
)
cms/djangoapps/contentstore/views/tests/test_assets.py
View file @
6fa96cf0
...
...
@@ -51,7 +51,7 @@ class BasicAssetsTestCase(AssetsTestCase):
module_store
=
modulestore
()
_
,
course_items
=
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
contentstore
(),
...
...
@@ -195,7 +195,7 @@ class LockAssetTestCase(AssetsTestCase):
module_store
=
modulestore
()
_
,
course_items
=
import_from_xml
(
module_store
,
'**replace_user**'
,
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
contentstore
(),
...
...
cms/djangoapps/contentstore/views/tests/test_container_page.py
View file @
6fa96cf0
...
...
@@ -20,16 +20,11 @@ class ContainerPageTestCase(StudioPageTestCase):
def
setUp
(
self
):
super
(
ContainerPageTestCase
,
self
)
.
setUp
()
self
.
vertical
=
ItemFactory
.
create
(
parent_location
=
self
.
sequential
.
location
,
category
=
'vertical'
,
display_name
=
'Unit'
)
self
.
html
=
ItemFactory
.
create
(
parent_location
=
self
.
vertical
.
location
,
category
=
"html"
,
display_name
=
"HTML"
)
self
.
child_container
=
ItemFactory
.
create
(
parent_location
=
self
.
vertical
.
location
,
category
=
'split_test'
,
display_name
=
'Split Test'
)
self
.
child_vertical
=
ItemFactory
.
create
(
parent_location
=
self
.
child_container
.
location
,
category
=
'vertical'
,
display_name
=
'Child Vertical'
)
self
.
video
=
ItemFactory
.
create
(
parent_location
=
self
.
child_vertical
.
location
,
category
=
"video"
,
display_name
=
"My Video"
)
self
.
vertical
=
self
.
_create_item
(
self
.
sequential
.
location
,
'vertical'
,
'Unit'
)
self
.
html
=
self
.
_create_item
(
self
.
vertical
.
location
,
"html"
,
"HTML"
)
self
.
child_container
=
self
.
_create_item
(
self
.
vertical
.
location
,
'split_test'
,
'Split Test'
)
self
.
child_vertical
=
self
.
_create_item
(
self
.
child_container
.
location
,
'vertical'
,
'Child Vertical'
)
self
.
video
=
self
.
_create_item
(
self
.
child_vertical
.
location
,
"video"
,
"My Video"
)
self
.
store
=
modulestore
()
def
test_container_html
(
self
):
...
...
@@ -51,14 +46,8 @@ class ContainerPageTestCase(StudioPageTestCase):
Create the scenario of an xblock with children (non-vertical) on the container page.
This should create a container page that is a child of another container page.
"""
draft_container
=
ItemFactory
.
create
(
parent_location
=
self
.
child_container
.
location
,
category
=
"wrapper"
,
display_name
=
"Wrapper"
)
ItemFactory
.
create
(
parent_location
=
draft_container
.
location
,
category
=
"html"
,
display_name
=
"Child HTML"
)
draft_container
=
self
.
_create_item
(
self
.
child_container
.
location
,
"wrapper"
,
"Wrapper"
)
self
.
_create_item
(
draft_container
.
location
,
"html"
,
"Child HTML"
)
def
test_container_html
(
xblock
):
self
.
_test_html_content
(
...
...
@@ -135,9 +124,8 @@ class ContainerPageTestCase(StudioPageTestCase):
"""
Verify that a public container rendered as a child of the container page returns the expected HTML.
"""
empty_child_container
=
ItemFactory
.
create
(
parent_location
=
self
.
vertical
.
location
,
category
=
'split_test'
,
display_name
=
'Split Test'
)
published_empty_child_container
=
self
.
store
.
publish
(
empty_child_container
.
location
,
'**replace_user**'
)
empty_child_container
=
self
.
_create_item
(
self
.
vertical
.
location
,
'split_test'
,
'Split Test'
)
published_empty_child_container
=
self
.
store
.
publish
(
empty_child_container
.
location
,
self
.
user
.
id
)
self
.
validate_preview_html
(
published_empty_child_container
,
self
.
reorderable_child_view
,
can_reorder
=
False
,
can_edit
=
False
,
can_add
=
False
)
...
...
@@ -145,7 +133,18 @@ class ContainerPageTestCase(StudioPageTestCase):
"""
Verify that a draft container rendered as a child of the container page returns the expected HTML.
"""
empty_child_container
=
ItemFactory
.
create
(
parent_location
=
self
.
vertical
.
location
,
category
=
'split_test'
,
display_name
=
'Split Test'
)
empty_child_container
=
self
.
_create_item
(
self
.
vertical
.
location
,
'split_test'
,
'Split Test'
)
self
.
validate_preview_html
(
empty_child_container
,
self
.
reorderable_child_view
,
can_reorder
=
True
,
can_edit
=
True
,
can_add
=
False
)
def
_create_item
(
self
,
parent_location
,
category
,
display_name
,
**
kwargs
):
"""
creates an item in the module store, without publishing it.
"""
return
ItemFactory
.
create
(
parent_location
=
parent_location
,
category
=
category
,
display_name
=
display_name
,
publish_item
=
False
,
**
kwargs
)
cms/djangoapps/contentstore/views/tests/test_item.py
View file @
6fa96cf0
...
...
@@ -25,10 +25,9 @@ from contentstore.tests.utils import CourseTestCase
from
student.tests.factories
import
UserFactory
from
xmodule.capa_module
import
CapaDescriptor
from
xmodule.modulestore
import
PublishState
from
xmodule.modulestore.django
import
modulestore
from
xmodule.x_module
import
STUDIO_VIEW
,
STUDENT_VIEW
from
xblock.exceptions
import
NoSuchHandlerError
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.keys
import
UsageKey
,
CourseKey
from
opaque_keys.edx.locations
import
Location
from
xmodule.partitions.partitions
import
Group
,
UserPartition
...
...
@@ -40,7 +39,6 @@ class ItemTest(CourseTestCase):
self
.
course_key
=
self
.
course
.
id
self
.
usage_key
=
self
.
course
.
location
self
.
store
=
modulestore
()
def
get_item_from_modulestore
(
self
,
usage_key
,
verify_is_draft
=
False
):
"""
...
...
cms/djangoapps/contentstore/views/tests/test_unit_page.py
View file @
6fa96cf0
...
...
@@ -40,7 +40,7 @@ class UnitPageTestCase(StudioPageTestCase):
"""
Verify that a public xblock's preview returns the expected HTML.
"""
published_video
=
self
.
store
.
publish
(
self
.
video
.
location
,
'**replace_user**'
)
published_video
=
self
.
store
.
publish
(
self
.
video
.
location
,
self
.
user
.
id
)
self
.
validate_preview_html
(
self
.
video
,
STUDENT_VIEW
,
can_edit
=
True
,
can_reorder
=
True
,
can_add
=
False
)
...
...
@@ -60,7 +60,7 @@ class UnitPageTestCase(StudioPageTestCase):
category
=
'split_test'
,
display_name
=
'Split Test'
)
ItemFactory
.
create
(
parent_location
=
child_container
.
location
,
category
=
'html'
,
display_name
=
'grandchild'
)
published_child_container
=
self
.
store
.
publish
(
child_container
.
location
,
'**replace_user**'
)
published_child_container
=
self
.
store
.
publish
(
child_container
.
location
,
self
.
user
.
id
)
self
.
validate_preview_html
(
published_child_container
,
STUDENT_VIEW
,
can_reorder
=
True
,
can_edit
=
True
,
can_add
=
False
)
...
...
cms/djangoapps/models/settings/course_metadata.py
View file @
6fa96cf0
...
...
@@ -53,7 +53,7 @@ class CourseMetadata(object):
return
result
@classmethod
def
update_from_json
(
cls
,
descriptor
,
jsondict
,
filter_tabs
=
True
,
user
=
Non
e
):
def
update_from_json
(
cls
,
descriptor
,
jsondict
,
user
,
filter_tabs
=
Tru
e
):
"""
Decode the json into CourseMetadata and save any changed attrs to the db.
...
...
@@ -84,6 +84,6 @@ class CourseMetadata(object):
setattr
(
descriptor
,
key
,
value
)
if
len
(
key_values
)
>
0
:
modulestore
()
.
update_item
(
descriptor
,
user
.
id
if
user
else
None
)
modulestore
()
.
update_item
(
descriptor
,
user
.
id
)
return
cls
.
fetch
(
descriptor
)
common/djangoapps/contentserver/tests/test.py
View file @
6fa96cf0
...
...
@@ -5,7 +5,6 @@ import copy
import
logging
from
uuid
import
uuid4
from
django.contrib.auth.models
import
User
from
django.conf
import
settings
from
django.test.client
import
Client
from
django.test.utils
import
override_settings
...
...
@@ -34,12 +33,16 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
"""
Create user and login.
"""
self
.
staff_pwd
=
super
(
ContentStoreToyCourseTest
,
self
)
.
setUp
()
self
.
staff_usr
=
self
.
user
self
.
non_staff_usr
,
self
.
non_staff_pwd
=
self
.
create_non_staff_user
()
self
.
client
=
Client
()
self
.
contentstore
=
contentstore
()
self
.
course_key
=
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'2012_Fall'
)
import_from_xml
(
modulestore
(),
'**replace_user**'
,
'common/test/data/'
,
[
'toy'
],
import_from_xml
(
modulestore
(),
self
.
user
.
id
,
'common/test/data/'
,
[
'toy'
],
static_content_store
=
self
.
contentstore
,
verbose
=
True
)
# A locked asset
...
...
@@ -52,24 +55,6 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
self
.
contentstore
.
set_attr
(
self
.
locked_asset
,
'locked'
,
True
)
# Create user
self
.
usr
=
'testuser'
self
.
pwd
=
'foo'
email
=
'test+courses@edx.org'
self
.
user
=
User
.
objects
.
create_user
(
self
.
usr
,
email
,
self
.
pwd
)
self
.
user
.
is_active
=
True
self
.
user
.
save
()
# Create staff user
self
.
staff_usr
=
'stafftestuser'
self
.
staff_pwd
=
'foo'
staff_email
=
'stafftest+courses@edx.org'
self
.
staff_user
=
User
.
objects
.
create_user
(
self
.
staff_usr
,
staff_email
,
self
.
staff_pwd
)
self
.
staff_user
.
is_active
=
True
self
.
staff_user
.
is_staff
=
True
self
.
staff_user
.
save
()
def
tearDown
(
self
):
contentstore
()
.
drop_database
()
...
...
@@ -97,7 +82,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
Test that locked assets behave appropriately in case user is logged in
in but not registered for the course.
"""
self
.
client
.
login
(
username
=
self
.
usr
,
password
=
self
.
pwd
)
self
.
client
.
login
(
username
=
self
.
non_staff_usr
,
password
=
self
.
non_staff_
pwd
)
resp
=
self
.
client
.
get
(
self
.
url_locked
)
self
.
assertEqual
(
resp
.
status_code
,
403
)
# pylint: disable=E1103
...
...
@@ -106,10 +91,10 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
Test that locked assets behave appropriately in case user is logged in
and registered for the course.
"""
CourseEnrollment
.
enroll
(
self
.
use
r
,
self
.
course_key
)
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
use
r
,
self
.
course_key
))
CourseEnrollment
.
enroll
(
self
.
non_staff_us
r
,
self
.
course_key
)
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
non_staff_us
r
,
self
.
course_key
))
self
.
client
.
login
(
username
=
self
.
usr
,
password
=
self
.
pwd
)
self
.
client
.
login
(
username
=
self
.
non_staff_usr
,
password
=
self
.
non_staff_
pwd
)
resp
=
self
.
client
.
get
(
self
.
url_locked
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# pylint: disable=E1103
...
...
common/djangoapps/external_auth/tests/test_shib.py
View file @
6fa96cf0
...
...
@@ -17,8 +17,8 @@ from django.utils.importlib import import_module
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
,
mixed_store_config
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
ModuleStoreEnum
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
external_auth.models
import
ExternalAuthMap
...
...
@@ -80,7 +80,8 @@ class ShibSPTest(ModuleStoreTestCase):
request_factory
=
RequestFactory
()
def
setUp
(
self
):
self
.
store
=
modulestore
()
super
(
ShibSPTest
,
self
)
.
setUp
(
create_user
=
False
)
self
.
test_user_id
=
ModuleStoreEnum
.
UserID
.
test
@unittest.skipUnless
(
settings
.
FEATURES
.
get
(
'AUTH_USE_SHIB'
),
"AUTH_USE_SHIB not set"
)
def
test_exception_shib_login
(
self
):
...
...
@@ -377,13 +378,21 @@ class ShibSPTest(ModuleStoreTestCase):
"""
Tests that the correct course specific login and registration urls work for shib
"""
course
=
CourseFactory
.
create
(
org
=
'MITx'
,
number
=
'999'
,
display_name
=
'Robot Super Course'
)
course
=
CourseFactory
.
create
(
org
=
'MITx'
,
number
=
'999'
,
display_name
=
'Robot Super Course'
,
user_id
=
self
.
test_user_id
,
)
# Test for cases where course is found
for
domain
in
[
""
,
"shib:https://idp.stanford.edu/"
]:
# set domains
# temporarily set the branch to draft-preferred so we can update the course
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
course
.
id
):
course
.
enrollment_domain
=
domain
self
.
store
.
update_item
(
course
,
'**replace_user**'
)
self
.
store
.
update_item
(
course
,
self
.
test_user_id
)
# setting location to test that GET params get passed through
login_request
=
self
.
request_factory
.
get
(
'/course_specific_login/MITx/999/Robot_Super_Course'
+
...
...
@@ -450,13 +459,21 @@ class ShibSPTest(ModuleStoreTestCase):
"""
# create 2 course, one with limited enrollment one without
shib_course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'123'
,
display_name
=
'Shib Only'
)
shib_course
.
enrollment_domain
=
'shib:https://idp.stanford.edu/'
self
.
store
.
update_item
(
shib_course
,
'**replace_user**'
)
open_enroll_course
=
CourseFactory
.
create
(
org
=
'MITx'
,
number
=
'999'
,
display_name
=
'Robot Super Course'
)
open_enroll_course
.
enrollment_domain
=
''
self
.
store
.
update_item
(
open_enroll_course
,
'**replace_user**'
)
shib_course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'123'
,
display_name
=
'Shib Only'
,
enrollment_domain
=
'shib:https://idp.stanford.edu/'
,
user_id
=
self
.
test_user_id
,
)
open_enroll_course
=
CourseFactory
.
create
(
org
=
'MITx'
,
number
=
'999'
,
display_name
=
'Robot Super Course'
,
enrollment_domain
=
''
,
user_id
=
self
.
test_user_id
,
)
# create 3 kinds of students, external_auth matching shib_course, external_auth not matching, no external auth
shib_student
=
UserFactory
.
create
()
...
...
@@ -520,9 +537,13 @@ class ShibSPTest(ModuleStoreTestCase):
student
.
save
()
extauth
.
save
()
course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'123'
,
display_name
=
'Shib Only'
)
course
.
enrollment_domain
=
'shib:https://idp.stanford.edu/'
self
.
store
.
update_item
(
course
,
'**replace_user**'
)
course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'123'
,
display_name
=
'Shib Only'
,
enrollment_domain
=
'shib:https://idp.stanford.edu/'
,
user_id
=
self
.
test_user_id
,
)
# use django test client for sessions and url processing
# no enrollment before trying
...
...
common/djangoapps/student/tests/test_course_listing.py
View file @
6fa96cf0
...
...
@@ -97,7 +97,7 @@ class TestCourseListing(ModuleStoreTestCase):
course_location
=
SlashSeparatedCourseKey
(
'testOrg'
,
'doomedCourse'
,
'RunBabyRun'
)
self
.
_create_course_with_access_groups
(
course_location
)
mongo_store
.
delete_course
(
course_location
)
mongo_store
.
delete_course
(
course_location
,
ModuleStoreEnum
.
UserID
.
test
)
course_location
=
SlashSeparatedCourseKey
(
'testOrg'
,
'erroredCourse'
,
'RunBabyRun'
)
course
=
self
.
_create_course_with_access_groups
(
course_location
)
...
...
common/djangoapps/student/tests/test_login.py
View file @
6fa96cf0
...
...
@@ -17,7 +17,6 @@ from student.views import _parse_course_id_from_string, _get_course_enrollment_d
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
,
mixed_store_config
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.django
import
modulestore
from
external_auth.models
import
ExternalAuthMap
...
...
@@ -346,11 +345,20 @@ class ExternalAuthShibTest(ModuleStoreTestCase):
Tests how login_user() interacts with ExternalAuth, in particular Shib
"""
def
setUp
(
self
):
self
.
store
=
modulestore
()
self
.
course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'456'
,
display_name
=
'NO SHIB'
)
self
.
shib_course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'123'
,
display_name
=
'Shib Only'
)
self
.
shib_course
.
enrollment_domain
=
'shib:https://idp.stanford.edu/'
self
.
store
.
update_item
(
self
.
shib_course
,
'**replace_user**'
)
super
(
ExternalAuthShibTest
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'456'
,
display_name
=
'NO SHIB'
,
user_id
=
self
.
user
.
id
,
)
self
.
shib_course
=
CourseFactory
.
create
(
org
=
'Stanford'
,
number
=
'123'
,
display_name
=
'Shib Only'
,
enrollment_domain
=
'shib:https://idp.stanford.edu/'
,
user_id
=
self
.
user
.
id
,
)
self
.
user_w_map
=
UserFactory
.
create
(
email
=
'withmap@stanford.edu'
)
self
.
extauth
=
ExternalAuthMap
(
external_id
=
'withmap@stanford.edu'
,
external_email
=
'withmap@stanford.edu'
,
...
...
common/djangoapps/util/testing.py
View file @
6fa96cf0
...
...
@@ -30,8 +30,8 @@ class UrlResetMixin(object):
# Resolve a URL so that the new urlconf gets loaded
resolve
(
'/'
)
def
setUp
(
self
):
def
setUp
(
self
,
**
kwargs
):
"""Reset django default urlconf before tests and after tests"""
super
(
UrlResetMixin
,
self
)
.
setUp
()
super
(
UrlResetMixin
,
self
)
.
setUp
(
**
kwargs
)
self
.
_reset_urls
()
self
.
addCleanup
(
self
.
_reset_urls
)
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
6fa96cf0
...
...
@@ -72,6 +72,21 @@ class ModuleStoreEnum(object):
draft
=
'draft-branch'
published
=
'published-branch'
class
UserID
(
object
):
"""
Values for user ID defaults
"""
# Note: we use negative values here to (try to) not collide
# with user identifiers provided by actual user services.
# user ID to use for all management commands
mgmt_command
=
-
1
# user ID to use for primitive commands
primitive_command
=
-
2
# user ID to use for tests that do not have a django user available
test
=
-
3
class
PublishState
(
object
):
"""
...
...
@@ -270,6 +285,18 @@ class ModuleStoreRead(object):
"""
pass
@abstractmethod
def
compute_publish_state
(
self
,
xblock
):
"""
Returns whether this xblock is draft, public, or private.
Returns:
PublishState.draft - content is in the process of being edited, but still has a previous
version deployed to LMS
PublishState.public - content is locked and deployed to LMS
PublishState.private - content is editable and not deployed to LMS
"""
pass
class
ModuleStoreWrite
(
ModuleStoreRead
):
"""
...
...
@@ -280,7 +307,7 @@ class ModuleStoreWrite(ModuleStoreRead):
__metaclass__
=
ABCMeta
@abstractmethod
def
update_item
(
self
,
xblock
,
user_id
=
None
,
allow_not_found
=
False
,
force
=
False
):
def
update_item
(
self
,
xblock
,
user_id
,
allow_not_found
=
False
,
force
=
False
):
"""
Update the given xblock's persisted repr. Pass the user's unique id which the persistent store
should save with the update if it has that ability.
...
...
@@ -296,7 +323,7 @@ class ModuleStoreWrite(ModuleStoreRead):
pass
@abstractmethod
def
delete_item
(
self
,
location
,
user_id
=
None
,
**
kwargs
):
def
delete_item
(
self
,
location
,
user_id
,
**
kwargs
):
"""
Delete an item and its subtree from persistence. Remove the item from any parents (Note, does not
affect parents from other branches or logical branches; thus, in old mongo, deleting something
...
...
@@ -315,7 +342,7 @@ class ModuleStoreWrite(ModuleStoreRead):
pass
@abstractmethod
def
create_course
(
self
,
org
,
offering
,
user_id
=
None
,
fields
=
None
,
**
kwargs
):
def
create_course
(
self
,
org
,
offering
,
user_id
,
fields
=
None
,
**
kwargs
):
"""
Creates and returns the course.
...
...
@@ -348,7 +375,7 @@ class ModuleStoreWrite(ModuleStoreRead):
pass
@abstractmethod
def
delete_course
(
self
,
course_key
,
user_id
=
None
):
def
delete_course
(
self
,
course_key
,
user_id
):
"""
Deletes the course. It may be a soft or hard delete. It may or may not remove the xblock definitions
depending on the persistence layer and how tightly bound the xblocks are to the course.
...
...
@@ -441,6 +468,12 @@ class ModuleStoreReadBase(ModuleStoreRead):
None
)
def
compute_publish_state
(
self
,
xblock
):
"""
Returns PublishState.public since this is a read-only store.
"""
return
PublishState
.
public
def
heartbeat
(
self
):
"""
Is this modulestore ready?
...
...
@@ -499,7 +532,7 @@ class ModuleStoreWriteBase(ModuleStoreReadBase, ModuleStoreWrite):
result
[
field
.
scope
][
field_name
]
=
value
return
result
def
update_item
(
self
,
xblock
,
user_id
=
None
,
allow_not_found
=
False
,
force
=
False
):
def
update_item
(
self
,
xblock
,
user_id
,
allow_not_found
=
False
,
force
=
False
):
"""
Update the given xblock's persisted repr. Pass the user's unique id which the persistent store
should save with the update if it has that ability.
...
...
@@ -514,7 +547,7 @@ class ModuleStoreWriteBase(ModuleStoreReadBase, ModuleStoreWrite):
"""
raise
NotImplementedError
def
delete_item
(
self
,
location
,
user_id
=
None
,
force
=
False
):
def
delete_item
(
self
,
location
,
user_id
,
force
=
False
):
"""
Delete an item from persistence. Pass the user's unique id which the persistent store
should save with the update if it has that ability.
...
...
@@ -553,6 +586,15 @@ class ModuleStoreWriteBase(ModuleStoreReadBase, ModuleStoreWrite):
super
(
ModuleStoreWriteBase
,
self
)
.
clone_course
(
source_course_id
,
dest_course_id
,
user_id
)
return
dest_course_id
def
delete_course
(
self
,
course_key
,
user_id
):
"""
This base method just deletes the assets. The lower level impls must do the actual deleting of
content.
"""
# delete the assets
self
.
contentstore
.
delete_all_course_assets
(
course_key
)
super
(
ModuleStoreWriteBase
,
self
)
.
delete_course
(
course_key
,
user_id
)
@contextmanager
def
bulk_write_operations
(
self
,
course_id
):
"""
...
...
common/lib/xmodule/xmodule/modulestore/mixed.py
View file @
6fa96cf0
...
...
@@ -229,16 +229,13 @@ class MixedModuleStore(ModuleStoreWriteBase):
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
return
store
.
has_course
(
course_id
,
ignore_case
)
def
delete_course
(
self
,
course_key
,
user_id
=
None
):
def
delete_course
(
self
,
course_key
,
user_id
):
"""
See xmodule.modulestore.__init__.ModuleStoreWrite.delete_course
"""
assert
(
isinstance
(
course_key
,
CourseKey
))
store
=
self
.
_get_modulestore_for_courseid
(
course_key
)
if
hasattr
(
store
,
'delete_course'
):
return
store
.
delete_course
(
course_key
,
user_id
)
else
:
raise
NotImplementedError
(
u"Cannot delete a course on store {}"
.
format
(
store
))
def
get_parent_location
(
self
,
location
,
**
kwargs
):
"""
...
...
@@ -276,7 +273,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
errs
.
update
(
store
.
get_errored_courses
())
return
errs
def
create_course
(
self
,
org
,
offering
,
user_id
=
None
,
fields
=
None
,
**
kwargs
):
def
create_course
(
self
,
org
,
offering
,
user_id
,
fields
=
None
,
**
kwargs
):
"""
Creates and returns the course.
...
...
@@ -290,10 +287,6 @@ class MixedModuleStore(ModuleStoreWriteBase):
Returns: a CourseDescriptor
"""
store
=
self
.
_get_modulestore_for_courseid
(
None
)
if
not
hasattr
(
store
,
'create_course'
):
raise
NotImplementedError
(
u"Cannot create a course on store {}"
.
format
(
store
))
return
store
.
create_course
(
org
,
offering
,
user_id
,
fields
,
**
kwargs
)
def
clone_course
(
self
,
source_course_id
,
dest_course_id
,
user_id
):
...
...
@@ -326,7 +319,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
source_course_id
,
user_id
,
dest_course_id
.
org
,
dest_course_id
.
offering
)
def
create_item
(
self
,
course_or_parent_loc
,
category
,
user_id
=
None
,
**
kwargs
):
def
create_item
(
self
,
course_or_parent_loc
,
category
,
user_id
,
**
kwargs
):
"""
Create and return the item. If parent_loc is a specific location v a course id,
it installs the new item as a child of the parent (if the parent_loc is a specific
...
...
@@ -353,7 +346,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
if
parent_loc
is
not
None
and
not
'detached'
in
xblock
.
_class_tags
:
parent
=
store
.
get_item
(
parent_loc
)
parent
.
children
.
append
(
location
)
store
.
update_item
(
parent
)
store
.
update_item
(
parent
,
user_id
)
elif
isinstance
(
store
,
SplitMongoModuleStore
):
if
not
isinstance
(
course_or_parent_loc
,
(
CourseLocator
,
BlockUsageLocator
)):
raise
ValueError
(
u"Cannot create a child of {} in split. Wrong repr."
.
format
(
course_or_parent_loc
))
...
...
@@ -378,7 +371,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
store
=
self
.
_verify_modulestore_support
(
xblock
.
location
,
'update_item'
)
return
store
.
update_item
(
xblock
,
user_id
,
allow_not_found
)
def
delete_item
(
self
,
location
,
user_id
=
None
,
**
kwargs
):
def
delete_item
(
self
,
location
,
user_id
,
**
kwargs
):
"""
Delete the given item from persistence. kwargs allow modulestore specific parameters.
"""
...
...
@@ -456,13 +449,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
"""
course_id
=
xblock
.
scope_ids
.
usage_id
.
course_key
store
=
self
.
_get_modulestore_for_courseid
(
course_id
)
if
hasattr
(
store
,
'compute_publish_state'
):
return
store
.
compute_publish_state
(
xblock
)
elif
hasattr
(
store
,
'publish'
):
raise
NotImplementedError
(
u"Cannot compute_publish_state on store {}"
.
format
(
store
))
else
:
# read-only store; so, everything's public
return
PublishState
.
public
def
publish
(
self
,
location
,
user_id
):
"""
...
...
common/lib/xmodule/xmodule/modulestore/mongo/base.py
View file @
6fa96cf0
...
...
@@ -841,7 +841,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
modules
=
self
.
_load_items
(
course_id
,
list
(
items
))
return
modules
def
create_course
(
self
,
org
,
offering
,
user_id
=
None
,
fields
=
None
,
**
kwargs
):
def
create_course
(
self
,
org
,
offering
,
user_id
,
fields
=
None
,
**
kwargs
):
"""
Creates and returns the course.
...
...
@@ -892,15 +892,6 @@ class MongoModuleStore(ModuleStoreWriteBase):
return
course
def
delete_course
(
self
,
course_key
,
user_id
=
None
):
"""
The impl removes all of the db records for the course.
:param course_key:
:param user_id:
"""
course_query
=
self
.
_course_key_to_son
(
course_key
)
self
.
collection
.
remove
(
course_query
,
multi
=
True
)
def
create_xmodule
(
self
,
location
,
definition_data
=
None
,
metadata
=
None
,
runtime
=
None
,
fields
=
{}):
"""
Create the new xmodule but don't save it. Returns the new module.
...
...
@@ -992,7 +983,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
self
.
_update_single_item
(
parent
,
update
)
self
.
_update_ancestors
(
parent
,
update
)
def
update_item
(
self
,
xblock
,
user_id
=
None
,
allow_not_found
=
False
,
force
=
False
,
isPublish
=
False
,
def
update_item
(
self
,
xblock
,
user_id
,
allow_not_found
=
False
,
force
=
False
,
isPublish
=
False
,
is_publish_root
=
True
):
"""
Update the persisted version of xblock to reflect its current values.
...
...
common/lib/xmodule/xmodule/modulestore/mongo/draft.py
View file @
6fa96cf0
...
...
@@ -144,6 +144,18 @@ class DraftModuleStore(MongoModuleStore):
del
key
[
'_id.revision'
]
return
self
.
collection
.
find
(
key
)
.
count
()
>
0
def
delete_course
(
self
,
course_key
,
user_id
):
"""
:param course_key: which course to delete
:param user_id: id of the user deleting the course
"""
# delete the assets
super
(
DraftModuleStore
,
self
)
.
delete_course
(
course_key
,
user_id
)
# delete all of the db records for the course
course_query
=
self
.
_course_key_to_son
(
course_key
)
self
.
collection
.
remove
(
course_query
,
multi
=
True
)
def
clone_course
(
self
,
source_course_id
,
dest_course_id
,
user_id
):
"""
Only called if cloning within this store or if env doesn't set up mixed.
...
...
@@ -419,7 +431,7 @@ class DraftModuleStore(MongoModuleStore):
# get_item will wrap_draft so don't call it here (otherwise, it would override the is_draft attribute)
return
self
.
get_item
(
location
)
def
update_item
(
self
,
xblock
,
user_id
=
None
,
allow_not_found
=
False
,
force
=
False
,
isPublish
=
False
):
def
update_item
(
self
,
xblock
,
user_id
,
allow_not_found
=
False
,
force
=
False
,
isPublish
=
False
):
"""
See superclass doc.
In addition to the superclass's behavior, this method converts the unit to draft if it's not
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
6fa96cf0
...
...
@@ -1380,7 +1380,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
return
result
def
delete_course
(
self
,
course_key
,
user_id
=
None
):
def
delete_course
(
self
,
course_key
,
user_id
):
"""
Remove the given course from the course index.
...
...
@@ -1395,6 +1395,10 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
log
.
info
(
u"deleting course from split-mongo:
%
s"
,
course_key
)
self
.
db_connection
.
delete_course_index
(
index
)
# We do NOT call the super class here since we need to keep the assets
# in case the course is later restored.
# super(SplitMongoModuleStore, self).delete_course(course_key, user_id)
def
revert_to_published
(
self
,
location
,
user_id
=
None
):
"""
Reverts an item to its last published version (recursively traversing all of its descendants).
...
...
@@ -1407,13 +1411,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
raise
NotImplementedError
()
def
get_errored_courses
(
self
):
"""
This function doesn't make sense for the mongo modulestore, as structures
are loaded on demand, rather than up front
"""
return
{}
def
inherit_settings
(
self
,
block_map
,
block_json
,
inheriting_settings
=
None
):
"""
Updates block_json with any inheritable setting set by an ancestor and recurses to children.
...
...
common/lib/xmodule/xmodule/modulestore/store_utilities.py
View file @
6fa96cf0
...
...
@@ -85,25 +85,3 @@ def rewrite_nonportable_content_links(source_course_id, dest_course_id, text):
logging
.
warning
(
"Error producing regex substitution
%
r for text =
%
r.
\n\n
Error msg =
%
s"
,
source_course_id
,
text
,
str
(
exc
))
return
text
def
delete_course
(
modulestore
,
contentstore
,
course_key
,
commit
=
False
):
"""
This method will actually do the work to delete all content in a course in a MongoDB backed
courseware store. BE VERY CAREFUL, this is not reversable.
"""
# check to see if the source course is actually there
if
not
modulestore
.
has_course
(
course_key
):
raise
Exception
(
"Cannot find a course at {0}. Aborting"
.
format
(
course_key
))
if
commit
:
print
"Deleting assets and thumbnails {}"
.
format
(
course_key
)
contentstore
.
delete_all_course_assets
(
course_key
)
# finally delete the course
print
"Deleting {0}..."
.
format
(
course_key
)
if
commit
:
modulestore
.
delete_course
(
course_key
,
'**replace-user**'
)
return
True
common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
View file @
6fa96cf0
...
...
@@ -4,8 +4,10 @@ Modulestore configuration for test cases.
from
uuid
import
uuid4
from
django.test
import
TestCase
from
django.contrib.auth.models
import
User
from
xmodule.modulestore.django
import
(
modulestore
,
clear_existing_modulestores
,
loc_mapper
)
modulestore
,
clear_existing_modulestores
,
loc_mapper
)
from
xmodule.modulestore
import
ModuleStoreEnum
...
...
@@ -126,18 +128,62 @@ class ModuleStoreTestCase(TestCase):
`clear_existing_modulestores()` directly in
your `setUp()` method.
"""
def
setUp
(
self
,
**
kwargs
):
"""
Creates a test User if `create_user` is True.
Returns the password for the test User.
@staticmethod
def
update_course
(
course
):
Args:
create_user - specifies whether or not to create a test User. Default is True.
"""
super
(
ModuleStoreTestCase
,
self
)
.
setUp
()
self
.
store
=
modulestore
()
uname
=
'testuser'
email
=
'test+courses@edx.org'
password
=
'foo'
if
kwargs
.
pop
(
'create_user'
,
True
):
# Create the user so we can log them in.
self
.
user
=
User
.
objects
.
create_user
(
uname
,
email
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self
.
user
.
is_active
=
True
# Staff has access to view all courses
self
.
user
.
is_staff
=
True
self
.
user
.
save
()
return
password
def
create_non_staff_user
(
self
):
"""
Creates a non-staff test user.
Returns the non-staff test user and its password.
"""
uname
=
'teststudent'
password
=
'foo'
nonstaff_user
=
User
.
objects
.
create_user
(
uname
,
'test+student@edx.org'
,
password
)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
nonstaff_user
.
is_active
=
True
nonstaff_user
.
is_staff
=
False
nonstaff_user
.
save
()
return
nonstaff_user
,
password
def
update_course
(
self
,
course
,
user_id
):
"""
Updates the version of course in the modulestore
'course' is an instance of CourseDescriptor for which we want
to update metadata.
"""
store
=
modulestore
()
store
.
update_item
(
course
,
'**replace_user**'
)
updated_course
=
store
.
get_course
(
course
.
id
)
with
self
.
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
course
.
id
):
self
.
store
.
update_item
(
course
,
user_id
)
updated_course
=
s
elf
.
s
tore
.
get_course
(
course
.
id
)
return
updated_course
@staticmethod
...
...
common/lib/xmodule/xmodule/modulestore/tests/factories.py
View file @
6fa96cf0
...
...
@@ -2,7 +2,7 @@ from factory import Factory, lazy_attribute_sequence, lazy_attribute
from
factory.containers
import
CyclicDefinitionError
from
uuid
import
uuid4
from
xmodule.modulestore
import
prefer_xmodules
from
xmodule.modulestore
import
prefer_xmodules
,
ModuleStoreEnum
from
opaque_keys.edx.locations
import
Location
from
xblock.core
import
XBlock
from
xmodule.tabs
import
StaticTab
...
...
@@ -52,9 +52,11 @@ class CourseFactory(XModuleFactory):
store
=
kwargs
.
pop
(
'modulestore'
)
name
=
kwargs
.
get
(
'name'
,
kwargs
.
get
(
'run'
,
Location
.
clean
(
kwargs
.
get
(
'display_name'
))))
run
=
kwargs
.
get
(
'run'
,
name
)
user_id
=
kwargs
.
pop
(
'user_id'
,
ModuleStoreEnum
.
UserID
.
test
)
location
=
Location
(
org
,
number
,
run
,
'course'
,
name
)
with
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
# Write the data to the mongo datastore
new_course
=
store
.
create_xmodule
(
location
,
metadata
=
kwargs
.
get
(
'metadata'
,
None
))
...
...
@@ -65,7 +67,7 @@ class CourseFactory(XModuleFactory):
# Save the attributes we just set
new_course
.
save
()
# Update the data in the mongo datastore
store
.
update_item
(
new_course
,
'**replace_user**'
)
store
.
update_item
(
new_course
,
user_id
)
return
new_course
...
...
@@ -128,6 +130,8 @@ class ItemFactory(XModuleFactory):
:boilerplate: (optional) the boilerplate for overriding field values
:publish_item: (optional) whether or not to publish the item (default is True)
:target_class: is ignored
"""
...
...
@@ -143,7 +147,8 @@ class ItemFactory(XModuleFactory):
display_name
=
kwargs
.
pop
(
'display_name'
,
None
)
metadata
=
kwargs
.
pop
(
'metadata'
,
{})
location
=
kwargs
.
pop
(
'location'
)
user_id
=
kwargs
.
pop
(
'user_id'
,
999
)
user_id
=
kwargs
.
pop
(
'user_id'
,
ModuleStoreEnum
.
UserID
.
test
)
publish_item
=
kwargs
.
pop
(
'publish_item'
,
True
)
assert
isinstance
(
location
,
Location
)
assert
location
!=
parent_location
...
...
@@ -153,6 +158,8 @@ class ItemFactory(XModuleFactory):
# This code was based off that in cms/djangoapps/contentstore/views.py
parent
=
kwargs
.
pop
(
'parent'
,
None
)
or
store
.
get_item
(
parent_location
)
with
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
if
'boilerplate'
in
kwargs
:
template_id
=
kwargs
.
pop
(
'boilerplate'
)
clz
=
XBlock
.
load_class
(
category
,
select
=
prefer_xmodules
)
...
...
@@ -175,11 +182,7 @@ class ItemFactory(XModuleFactory):
# Save the attributes we just set
module
.
save
()
store
.
update_item
(
module
,
'**replace_user**'
)
if
'detached'
not
in
module
.
_class_tags
:
parent
.
children
.
append
(
location
)
store
.
update_item
(
parent
,
'**replace_user**'
)
store
.
update_item
(
module
,
user_id
)
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
# if we add one then we need to also add it to the policy information (i.e. metadata)
...
...
@@ -192,8 +195,18 @@ class ItemFactory(XModuleFactory):
url_slug
=
location
.
name
,
)
)
store
.
update_item
(
course
,
'**replace_user**'
)
store
.
update_item
(
course
,
user_id
)
# parent and publish the item, so it can be accessed
if
'detached'
not
in
module
.
_class_tags
:
parent
.
children
.
append
(
location
)
store
.
update_item
(
parent
,
user_id
)
if
publish_item
:
store
.
publish
(
parent
.
location
,
user_id
)
elif
publish_item
:
store
.
publish
(
location
,
user_id
)
# return the published item
return
store
.
get_item
(
location
)
...
...
common/lib/xmodule/xmodule/modulestore/tests/persistent_factories.py
View file @
6fa96cf0
...
...
@@ -33,7 +33,7 @@ class PersistentCourseFactory(SplitFactory):
# pylint: disable=W0613
@classmethod
def
_create
(
cls
,
target_class
,
offering
=
'999'
,
org
=
'testX'
,
user_id
=
'test_user'
,
def
_create
(
cls
,
target_class
,
offering
=
'999'
,
org
=
'testX'
,
user_id
=
ModuleStoreEnum
.
UserID
.
test
,
master_branch
=
ModuleStoreEnum
.
BranchName
.
draft
,
**
kwargs
):
modulestore
=
kwargs
.
pop
(
'modulestore'
)
...
...
@@ -59,7 +59,7 @@ class ItemFactory(SplitFactory):
# pylint: disable=W0613
@classmethod
def
_create
(
cls
,
target_class
,
parent_location
,
category
=
'chapter'
,
user_id
=
'test_user'
,
block_id
=
None
,
definition_locator
=
None
,
force
=
False
,
user_id
=
ModuleStoreEnum
.
UserID
.
test
,
block_id
=
None
,
definition_locator
=
None
,
force
=
False
,
continue_version
=
False
,
**
kwargs
):
"""
passes *kwargs* as the new item's field values:
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
View file @
6fa96cf0
...
...
@@ -116,7 +116,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
writable_chapter_location
=
self
.
store
=
self
.
fake_location
=
self
.
xml_chapter_location
=
None
self
.
course_locations
=
[]
self
.
user_id
=
0
self
.
user_id
=
ModuleStoreEnum
.
UserID
.
test
# pylint: disable=invalid-name
def
_create_course
(
self
,
default
,
course_key
):
...
...
@@ -127,12 +127,12 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
offering
=
course_key
.
offering
.
replace
(
'/'
,
'.'
)
else
:
offering
=
course_key
.
offering
course
=
self
.
store
.
create_course
(
course_key
.
org
,
offering
)
course
=
self
.
store
.
create_course
(
course_key
.
org
,
offering
,
self
.
user_id
)
category
=
self
.
writable_chapter_location
.
category
block_id
=
self
.
writable_chapter_location
.
name
chapter
=
self
.
store
.
create_item
(
# don't use course_location as it may not be the repr
course
.
location
,
category
,
location
=
self
.
writable_chapter_location
,
block_id
=
block_id
course
.
location
,
category
,
self
.
user_id
,
location
=
self
.
writable_chapter_location
,
block_id
=
block_id
)
if
isinstance
(
course
.
id
,
CourseLocator
):
self
.
course_locations
[
self
.
MONGO_COURSEID
]
=
course
.
location
.
version_agnostic
()
...
...
@@ -184,7 +184,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
]
def
create_sub_tree
(
parent
,
block_info
):
block
=
self
.
store
.
create_item
(
parent
.
location
,
category
=
block_info
.
category
,
block_id
=
block_info
.
display_name
)
block
=
self
.
store
.
create_item
(
parent
.
location
,
block_info
.
category
,
self
.
user_id
,
block_id
=
block_info
.
display_name
)
for
tree
in
block_info
.
sub_tree
:
create_sub_tree
(
block
,
tree
)
# reload the block to update its children field
...
...
@@ -306,13 +306,13 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
assertFalse
(
course
.
show_calculator
,
"Default changed making test meaningless"
)
course
.
show_calculator
=
True
with
self
.
assertRaises
(
NotImplementedError
):
# ensure it doesn't allow writing
self
.
store
.
update_item
(
course
,
None
)
self
.
store
.
update_item
(
course
,
self
.
user_id
)
# now do it for a r/w db
course
=
self
.
store
.
get_course
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
# if following raised, then the test is really a noop, change it
self
.
assertFalse
(
course
.
show_calculator
,
"Default changed making test meaningless"
)
course
.
show_calculator
=
True
self
.
store
.
update_item
(
course
,
None
)
self
.
store
.
update_item
(
course
,
self
.
user_id
)
course
=
self
.
store
.
get_course
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
self
.
assertTrue
(
course
.
show_calculator
)
...
...
@@ -324,8 +324,8 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
initdb
(
default_ms
)
# r/o try deleting the course (is here to ensure it can't be deleted)
with
self
.
assertRaises
(
NotImplementedError
):
self
.
store
.
delete_item
(
self
.
xml_chapter_location
,
13
)
self
.
store
.
delete_item
(
self
.
writable_chapter_location
,
9
)
self
.
store
.
delete_item
(
self
.
xml_chapter_location
,
self
.
user_id
)
self
.
store
.
delete_item
(
self
.
writable_chapter_location
,
self
.
user_id
)
# verify it's gone
with
self
.
assertRaises
(
ItemNotFoundError
):
self
.
store
.
get_item
(
self
.
writable_chapter_location
)
...
...
@@ -367,7 +367,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
xml_store
=
self
.
store
.
_get_modulestore_by_type
(
ModuleStoreEnum
.
Type
.
xml
)
# the important thing is not which exception it raises but that it raises an exception
with
self
.
assertRaises
(
AttributeError
):
xml_store
.
create_course
(
"org"
,
"course/run"
,
999
)
xml_store
.
create_course
(
"org"
,
"course/run"
,
self
.
user_id
)
@ddt.data
(
'draft'
,
'split'
)
def
test_get_course
(
self
,
default_ms
):
...
...
@@ -547,7 +547,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
self
.
initdb
(
default_ms
)
# create an orphan
course_id
=
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
orphan
=
self
.
store
.
create_item
(
course_id
,
'problem'
,
block_id
=
'orphan'
)
orphan
=
self
.
store
.
create_item
(
course_id
,
'problem'
,
self
.
user_id
,
block_id
=
'orphan'
)
found_orphans
=
self
.
store
.
get_orphans
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
if
default_ms
==
'split'
:
self
.
assertEqual
(
found_orphans
,
[
orphan
.
location
.
version_agnostic
()])
...
...
@@ -561,7 +561,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
new location for the child
"""
self
.
initdb
(
default_ms
)
self
.
store
.
create_item
(
self
.
course_locations
[
self
.
MONGO_COURSEID
],
'problem'
,
block_id
=
'orphan'
)
self
.
store
.
create_item
(
self
.
course_locations
[
self
.
MONGO_COURSEID
],
'problem'
,
self
.
user_id
,
block_id
=
'orphan'
)
orphans
=
self
.
store
.
get_orphans
(
self
.
course_locations
[
self
.
MONGO_COURSEID
]
.
course_key
)
self
.
assertEqual
(
len
(
orphans
),
0
,
"unexpected orphans: {}"
.
format
(
orphans
))
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
View file @
6fa96cf0
...
...
@@ -134,6 +134,14 @@ class TestMongoModuleStore(unittest.TestCase):
# Destroy the test db.
connection
.
drop_database
(
DB
)
def
setUp
(
self
):
# make a copy for convenience
self
.
connection
=
TestMongoModuleStore
.
connection
self
.
dummy_user
=
ModuleStoreEnum
.
UserID
.
test
def
tearDown
(
self
):
pass
def
test_init
(
self
):
'''Make sure the db loads'''
ids
=
list
(
self
.
connection
[
DB
][
COLLECTION
]
.
find
({},
{
'_id'
:
True
}))
...
...
@@ -351,7 +359,7 @@ class TestMongoModuleStore(unittest.TestCase):
# set toy course to share the wiki with simple course
toy_course
=
self
.
draft_store
.
get_course
(
SlashSeparatedCourseKey
(
'edX'
,
'toy'
,
'2012_Fall'
))
toy_course
.
wiki_slug
=
'simple'
self
.
draft_store
.
update_item
(
toy_course
)
self
.
draft_store
.
update_item
(
toy_course
,
ModuleStoreEnum
.
UserID
.
test
)
# now toy_course should not be retrievable with old wiki_slug
course_locations
=
self
.
draft_store
.
get_courses_for_wiki
(
'toy'
)
...
...
@@ -366,7 +374,7 @@ class TestMongoModuleStore(unittest.TestCase):
# configure simple course to use unique wiki_slug.
simple_course
=
self
.
draft_store
.
get_course
(
SlashSeparatedCourseKey
(
'edX'
,
'simple'
,
'2012_Fall'
))
simple_course
.
wiki_slug
=
'edX.simple.2012_Fall'
self
.
draft_store
.
update_item
(
simple_course
)
self
.
draft_store
.
update_item
(
simple_course
,
ModuleStoreEnum
.
UserID
.
test
)
# it should be retrievable with its new wiki_slug
course_locations
=
self
.
draft_store
.
get_courses_for_wiki
(
'edX.simple.2012_Fall'
)
assert_equals
(
len
(
course_locations
),
1
)
...
...
@@ -491,11 +499,10 @@ class TestMongoModuleStore(unittest.TestCase):
"""
course_location
=
Location
(
'edx'
,
'direct'
,
'2012_Fall'
,
'course'
,
'test_course'
)
chapter_location
=
Location
(
'edx'
,
'direct'
,
'2012_Fall'
,
'chapter'
,
'test_chapter'
)
dummy_user
=
123
# Create dummy direct only xblocks
self
.
draft_store
.
create_and_save_xmodule
(
course_location
,
user_id
=
dummy_user
)
self
.
draft_store
.
create_and_save_xmodule
(
chapter_location
,
user_id
=
dummy_user
)
self
.
draft_store
.
create_and_save_xmodule
(
course_location
,
user_id
=
self
.
dummy_user
)
self
.
draft_store
.
create_and_save_xmodule
(
chapter_location
,
user_id
=
self
.
dummy_user
)
# Check that neither xblock has changes
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
course_location
))
...
...
@@ -506,29 +513,28 @@ class TestMongoModuleStore(unittest.TestCase):
Tests that has_changes() only returns true when changes are present
"""
location
=
Location
(
'edX'
,
'changes'
,
'2012_Fall'
,
'vertical'
,
'test_vertical'
)
dummy_user
=
123
# Create a dummy component to test against
self
.
draft_store
.
create_and_save_xmodule
(
location
,
user_id
=
dummy_user
)
self
.
draft_store
.
create_and_save_xmodule
(
location
,
user_id
=
self
.
dummy_user
)
# Not yet published, so changes are present
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
location
))
# Publish and verify that there are no unpublished changes
self
.
draft_store
.
publish
(
location
,
dummy_user
)
self
.
draft_store
.
publish
(
location
,
self
.
dummy_user
)
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
location
))
# Change the component, then check that there now are changes
component
=
self
.
draft_store
.
get_item
(
location
)
component
.
display_name
=
'Changed Display Name'
self
.
draft_store
.
update_item
(
component
,
dummy_user
)
self
.
draft_store
.
update_item
(
component
,
self
.
dummy_user
)
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
location
))
# Publish and verify again
self
.
draft_store
.
publish
(
location
,
dummy_user
)
self
.
draft_store
.
publish
(
location
,
self
.
dummy_user
)
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
location
))
def
_create_test_tree
(
self
,
name
,
user_id
=
123
):
def
_create_test_tree
(
self
,
name
,
user_id
=
None
):
"""
Creates and returns a tree with the following structure:
Grandparent
...
...
@@ -538,6 +544,9 @@ class TestMongoModuleStore(unittest.TestCase):
Child Sibling
"""
if
user_id
is
None
:
user_id
=
self
.
dummy_user
locations
=
{
'grandparent'
:
Location
(
'edX'
,
'tree'
,
name
,
'chapter'
,
'grandparent'
),
'parent_sibling'
:
Location
(
'edX'
,
'tree'
,
name
,
'sequential'
,
'parent_sibling'
),
...
...
@@ -566,7 +575,6 @@ class TestMongoModuleStore(unittest.TestCase):
"""
Tests that has_changes() returns true on ancestors when a child is changed
"""
dummy_user
=
123
locations
=
self
.
_create_test_tree
(
'has_changes_ancestors'
)
# Verify that there are no unpublished changes
...
...
@@ -576,7 +584,7 @@ class TestMongoModuleStore(unittest.TestCase):
# Change the child
child
=
self
.
draft_store
.
get_item
(
locations
[
'child'
])
child
.
display_name
=
'Changed Display Name'
self
.
draft_store
.
update_item
(
child
,
user_id
=
dummy_user
)
self
.
draft_store
.
update_item
(
child
,
user_id
=
self
.
dummy_user
)
# All ancestors should have changes, but not siblings
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
locations
[
'grandparent'
]))
...
...
@@ -586,7 +594,7 @@ class TestMongoModuleStore(unittest.TestCase):
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
locations
[
'child_sibling'
]))
# Publish the unit with changes
self
.
draft_store
.
publish
(
locations
[
'parent'
],
dummy_user
)
self
.
draft_store
.
publish
(
locations
[
'parent'
],
self
.
dummy_user
)
# Verify that there are no unpublished changes
for
key
in
locations
:
...
...
@@ -596,7 +604,6 @@ class TestMongoModuleStore(unittest.TestCase):
"""
Tests that has_changes() returns false after a child is published only if all children are unchanged
"""
dummy_user
=
123
locations
=
self
.
_create_test_tree
(
'has_changes_publish_ancestors'
)
# Verify that there are no unpublished changes
...
...
@@ -608,22 +615,22 @@ class TestMongoModuleStore(unittest.TestCase):
child_sibling
=
self
.
draft_store
.
get_item
(
locations
[
'child_sibling'
])
child
.
display_name
=
'Changed Display Name'
child_sibling
.
display_name
=
'Changed Display Name'
self
.
draft_store
.
update_item
(
child
,
user_id
=
dummy_user
)
self
.
draft_store
.
update_item
(
child_sibling
,
user_id
=
dummy_user
)
self
.
draft_store
.
update_item
(
child
,
user_id
=
self
.
dummy_user
)
self
.
draft_store
.
update_item
(
child_sibling
,
user_id
=
self
.
dummy_user
)
# Verify that ancestors have changes
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
locations
[
'grandparent'
]))
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
locations
[
'parent'
]))
# Publish one child
self
.
draft_store
.
publish
(
locations
[
'child_sibling'
],
dummy_user
)
self
.
draft_store
.
publish
(
locations
[
'child_sibling'
],
self
.
dummy_user
)
# Verify that ancestors still have changes
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
locations
[
'grandparent'
]))
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
locations
[
'parent'
]))
# Publish the other child
self
.
draft_store
.
publish
(
locations
[
'child'
],
dummy_user
)
self
.
draft_store
.
publish
(
locations
[
'child'
],
self
.
dummy_user
)
# Verify that ancestors now have no changes
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
locations
[
'grandparent'
]))
...
...
@@ -634,7 +641,6 @@ class TestMongoModuleStore(unittest.TestCase):
Tests that has_changes() returns true for the parent when a child with changes is added
and false when that child is removed.
"""
dummy_user
=
123
locations
=
self
.
_create_test_tree
(
'has_changes_add_remove_child'
)
# Test that the ancestors don't have changes
...
...
@@ -643,10 +649,10 @@ class TestMongoModuleStore(unittest.TestCase):
# Create a new child and attach it to parent
new_child_location
=
Location
(
'edX'
,
'tree'
,
'has_changes_add_remove_child'
,
'vertical'
,
'new_child'
)
self
.
draft_store
.
create_and_save_xmodule
(
new_child_location
,
user_id
=
dummy_user
)
self
.
draft_store
.
create_and_save_xmodule
(
new_child_location
,
user_id
=
self
.
dummy_user
)
parent
=
self
.
draft_store
.
get_item
(
locations
[
'parent'
])
parent
.
children
+=
[
new_child_location
]
self
.
draft_store
.
update_item
(
parent
,
user_id
=
dummy_user
)
self
.
draft_store
.
update_item
(
parent
,
user_id
=
self
.
dummy_user
)
# Verify that the ancestors now have changes
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
locations
[
'grandparent'
]))
...
...
@@ -655,7 +661,7 @@ class TestMongoModuleStore(unittest.TestCase):
# Remove the child from the parent
parent
=
self
.
draft_store
.
get_item
(
locations
[
'parent'
])
parent
.
children
=
[
locations
[
'child'
],
locations
[
'child_sibling'
]]
self
.
draft_store
.
update_item
(
parent
,
user_id
=
dummy_user
)
self
.
draft_store
.
update_item
(
parent
,
user_id
=
self
.
dummy_user
)
# Verify that ancestors now have no changes
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
locations
[
'grandparent'
]))
...
...
@@ -665,15 +671,14 @@ class TestMongoModuleStore(unittest.TestCase):
"""
Tests that has_changes() returns true after editing the child of a vertical (both not direct only categories).
"""
dummy_user
=
123
parent_location
=
Location
(
'edX'
,
'test'
,
'non_direct_only_children'
,
'vertical'
,
'parent'
)
child_location
=
Location
(
'edX'
,
'test'
,
'non_direct_only_children'
,
'html'
,
'child'
)
parent
=
self
.
draft_store
.
create_and_save_xmodule
(
parent_location
,
user_id
=
dummy_user
)
child
=
self
.
draft_store
.
create_and_save_xmodule
(
child_location
,
user_id
=
dummy_user
)
parent
=
self
.
draft_store
.
create_and_save_xmodule
(
parent_location
,
user_id
=
self
.
dummy_user
)
child
=
self
.
draft_store
.
create_and_save_xmodule
(
child_location
,
user_id
=
self
.
dummy_user
)
parent
.
children
+=
[
child_location
]
self
.
draft_store
.
update_item
(
parent
,
user_id
=
dummy_user
)
self
.
draft_store
.
publish
(
parent_location
,
dummy_user
)
self
.
draft_store
.
update_item
(
parent
,
user_id
=
self
.
dummy_user
)
self
.
draft_store
.
publish
(
parent_location
,
self
.
dummy_user
)
# Verify that there are no changes
self
.
assertFalse
(
self
.
draft_store
.
has_changes
(
parent_location
))
...
...
@@ -681,7 +686,7 @@ class TestMongoModuleStore(unittest.TestCase):
# Change the child
child
.
display_name
=
'Changed Display Name'
self
.
draft_store
.
update_item
(
child
,
user_id
=
123
)
self
.
draft_store
.
update_item
(
child
,
user_id
=
self
.
dummy_user
)
# Verify that both parent and child have changes
self
.
assertTrue
(
self
.
draft_store
.
has_changes
(
parent_location
))
...
...
@@ -693,7 +698,7 @@ class TestMongoModuleStore(unittest.TestCase):
"""
create_user
=
123
edit_user
=
456
locations
=
self
.
_create_test_tree
(
'update_edit_info_ancestors'
,
create_user
)
locations
=
self
.
_create_test_tree
(
'update_edit_info_ancestors'
,
create_user
)
def
check_node
(
location_key
,
after
,
before
,
edited_by
,
subtree_after
,
subtree_before
,
subtree_by
):
"""
...
...
@@ -739,24 +744,23 @@ class TestMongoModuleStore(unittest.TestCase):
Tests that edited_on and edited_by are set correctly during an update
"""
location
=
Location
(
'edX'
,
'editInfoTest'
,
'2012_Fall'
,
'html'
,
'test_html'
)
dummy_user
=
123
# Create a dummy component to test against
self
.
draft_store
.
create_and_save_xmodule
(
location
,
user_id
=
dummy_user
)
self
.
draft_store
.
create_and_save_xmodule
(
location
,
user_id
=
self
.
dummy_user
)
# Store the current edit time and verify that dummy_user created the component
component
=
self
.
draft_store
.
get_item
(
location
)
self
.
assertEqual
(
component
.
edited_by
,
dummy_user
)
self
.
assertEqual
(
component
.
edited_by
,
self
.
dummy_user
)
old_edited_on
=
component
.
edited_on
# Change the component
component
.
display_name
=
component
.
display_name
+
' Changed'
self
.
draft_store
.
update_item
(
component
,
dummy_user
)
self
.
draft_store
.
update_item
(
component
,
self
.
dummy_user
)
updated_component
=
self
.
draft_store
.
get_item
(
location
)
# Verify the ordering of edit times and that dummy_user made the edit
self
.
assertLess
(
old_edited_on
,
updated_component
.
edited_on
)
self
.
assertEqual
(
updated_component
.
edited_by
,
dummy_user
)
self
.
assertEqual
(
updated_component
.
edited_by
,
self
.
dummy_user
)
def
test_update_published_info
(
self
):
"""
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py
View file @
6fa96cf0
...
...
@@ -5,6 +5,7 @@ Tests for split_migrator
import
uuid
import
random
import
mock
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.mongo.base
import
MongoRevisionKey
from
xmodule.modulestore.loc_mapper_store
import
LocMapperStore
from
xmodule.modulestore.split_migrator
import
SplitMigrator
...
...
@@ -63,7 +64,7 @@ class TestMigration(SplitWMongoCourseBoostrapper):
self
.
create_random_units
(
False
,
both_vert_loc
)
draft_both
=
self
.
draft_mongo
.
get_item
(
both_vert_loc
)
draft_both
.
display_name
=
'Both vertical renamed'
self
.
draft_mongo
.
update_item
(
draft_both
)
self
.
draft_mongo
.
update_item
(
draft_both
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
create_random_units
(
True
,
both_vert_loc
)
# vertical in draft only (x2)
draft_vert_loc
=
self
.
old_course_key
.
make_usage_key
(
'vertical'
,
uuid
.
uuid4
()
.
hex
)
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
View file @
6fa96cf0
...
...
@@ -441,6 +441,7 @@ class SplitModuleTest(unittest.TestCase):
}
},
}
@staticmethod
def
bootstrapDB
():
'''
...
...
@@ -489,6 +490,9 @@ class SplitModuleTest(unittest.TestCase):
destination
=
CourseLocator
(
org
=
"testx"
,
offering
=
"wonderful"
,
branch
=
BRANCH_NAME_PUBLISHED
)
split_store
.
xblock_publish
(
"test@edx.org"
,
to_publish
,
destination
,
[
to_publish
],
None
)
def
setUp
(
self
):
self
.
user_id
=
random
.
getrandbits
(
32
)
def
tearDown
(
self
):
"""
Clear persistence between each test.
...
...
@@ -817,7 +821,7 @@ class SplitModuleItemTests(SplitModuleTest):
draft_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
BRANCH_NAME_DRAFT
)
published_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
BRANCH_NAME_PUBLISHED
)
head
=
draft_course
.
make_usage_key
(
'course'
,
'head12345'
)
dummy_user
=
'testUser'
dummy_user
=
ModuleStoreEnum
.
UserID
.
test
# Not yet published, so changes are present
self
.
assertTrue
(
modulestore
()
.
has_changes
(
head
))
...
...
@@ -1217,7 +1221,7 @@ class TestItemCrud(SplitModuleTest):
problem
.
max_attempts
=
4
problem
.
save
()
# decache above setting into the kvs
updated_problem
=
modulestore
()
.
update_item
(
problem
,
'**replace_user**'
)
updated_problem
=
modulestore
()
.
update_item
(
problem
,
self
.
user_id
)
# check that course version changed and course's previous is the other one
self
.
assertEqual
(
updated_problem
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_problem
.
location
.
version_guid
,
pre_version_guid
)
...
...
@@ -1232,7 +1236,7 @@ class TestItemCrud(SplitModuleTest):
history_info
=
modulestore
()
.
get_course_history_info
(
current_course
.
location
)
self
.
assertEqual
(
history_info
[
'previous_version'
],
pre_version_guid
)
self
.
assertEqual
(
history_info
[
'edited_by'
],
"**replace_user**"
)
self
.
assertEqual
(
history_info
[
'edited_by'
],
self
.
user_id
)
def
test_update_children
(
self
):
"""
...
...
@@ -1249,7 +1253,7 @@ class TestItemCrud(SplitModuleTest):
self
.
assertGreater
(
len
(
block
.
children
),
0
,
"meaningless test"
)
moved_child
=
block
.
children
.
pop
()
block
.
save
()
# decache model changes
updated_problem
=
modulestore
()
.
update_item
(
block
,
'**replace_user**'
)
updated_problem
=
modulestore
()
.
update_item
(
block
,
self
.
user_id
)
# check that course version changed and course's previous is the other one
self
.
assertEqual
(
updated_problem
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_problem
.
location
.
version_guid
,
pre_version_guid
)
...
...
@@ -1258,7 +1262,7 @@ class TestItemCrud(SplitModuleTest):
locator
=
locator
.
course_key
.
make_usage_key
(
'Chapter'
,
"chapter1"
)
other_block
=
modulestore
()
.
get_item
(
locator
)
other_block
.
children
.
append
(
moved_child
)
other_updated
=
modulestore
()
.
update_item
(
other_block
,
'**replace_user**'
)
other_updated
=
modulestore
()
.
update_item
(
other_block
,
self
.
user_id
)
self
.
assertIn
(
moved_child
.
version_agnostic
(),
version_agnostic
(
other_updated
.
children
))
def
test_update_definition
(
self
):
...
...
@@ -1274,7 +1278,7 @@ class TestItemCrud(SplitModuleTest):
block
.
grading_policy
[
'GRADER'
][
0
][
'min_count'
]
=
13
block
.
save
()
# decache model changes
updated_block
=
modulestore
()
.
update_item
(
block
,
'**replace_user**'
)
updated_block
=
modulestore
()
.
update_item
(
block
,
self
.
user_id
)
self
.
assertNotEqual
(
updated_block
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_block
.
location
.
version_guid
,
pre_version_guid
)
...
...
@@ -1320,7 +1324,7 @@ class TestItemCrud(SplitModuleTest):
block
.
advertised_start
=
"Soon"
block
.
save
()
# decache model changes
updated_block
=
modulestore
()
.
update_item
(
block
,
"**replace_user**"
)
updated_block
=
modulestore
()
.
update_item
(
block
,
self
.
user_id
)
self
.
assertNotEqual
(
updated_block
.
definition_locator
.
definition_id
,
pre_def_id
)
self
.
assertNotEqual
(
updated_block
.
location
.
version_guid
,
pre_version_guid
)
self
.
assertEqual
(
updated_block
.
grading_policy
[
'GRADER'
][
0
][
'min_count'
],
13
)
...
...
@@ -1330,13 +1334,13 @@ class TestItemCrud(SplitModuleTest):
def
test_delete_item
(
self
):
course
=
self
.
create_course_for_deletion
()
with
self
.
assertRaises
(
ValueError
):
modulestore
()
.
delete_item
(
course
.
location
,
'deleting_user'
)
modulestore
()
.
delete_item
(
course
.
location
,
self
.
user_id
)
reusable_location
=
course
.
id
.
version_agnostic
()
.
for_branch
(
BRANCH_NAME_DRAFT
)
# delete a leaf
problems
=
modulestore
()
.
get_items
(
reusable_location
,
category
=
'problem'
)
locn_to_del
=
problems
[
0
]
.
location
new_course_loc
=
modulestore
()
.
delete_item
(
locn_to_del
,
'deleting_user'
)
new_course_loc
=
modulestore
()
.
delete_item
(
locn_to_del
,
self
.
user_id
)
deleted
=
locn_to_del
.
version_agnostic
()
self
.
assertFalse
(
modulestore
()
.
has_item
(
deleted
))
with
self
.
assertRaises
(
VersionConflictError
):
...
...
@@ -1347,7 +1351,7 @@ class TestItemCrud(SplitModuleTest):
# delete a subtree
nodes
=
modulestore
()
.
get_items
(
reusable_location
,
category
=
'chapter'
)
new_course_loc
=
modulestore
()
.
delete_item
(
nodes
[
0
]
.
location
,
'deleting_user'
)
new_course_loc
=
modulestore
()
.
delete_item
(
nodes
[
0
]
.
location
,
self
.
user_id
)
# check subtree
def
check_subtree
(
node
):
...
...
@@ -1582,7 +1586,6 @@ class TestPublish(SplitModuleTest):
"""
def
setUp
(
self
):
SplitModuleTest
.
setUp
(
self
)
self
.
user
=
random
.
getrandbits
(
32
)
def
tearDown
(
self
):
SplitModuleTest
.
tearDown
(
self
)
...
...
@@ -1597,14 +1600,14 @@ class TestPublish(SplitModuleTest):
chapter1
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter1'
)
chapter2
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter2'
)
chapter3
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter3'
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
head
],
[
chapter2
,
chapter3
])
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
dest_course
,
[
head
],
[
chapter2
,
chapter3
])
expected
=
[
head
.
block_id
,
chapter1
.
block_id
]
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
chapter2
.
block_id
,
chapter3
.
block_id
,
"problem1"
,
"problem3_2"
]
)
# add a child under chapter1
new_module
=
modulestore
()
.
create_item
(
chapter1
,
"sequential"
,
self
.
user
,
chapter1
,
"sequential"
,
self
.
user
_id
,
fields
=
{
'display_name'
:
'new sequential'
},
)
# remove chapter1 from expected b/c its pub'd version != the source anymore since source changed
...
...
@@ -1613,7 +1616,7 @@ class TestPublish(SplitModuleTest):
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
# publish it
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
new_module
.
location
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
dest_course
,
[
new_module
.
location
],
None
)
expected
.
append
(
new_module
.
location
.
block_id
)
# check that it is in the published course and that its parent is the chapter
pub_module
=
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
...
...
@@ -1622,10 +1625,10 @@ class TestPublish(SplitModuleTest):
)
# ensure intentionally orphaned blocks work (e.g., course_info)
new_module
=
modulestore
()
.
create_item
(
source_course
,
"course_info"
,
self
.
user
,
block_id
=
"handouts"
source_course
,
"course_info"
,
self
.
user
_id
,
block_id
=
"handouts"
)
# publish it
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
new_module
.
location
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
dest_course
,
[
new_module
.
location
],
None
)
expected
.
append
(
new_module
.
location
.
block_id
)
# check that it is in the published course (no error means it worked)
pub_module
=
modulestore
()
.
get_item
(
new_module
.
location
.
map_into_course
(
dest_course
))
...
...
@@ -1644,15 +1647,15 @@ class TestPublish(SplitModuleTest):
chapter3
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter3'
)
problem1
=
source_course
.
make_usage_key
(
'problem'
,
'problem1'
)
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
chapter3
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
destination_course
,
[
chapter3
],
None
)
# publishing into a new branch w/o publishing the root
destination_course
=
CourseLocator
(
org
=
'testx'
,
offering
=
'GreekHero'
,
branch
=
BRANCH_NAME_PUBLISHED
)
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
chapter3
],
None
)
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
destination_course
,
[
chapter3
],
None
)
# publishing a subdag w/o the parent already in course
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
head
],
[
chapter3
])
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
destination_course
,
[
head
],
[
chapter3
])
with
self
.
assertRaises
(
ItemNotFoundError
):
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
destination_course
,
[
problem1
],
[])
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
destination_course
,
[
problem1
],
[])
def
test_move_delete
(
self
):
"""
...
...
@@ -1663,7 +1666,7 @@ class TestPublish(SplitModuleTest):
head
=
source_course
.
make_usage_key
(
'course'
,
"head12345"
)
chapter2
=
source_course
.
make_usage_key
(
'chapter'
,
'chapter2'
)
problem1
=
source_course
.
make_usage_key
(
'problem'
,
'problem1'
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
head
],
[
chapter2
])
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
dest_course
,
[
head
],
[
chapter2
])
expected
=
[
"head12345"
,
"chapter1"
,
"chapter3"
,
"problem1"
,
"problem3_2"
]
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
])
# now move problem1 and delete problem3_2
...
...
@@ -1671,8 +1674,8 @@ class TestPublish(SplitModuleTest):
chapter3
=
modulestore
()
.
get_item
(
source_course
.
make_usage_key
(
"chapter"
,
"chapter3"
))
chapter1
.
children
.
append
(
problem1
)
chapter3
.
children
.
remove
(
problem1
.
map_into_course
(
chapter3
.
location
.
course_key
))
modulestore
()
.
delete_item
(
source_course
.
make_usage_key
(
"problem"
,
"problem3_2"
),
self
.
user
)
modulestore
()
.
xblock_publish
(
self
.
user
,
source_course
,
dest_course
,
[
head
],
[
chapter2
])
modulestore
()
.
delete_item
(
source_course
.
make_usage_key
(
"problem"
,
"problem3_2"
),
self
.
user
_id
)
modulestore
()
.
xblock_publish
(
self
.
user
_id
,
source_course
,
dest_course
,
[
head
],
[
chapter2
])
expected
=
[
"head12345"
,
"chapter1"
,
"chapter3"
,
"problem1"
]
self
.
_check_course
(
source_course
,
dest_course
,
expected
,
[
"chapter2"
,
"problem3_2"
])
...
...
@@ -1681,7 +1684,7 @@ class TestPublish(SplitModuleTest):
Check that the course has the expected blocks and does not have the unexpected blocks
"""
history_info
=
modulestore
()
.
get_course_history_info
(
dest_course_loc
)
self
.
assertEqual
(
history_info
[
'edited_by'
],
self
.
user
)
self
.
assertEqual
(
history_info
[
'edited_by'
],
self
.
user
_id
)
for
expected
in
expected_blocks
:
# since block_type has no impact on identity, we can just provide an empty string
source
=
modulestore
()
.
get_item
(
source_course_loc
.
make_usage_key
(
""
,
expected
))
...
...
@@ -1690,8 +1693,8 @@ class TestPublish(SplitModuleTest):
self
.
assertEqual
(
source
.
category
,
pub_copy
.
category
)
self
.
assertEqual
(
source
.
update_version
,
pub_copy
.
update_version
)
self
.
assertEqual
(
self
.
user
,
pub_copy
.
edited_by
,
"{} edited_by {} not {}"
.
format
(
pub_copy
.
location
,
pub_copy
.
edited_by
,
self
.
user
)
self
.
user
_id
,
pub_copy
.
edited_by
,
"{} edited_by {} not {}"
.
format
(
pub_copy
.
location
,
pub_copy
.
edited_by
,
self
.
user
_id
)
)
for
field
in
source
.
fields
.
values
():
if
field
.
name
==
'children'
:
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_split_w_old_mongo.py
View file @
6fa96cf0
...
...
@@ -10,7 +10,6 @@ from xmodule.modulestore.split_mongo.split import SplitMongoModuleStore
from
xmodule.modulestore.mongo
import
MongoModuleStore
,
DraftMongoModuleStore
from
xmodule.modulestore.mongo.draft
import
DIRECT_ONLY_CATEGORIES
from
xmodule.modulestore
import
ModuleStoreEnum
from
mock
import
Mock
class
SplitWMongoCourseBoostrapper
(
unittest
.
TestCase
):
...
...
@@ -138,6 +137,6 @@ class SplitWMongoCourseBoostrapper(unittest.TestCase):
self
.
split_mongo
.
create_course
(
self
.
split_course_key
.
org
,
self
.
split_course_key
.
offering
,
self
.
userid
,
fields
=
fields
,
root_block_id
=
'runid'
)
old_course
=
self
.
old_mongo
.
create_course
(
self
.
split_course_key
.
org
,
'test_course/runid'
,
fields
=
fields
)
old_course
=
self
.
old_mongo
.
create_course
(
self
.
split_course_key
.
org
,
'test_course/runid'
,
self
.
userid
,
fields
=
fields
)
self
.
old_course_key
=
old_course
.
id
self
.
runtime
=
old_course
.
runtime
common/lib/xmodule/xmodule/modulestore/xml_importer.py
View file @
6fa96cf0
...
...
@@ -17,6 +17,7 @@ import xblock
from
xmodule.tabs
import
CourseTabList
from
xmodule.modulestore.exceptions
import
InvalidLocationError
from
xmodule.modulestore.mongo.base
import
MongoRevisionKey
from
xmodule.modulestore
import
ModuleStoreEnum
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -159,6 +160,8 @@ def import_from_xml(
# of course modules. It will be left as a TBD to implement that
# method on XmlModuleStore.
course_items
=
[]
with
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
):
for
course_key
in
xml_module_store
.
modules
.
keys
():
if
target_course_id
is
not
None
:
...
...
@@ -169,7 +172,7 @@ def import_from_xml(
# Creates a new course if it doesn't already exist
if
create_new_course_if_not_present
and
not
store
.
has_course
(
dest_course_id
,
ignore_case
=
True
):
try
:
store
.
create_course
(
dest_course_id
.
org
,
dest_course_id
.
offering
)
store
.
create_course
(
dest_course_id
.
org
,
dest_course_id
.
offering
,
user_id
)
except
InvalidLocationError
:
# course w/ same org and course exists
log
.
debug
(
...
...
common/lib/xmodule/xmodule/split_test_module.py
View file @
6fa96cf0
...
...
@@ -559,7 +559,7 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes
changed
=
True
if
changed
:
#
request does not have a user attribute, so pass None for user.
#
TODO user.id - to be fixed by Publishing team
self
.
system
.
modulestore
.
update_item
(
self
,
None
)
return
Response
()
...
...
common/lib/xmodule/xmodule/video_module/video_module.py
View file @
6fa96cf0
...
...
@@ -283,7 +283,7 @@ class VideoDescriptor(VideoFields, VideoStudioViewHandlers, TabsEditingDescripto
Save module with updated metadata to database."
"""
self
.
save
()
self
.
runtime
.
modulestore
.
update_item
(
self
,
user
.
id
if
user
else
None
)
self
.
runtime
.
modulestore
.
update_item
(
self
,
user
.
id
)
@property
def
editable_metadata_fields
(
self
):
...
...
lms/djangoapps/branding/tests.py
View file @
6fa96cf0
...
...
@@ -28,12 +28,13 @@ class AnonymousIndexPageTest(ModuleStoreTestCase):
Tests that anonymous users can access the '/' page, Need courses with start date
"""
def
setUp
(
self
):
s
elf
.
store
=
modulestore
()
s
uper
(
AnonymousIndexPageTest
,
self
)
.
setUp
()
self
.
factory
=
RequestFactory
()
self
.
course
=
CourseFactory
.
create
()
self
.
course
.
days_early_for_beta
=
5
self
.
course
.
enrollment_start
=
datetime
.
datetime
.
now
(
UTC
)
+
datetime
.
timedelta
(
days
=
3
)
self
.
store
.
update_item
(
self
.
course
,
'**replace_user**'
)
self
.
course
=
CourseFactory
.
create
(
days_early_for_beta
=
5
,
enrollment_start
=
datetime
.
datetime
.
now
(
UTC
)
+
datetime
.
timedelta
(
days
=
3
),
user_id
=
self
.
user
.
id
,
)
@override_settings
(
FEATURES
=
FEATURES_WITH_STARTDATE
)
def
test_none_user_index_access_with_startdate_fails
(
self
):
...
...
lms/djangoapps/courseware/features/annotatable.py
View file @
6fa96cf0
...
...
@@ -3,7 +3,7 @@ import textwrap
from
lettuce
import
world
,
steps
from
nose.tools
import
assert_in
,
assert_equals
,
assert_true
from
common
import
i_am_registered_for_the_course
,
visit_scenario_item
,
publish
from
common
import
i_am_registered_for_the_course
,
visit_scenario_item
DATA_TEMPLATE
=
textwrap
.
dedent
(
"""
\
<annotatable>
...
...
@@ -78,9 +78,6 @@ class AnnotatableSteps(object):
display_name
=
"Test Annotation Module"
,
data
=
DATA_TEMPLATE
.
format
(
"
\n
"
.
join
(
ANNOTATION_TEMPLATE
.
format
(
i
)
for
i
in
xrange
(
count
)))
)
publish
(
world
.
scenario_dict
[
'ANNOTATION_VERTICAL'
]
.
location
)
self
.
annotations_count
=
count
def
view_component
(
self
,
step
):
...
...
@@ -125,7 +122,6 @@ class AnnotatableSteps(object):
)
)
)
publish
(
world
.
scenario_dict
[
'ANNOTATION_VERTICAL'
]
.
location
)
def
click_reply
(
self
,
step
,
problem
):
r"""I click "Reply to annotation" on passage (?P<problem>\d+)$"""
...
...
lms/djangoapps/courseware/features/common.py
View file @
6fa96cf0
...
...
@@ -134,10 +134,6 @@ def section_location(course_num):
return
world
.
scenario_dict
[
'SECTION'
]
.
location
.
replace
(
course
=
course_num
)
def
publish
(
location
):
modulestore
()
.
publish
(
location
,
'**replace_user**'
)
def
visit_scenario_item
(
item_key
):
"""
Go to the courseware page containing the item stored in `world.scenario_dict`
...
...
lms/djangoapps/courseware/features/conditional.py
View file @
6fa96cf0
...
...
@@ -4,7 +4,7 @@
from
lettuce
import
world
,
steps
from
nose.tools
import
assert_in
,
assert_true
# pylint: disable=no-name-in-module
from
common
import
i_am_registered_for_the_course
,
visit_scenario_item
,
publish
from
common
import
i_am_registered_for_the_course
,
visit_scenario_item
from
problems_setup
import
add_problem_to_course
,
answer_problem
@steps
...
...
@@ -67,9 +67,6 @@ class ConditionalSteps(object):
data
=
'<html><div class="hidden-contents">Hidden Contents</p></html>'
)
publish
(
world
.
scenario_dict
[
'VERTICAL'
]
.
location
)
def
setup_problem_attempts
(
self
,
step
,
not_attempted
=
None
):
r'that the conditioned problem has (?P<not_attempted>not )?been attempted$'
visit_scenario_item
(
'CONDITION_SOURCE'
)
...
...
lms/djangoapps/courseware/features/gst.py
View file @
6fa96cf0
...
...
@@ -2,7 +2,7 @@
from
lettuce
import
world
,
steps
from
nose.tools
import
assert_in
,
assert_equals
,
assert_true
from
common
import
i_am_registered_for_the_course
,
visit_scenario_item
,
publish
from
common
import
i_am_registered_for_the_course
,
visit_scenario_item
from
problems_setup
import
add_problem_to_course
,
answer_problem
...
...
lms/djangoapps/courseware/management/commands/tests/test_dump_course.py
View file @
6fa96cf0
...
...
@@ -18,6 +18,7 @@ from courseware.tests.modulestore_config import TEST_DATA_XML_MODULESTORE
from
courseware.tests.modulestore_config
import
TEST_DATA_MIXED_MODULESTORE
from
courseware.tests.modulestore_config
import
TEST_DATA_MONGO_MODULESTORE
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
...
...
@@ -56,7 +57,7 @@ class CommandsTestBase(TestCase):
courses
=
store
.
get_courses
()
# NOTE: if xml store owns these, it won't import them into mongo
if
SlashSeparatedCourseKey
.
from_deprecated_string
(
TEST_COURSE_ID
)
not
in
[
c
.
id
for
c
in
courses
]:
import_from_xml
(
store
,
"**replace_user**"
,
DATA_DIR
,
[
'toy'
,
'simple'
])
import_from_xml
(
store
,
ModuleStoreEnum
.
UserID
.
mgmt_command
,
DATA_DIR
,
[
'toy'
,
'simple'
])
return
[
course
.
id
for
course
in
store
.
get_courses
()]
...
...
lms/djangoapps/courseware/tests/__init__.py
View file @
6fa96cf0
...
...
@@ -132,6 +132,7 @@ class BaseTestXmodule(ModuleStoreTestCase):
self
.
assertTrue
(
all
(
self
.
login_statuses
))
def
setUp
(
self
):
super
(
BaseTestXmodule
,
self
)
.
setUp
()
self
.
setup_course
()
self
.
initialize_module
(
metadata
=
self
.
METADATA
,
data
=
self
.
DATA
)
...
...
lms/djangoapps/courseware/tests/helpers.py
View file @
6fa96cf0
...
...
@@ -67,7 +67,7 @@ class LoginEnrollmentTestCase(TestCase):
self
.
email
=
'foo@test.com'
self
.
password
=
'bar'
self
.
username
=
'test'
self
.
create_account
(
self
.
username
,
self
.
user
=
self
.
create_account
(
self
.
username
,
self
.
email
,
self
.
password
)
self
.
activate_user
(
self
.
email
)
self
.
login
(
self
.
email
,
self
.
password
)
...
...
@@ -107,7 +107,9 @@ class LoginEnrollmentTestCase(TestCase):
data
=
json
.
loads
(
resp
.
content
)
self
.
assertEqual
(
data
[
'success'
],
True
)
# Check both that the user is created, and inactive
self
.
assertFalse
(
User
.
objects
.
get
(
email
=
email
)
.
is_active
)
user
=
User
.
objects
.
get
(
email
=
email
)
self
.
assertFalse
(
user
.
is_active
)
return
user
def
activate_user
(
self
,
email
):
"""
...
...
lms/djangoapps/courseware/tests/test_lti_integration.py
View file @
6fa96cf0
...
...
@@ -10,7 +10,8 @@ from django.test.utils import override_settings
from
django.core.urlresolvers
import
reverse
from
django.conf
import
settings
from
xmodule.modulestore.mongo.base
import
MongoRevisionKey
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.x_module
import
STUDENT_VIEW
...
...
@@ -160,7 +161,8 @@ class TestLTIModuleListing(ModuleStoreTestCase):
parent_location
=
self
.
section2
.
location
,
display_name
=
"lti draft"
,
category
=
"lti"
,
location
=
self
.
course
.
id
.
make_usage_key
(
'lti'
,
'lti_published'
)
.
replace
(
revision
=
MongoRevisionKey
.
draft
),
location
=
self
.
course
.
id
.
make_usage_key
(
'lti'
,
'lti_published'
),
publish_item
=
False
,
)
def
expected_handler_url
(
self
,
handler
):
...
...
lms/djangoapps/courseware/tests/test_submitting_problems.py
View file @
6fa96cf0
...
...
@@ -19,8 +19,6 @@ from django.test.utils import override_settings
from
courseware
import
grades
from
courseware.models
import
StudentModule
from
xmodule.modulestore.django
import
modulestore
#import factories and parent testcase modules
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
...
...
@@ -46,7 +44,7 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase):
def
setUp
(
self
):
super
(
TestSubmittingProblems
,
self
)
.
setUp
()
super
(
TestSubmittingProblems
,
self
)
.
setUp
(
create_user
=
False
)
# Create course
self
.
course
=
CourseFactory
.
create
(
display_name
=
self
.
COURSE_NAME
,
number
=
self
.
COURSE_SLUG
)
assert
self
.
course
,
"Couldn't load course
%
r"
%
self
.
COURSE_NAME
...
...
@@ -64,7 +62,7 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
Re-fetch the course from the database so that the object being dealt with has everything added to it.
"""
self
.
course
=
modulestore
()
.
get_course
(
self
.
course
.
id
)
self
.
course
=
self
.
store
.
get_course
(
self
.
course
.
id
)
def
problem_location
(
self
,
problem_url_name
):
"""
...
...
@@ -230,8 +228,7 @@ class TestCourseGrader(TestSubmittingProblems):
"""
self
.
course
.
grading_policy
=
grading_policy
store
=
modulestore
()
store
.
update_item
(
self
.
course
,
'**replace_user**'
)
self
.
update_course
(
self
.
course
,
self
.
student_user
.
id
)
self
.
refresh_course
()
def
get_grade_summary
(
self
):
...
...
lms/djangoapps/courseware/tests/test_video_handlers.py
View file @
6fa96cf0
...
...
@@ -12,6 +12,7 @@ from webob import Request
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.contentstore.django
import
contentstore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.x_module
import
STUDENT_VIEW
from
.
import
BaseTestXmodule
from
.test_video_xml
import
SOURCE_XML
...
...
@@ -411,7 +412,8 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
self
.
course
.
static_asset_path
=
'dummy/static'
self
.
course
.
save
()
store
=
modulestore
()
store
.
update_item
(
self
.
course
,
'OEoXaMPEzfM'
)
with
store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
self
.
course
.
id
):
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
# Test youtube style en
request
=
Request
.
blank
(
'/translation/en?videoId=12345'
)
...
...
lms/djangoapps/courseware/tests/test_view_authentication.py
View file @
6fa96cf0
...
...
@@ -110,6 +110,7 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
return
super
(
TestViewAuth
,
self
)
.
login
(
user
.
email
,
'test'
)
def
setUp
(
self
):
super
(
TestViewAuth
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
(
number
=
'999'
,
display_name
=
'Robot_Super_Course'
)
self
.
courseware_chapter
=
ItemFactory
.
create
(
display_name
=
'courseware'
)
...
...
@@ -296,8 +297,8 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
self
.
course
.
start
=
tomorrow
self
.
test_course
.
start
=
tomorrow
self
.
course
=
self
.
update_course
(
self
.
course
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
self
.
user
.
id
)
self
.
assertFalse
(
self
.
course
.
has_started
())
self
.
assertFalse
(
self
.
test_course
.
has_started
())
...
...
@@ -321,8 +322,8 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
tomorrow
=
now
+
datetime
.
timedelta
(
days
=
1
)
self
.
course
.
start
=
tomorrow
self
.
test_course
.
start
=
tomorrow
self
.
course
=
self
.
update_course
(
self
.
course
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
self
.
user
.
id
)
self
.
login
(
self
.
instructor_user
)
# Enroll in the classes---can't see courseware otherwise.
...
...
@@ -345,8 +346,8 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
self
.
course
.
start
=
tomorrow
self
.
test_course
.
start
=
tomorrow
self
.
course
=
self
.
update_course
(
self
.
course
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
self
.
user
.
id
)
self
.
login
(
self
.
global_staff_user
)
self
.
enroll
(
self
.
course
,
True
)
...
...
@@ -373,8 +374,8 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
# test_course course's has
self
.
test_course
.
enrollment_start
=
yesterday
self
.
test_course
.
enrollment_end
=
tomorrow
self
.
course
=
self
.
update_course
(
self
.
course
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
)
self
.
course
=
self
.
update_course
(
self
.
course
,
self
.
user
.
id
)
self
.
test_course
=
self
.
update_course
(
self
.
test_course
,
self
.
user
.
id
)
# First, try with an enrolled student
self
.
login
(
self
.
unenrolled_user
)
...
...
lms/djangoapps/courseware/tests/tests.py
View file @
6fa96cf0
...
...
@@ -142,9 +142,8 @@ class TestMongoCoursesLoad(ModuleStoreTestCase, PageLoaderTestCase):
super
(
TestMongoCoursesLoad
,
self
)
.
setUp
()
self
.
setup_user
()
# Import the toy course into a Mongo-backed modulestore
self
.
store
=
modulestore
()
import_from_xml
(
self
.
store
,
"**replace_user**"
,
TEST_DATA_DIR
,
[
'toy'
])
# Import the toy course
import_from_xml
(
self
.
store
,
self
.
user
.
id
,
TEST_DATA_DIR
,
[
'toy'
])
@mock.patch
(
'xmodule.course_module.requests.get'
)
def
test_toy_textbooks_loads
(
self
,
mock_get
):
...
...
lms/djangoapps/dashboard/management/commands/tests/test_git_add_course.py
View file @
6fa96cf0
...
...
@@ -15,10 +15,9 @@ from django.core.management.base import CommandError
from
django.test.utils
import
override_settings
from
courseware.tests.tests
import
TEST_DATA_MONGO_MODULESTORE
from
xmodule.
contentstore.django
import
contentstore
from
xmodule.
modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
xmodule.modulestore.store_utilities
import
delete_course
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
import
dashboard.git_import
as
git_import
from
dashboard.git_import
import
GitImportError
...
...
@@ -161,9 +160,7 @@ class TestGitAddCourse(ModuleStoreTestCase):
self
.
TEST_BRANCH
)
# Delete to test branching back to master
delete_course
(
def_ms
,
contentstore
(),
self
.
TEST_BRANCH_COURSE
,
True
)
def_ms
.
delete_course
(
self
.
TEST_BRANCH_COURSE
,
ModuleStoreEnum
.
UserID
.
test
)
self
.
assertIsNone
(
def_ms
.
get_course
(
self
.
TEST_BRANCH_COURSE
))
git_import
.
add_repo
(
self
.
TEST_REPO
,
repo_dir
/
'edx4edx_lite'
,
...
...
lms/djangoapps/dashboard/sysadmin.py
View file @
6fa96cf0
...
...
@@ -38,10 +38,8 @@ from external_auth.models import ExternalAuthMap
from
external_auth.views
import
generate_password
from
student.models
import
CourseEnrollment
,
UserProfile
,
Registration
import
track.views
from
xmodule.contentstore.django
import
contentstore
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.store_utilities
import
delete_course
from
xmodule.modulestore.xml
import
XMLModuleStore
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
...
...
@@ -591,9 +589,7 @@ class Courses(SysadminDashboardView):
elif
course_found
and
not
is_xml_course
:
# delete course that is stored with mongodb backend
content_store
=
contentstore
()
commit
=
True
delete_course
(
self
.
def_ms
,
content_store
,
course
.
id
,
commit
)
self
.
def_ms
.
delete_course
(
course
.
id
,
request
.
user
.
id
)
# don't delete user permission groups, though
self
.
msg
+=
\
u"<font color='red'>{0} {1} = {2} ({3})</font>"
.
format
(
...
...
lms/djangoapps/dashboard/tests/test_sysadmin.py
View file @
6fa96cf0
...
...
@@ -54,7 +54,7 @@ class SysadminBaseTestCase(ModuleStoreTestCase):
def
setUp
(
self
):
"""Setup test case by adding primary user."""
super
(
SysadminBaseTestCase
,
self
)
.
setUp
()
super
(
SysadminBaseTestCase
,
self
)
.
setUp
(
create_user
=
False
)
self
.
user
=
UserFactory
.
create
(
username
=
'test_user'
,
email
=
'test_user+sysadmin@edx.org'
,
password
=
'foo'
)
...
...
@@ -129,6 +129,9 @@ class TestSysadmin(SysadminBaseTestCase):
response
=
self
.
client
.
get
(
reverse
(
view
))
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
user
.
is_staff
=
False
self
.
user
.
save
()
logged_in
=
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
'foo'
)
self
.
assertTrue
(
logged_in
)
...
...
lms/djangoapps/django_comment_client/base/tests.py
View file @
6fa96cf0
...
...
@@ -41,7 +41,7 @@ class ViewsTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin):
# Patching the ENABLE_DISCUSSION_SERVICE value affects the contents of urls.py,
# so we need to call super.setUp() which reloads urls.py (because
# of the UrlResetMixin)
super
(
ViewsTestCase
,
self
)
.
setUp
()
super
(
ViewsTestCase
,
self
)
.
setUp
(
create_user
=
False
)
# create a course
self
.
course
=
CourseFactory
.
create
(
org
=
'MITx'
,
course
=
'999'
,
...
...
lms/djangoapps/instructor_task/tests/test_base.py
View file @
6fa96cf0
...
...
@@ -13,6 +13,7 @@ from django.contrib.auth.models import User
from
django.test.utils
import
override_settings
from
capa.tests.response_xml_factory
import
OptionResponseXMLFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
...
...
@@ -207,8 +208,10 @@ class InstructorTaskModuleTestCase(InstructorTaskCourseTestCase):
problem_xml
=
factory
.
build_xml
(
**
factory_args
)
location
=
InstructorTaskTestCase
.
problem_location
(
problem_url_name
)
item
=
self
.
module_store
.
get_item
(
location
)
with
self
.
module_store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
location
.
course_key
):
item
.
data
=
problem_xml
self
.
module_store
.
update_item
(
item
,
'**replace_user**'
)
self
.
module_store
.
update_item
(
item
,
self
.
user
.
id
)
self
.
module_store
.
publish
(
location
,
self
.
user
.
id
)
def
get_student_module
(
self
,
username
,
descriptor
):
"""Get StudentModule object for test course, given the `username` and the problem's `descriptor`."""
...
...
lms/djangoapps/instructor_task/tests/test_integration.py
View file @
6fa96cf0
...
...
@@ -17,6 +17,7 @@ from django.core.urlresolvers import reverse
from
capa.tests.response_xml_factory
import
(
CodeResponseXMLFactory
,
CustomResponseXMLFactory
)
from
xmodule.modulestore.tests.factories
import
ItemFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
courseware.model_data
import
StudentModule
...
...
@@ -105,6 +106,9 @@ class TestRescoringTask(TestIntegrationTask):
self
.
create_student
(
'u4'
)
self
.
logout
()
# set up test user for performing test operations
self
.
setup_user
()
def
render_problem
(
self
,
username
,
problem_url_name
):
"""
Use ajax interface to request html for a problem.
...
...
@@ -294,7 +298,9 @@ class TestRescoringTask(TestIntegrationTask):
InstructorTaskModuleTestCase
.
problem_location
(
problem_url_name
)
)
descriptor
.
data
=
problem_xml
self
.
module_store
.
update_item
(
descriptor
,
'**replace_user**'
)
with
self
.
module_store
.
branch_setting
(
ModuleStoreEnum
.
Branch
.
draft_preferred
,
descriptor
.
location
.
course_key
):
self
.
module_store
.
update_item
(
descriptor
,
self
.
user
.
id
)
self
.
module_store
.
publish
(
descriptor
.
location
,
self
.
user
.
id
)
else
:
# Use "per-student" rerandomization so that check-problem can be called more than once.
# Using "always" means we cannot check a problem twice, but we want to call once to get the
...
...
lms/envs/test.py
View file @
6fa96cf0
...
...
@@ -109,7 +109,6 @@ STATICFILES_DIRS += [
if
os
.
path
.
isdir
(
COMMON_TEST_DATA_ROOT
/
course_dir
)
]
MODULESTORE_BRANCH
=
'draft-preferred'
update_module_store_settings
(
MODULESTORE
,
module_store_options
=
{
...
...
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