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
d999d0af
Commit
d999d0af
authored
Jan 16, 2014
by
Don Mitchell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Detached categories don't access control on date
parent
e74ddf81
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
113 additions
and
37 deletions
+113
-37
cms/djangoapps/contentstore/views/item.py
+7
-9
common/lib/xmodule/xmodule/html_module.py
+7
-21
common/lib/xmodule/xmodule/modulestore/mongo/base.py
+3
-1
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+2
-1
common/lib/xmodule/xmodule/modulestore/tests/test_orphan.py
+2
-2
lms/djangoapps/courseware/access.py
+1
-2
lms/djangoapps/courseware/tests/test_about.py
+33
-0
lms/djangoapps/courseware/tests/test_course_info.py
+33
-0
lms/djangoapps/courseware/tests/test_tabs.py
+25
-1
No files found.
cms/djangoapps/contentstore/views/item.py
View file @
d999d0af
...
...
@@ -40,9 +40,6 @@ __all__ = ['orphan_handler', 'xblock_handler']
log
=
logging
.
getLogger
(
__name__
)
# cdodge: these are categories which should not be parented, they are detached from the hierarchy
DETACHED_CATEGORIES
=
[
'about'
,
'static_tab'
,
'course_info'
]
CREATE_IF_NOT_FOUND
=
[
'course_info'
]
...
...
@@ -297,10 +294,11 @@ def _create_item(request):
dest_location
,
definition_data
=
data
,
metadata
=
metadata
,
system
=
parent
.
system
,
system
=
parent
.
runtime
,
)
if
category
not
in
DETACHED_CATEGORIES
:
# TODO replace w/ nicer accessor
if
not
'detached'
in
parent
.
runtime
.
load_block_type
(
category
)
.
_class_tags
:
get_modulestore
(
parent
.
location
)
.
update_children
(
parent_location
,
parent
.
children
+
[
dest_location
.
url
()])
course_location
=
loc_mapper
()
.
translate_locator_to_location
(
parent_locator
,
get_course
=
True
)
...
...
@@ -329,7 +327,7 @@ def _duplicate_item(parent_location, duplicate_source_location, display_name=Non
dest_location
,
definition_data
=
source_item
.
data
if
hasattr
(
source_item
,
'data'
)
else
None
,
metadata
=
duplicate_metadata
,
system
=
source_item
.
system
if
hasattr
(
source_item
,
'system'
)
else
Non
e
,
system
=
source_item
.
runtim
e
,
)
# Children are not automatically copied over (and not all xblocks have a 'children' attribute).
...
...
@@ -340,7 +338,7 @@ def _duplicate_item(parent_location, duplicate_source_location, display_name=Non
copied_children
.
append
(
_duplicate_item
(
dest_location
,
Location
(
child
))
.
url
())
get_modulestore
(
dest_location
)
.
update_children
(
dest_location
,
copied_children
)
if
category
not
in
DETACHED_CATEGORIES
:
if
not
'detached'
in
source_item
.
runtime
.
load_block_type
(
category
)
.
_class_tags
:
parent
=
get_modulestore
(
parent_location
)
.
get_item
(
parent_location
)
# If source was already a child of the parent, add duplicate immediately afterward.
# Otherwise, add child to end.
...
...
@@ -404,12 +402,12 @@ def orphan_handler(request, tag=None, package_id=None, branch=None, version_guid
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
)
if
request
.
method
==
'GET'
:
if
has_course_access
(
request
.
user
,
old_location
):
return
JsonResponse
(
modulestore
()
.
get_orphans
(
old_location
,
DETACHED_CATEGORIES
,
'draft'
))
return
JsonResponse
(
modulestore
()
.
get_orphans
(
old_location
,
'draft'
))
else
:
raise
PermissionDenied
()
if
request
.
method
==
'DELETE'
:
if
request
.
user
.
is_staff
:
items
=
modulestore
()
.
get_orphans
(
old_location
,
DETACHED_CATEGORIES
,
'draft'
)
items
=
modulestore
()
.
get_orphans
(
old_location
,
'draft'
)
for
item
in
items
:
modulestore
(
'draft'
)
.
delete_item
(
item
,
True
)
return
JsonResponse
({
'deleted'
:
items
})
...
...
common/lib/xmodule/xmodule/html_module.py
View file @
d999d0af
...
...
@@ -3,14 +3,11 @@ from fs.errors import ResourceNotFoundError
import
logging
import
os
import
sys
from
datetime
import
datetime
from
lxml
import
etree
from
path
import
path
from
pytz
import
UTC
from
pkg_resources
import
resource_string
from
xblock.fields
import
Scope
,
String
,
Boolean
from
xmodule.fields
import
Date
from
xmodule.editing_module
import
EditingDescriptor
from
xmodule.html_checker
import
check_html
from
xmodule.stringify
import
stringify_children
...
...
@@ -18,6 +15,7 @@ from xmodule.x_module import XModule
from
xmodule.xml_module
import
XmlDescriptor
,
name_to_pathname
import
textwrap
from
xmodule.contentstore.content
import
StaticContent
from
xblock.core
import
XBlock
log
=
logging
.
getLogger
(
"edx.courseware"
)
...
...
@@ -230,14 +228,9 @@ class AboutFields(object):
default
=
""
,
scope
=
Scope
.
content
)
# this exists purely to override the default start date
start
=
Date
(
help
=
"placeholder to make sure that About is always active"
,
default
=
datetime
.
fromtimestamp
(
0
,
UTC
),
scope
=
Scope
.
settings
,
)
@XBlock.tag
(
"detached"
)
class
AboutModule
(
AboutFields
,
HtmlModule
):
"""
Overriding defaults but otherwise treated as HtmlModule.
...
...
@@ -245,6 +238,7 @@ class AboutModule(AboutFields, HtmlModule):
pass
@XBlock.tag
(
"detached"
)
class
AboutDescriptor
(
AboutFields
,
HtmlDescriptor
):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
...
...
@@ -271,14 +265,9 @@ class StaticTabFields(object):
scope
=
Scope
.
content
,
help
=
"HTML for the additional pages"
)
# this exists purely to override the default start date
start
=
Date
(
help
=
"placeholder to make sure that Static Tabs are always active"
,
default
=
datetime
.
fromtimestamp
(
0
,
UTC
),
scope
=
Scope
.
settings
,
)
@XBlock.tag
(
"detached"
)
class
StaticTabModule
(
StaticTabFields
,
HtmlModule
):
"""
Supports the field overrides
...
...
@@ -286,6 +275,7 @@ class StaticTabModule(StaticTabFields, HtmlModule):
pass
@XBlock.tag
(
"detached"
)
class
StaticTabDescriptor
(
StaticTabFields
,
HtmlDescriptor
):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
...
...
@@ -304,14 +294,9 @@ class CourseInfoFields(object):
default
=
"<ol></ol>"
,
scope
=
Scope
.
content
)
# this exists purely to override the default start date
start
=
Date
(
help
=
"placeholder to make sure that Course Info is always active"
,
default
=
datetime
.
fromtimestamp
(
0
,
UTC
),
scope
=
Scope
.
settings
,
)
@XBlock.tag
(
"detached"
)
class
CourseInfoModule
(
CourseInfoFields
,
HtmlModule
):
"""
Just to support xblock field overrides
...
...
@@ -319,6 +304,7 @@ class CourseInfoModule(CourseInfoFields, HtmlModule):
pass
@XBlock.tag
(
"detached"
)
class
CourseInfoDescriptor
(
CourseInfoFields
,
HtmlDescriptor
):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
...
...
common/lib/xmodule/xmodule/modulestore/mongo/base.py
View file @
d999d0af
...
...
@@ -34,6 +34,7 @@ from xmodule.modulestore import ModuleStoreWriteBase, Location, MONGO_MODULESTOR
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.inheritance
import
own_metadata
,
InheritanceMixin
,
inherit_metadata
,
InheritanceKeyValueStore
from
xmodule.modulestore.xml
import
LocationReader
from
xblock.core
import
XBlock
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -869,10 +870,11 @@ class MongoModuleStore(ModuleStoreWriteBase):
"""
return
MONGO_MODULESTORE_TYPE
def
get_orphans
(
self
,
course_location
,
detached_categories
,
_branch
):
def
get_orphans
(
self
,
course_location
,
_branch
):
"""
Return an array all of the locations for orphans in the course.
"""
detached_categories
=
[
name
for
name
,
__
in
XBlock
.
load_tagged_classes
(
"detached"
)]
all_items
=
self
.
collection
.
find
({
'_id.org'
:
course_location
.
org
,
'_id.course'
:
course_location
.
course
,
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
d999d0af
...
...
@@ -439,12 +439,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
)
for
parent_id
in
items
]
def
get_orphans
(
self
,
package_id
,
detached_categories
,
branch
):
def
get_orphans
(
self
,
package_id
,
branch
):
"""
Return a dict of all of the orphans in the course.
:param package_id:
"""
detached_categories
=
[
name
for
name
,
__
in
XBlock
.
load_tagged_classes
(
"detached"
)]
course
=
self
.
_lookup_course
(
CourseLocator
(
package_id
=
package_id
,
branch
=
branch
))
items
=
{
LocMapperStore
.
decode_key_from_mongo
(
block_id
)
for
block_id
in
course
[
'structure'
][
'blocks'
]
.
keys
()}
items
.
remove
(
course
[
'structure'
][
'root'
])
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_orphan.py
View file @
d999d0af
...
...
@@ -135,7 +135,7 @@ class TestOrphan(unittest.TestCase):
"""
Test that old mongo finds the orphans
"""
orphans
=
self
.
old_mongo
.
get_orphans
(
self
.
course_location
,
[
'static_tab'
,
'about'
,
'course_info'
],
None
)
orphans
=
self
.
old_mongo
.
get_orphans
(
self
.
course_location
,
None
)
self
.
assertEqual
(
len
(
orphans
),
3
,
"Wrong # {}"
.
format
(
orphans
))
location
=
self
.
course_location
.
replace
(
category
=
'chapter'
,
name
=
'OrphanChapter'
)
self
.
assertIn
(
location
.
url
(),
orphans
)
...
...
@@ -148,7 +148,7 @@ class TestOrphan(unittest.TestCase):
"""
Test that old mongo finds the orphans
"""
orphans
=
self
.
split_mongo
.
get_orphans
(
self
.
split_package_id
,
[
'static_tab'
,
'about'
,
'course_info'
],
'draft'
)
orphans
=
self
.
split_mongo
.
get_orphans
(
self
.
split_package_id
,
'draft'
)
self
.
assertEqual
(
len
(
orphans
),
3
,
"Wrong # {}"
.
format
(
orphans
))
location
=
BlockUsageLocator
(
package_id
=
self
.
split_package_id
,
branch
=
'draft'
,
block_id
=
'OrphanChapter'
)
self
.
assertIn
(
location
,
orphans
)
...
...
lms/djangoapps/courseware/access.py
View file @
d999d0af
...
...
@@ -24,7 +24,6 @@ from student.roles import (
GlobalStaff
,
CourseStaffRole
,
CourseInstructorRole
,
OrgStaffRole
,
OrgInstructorRole
,
CourseBetaTesterRole
)
DEBUG_ACCESS
=
False
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -246,7 +245,7 @@ def _has_access_descriptor(user, descriptor, action, course_context=None):
return
True
# Check start date
if
descriptor
.
start
is
not
None
:
if
'detached'
not
in
descriptor
.
_class_tags
and
descriptor
.
start
is
not
None
:
now
=
datetime
.
now
(
UTC
())
effective_start
=
_adjust_start_date_for_beta_testers
(
user
,
...
...
lms/djangoapps/courseware/tests/test_about.py
0 → 100644
View file @
d999d0af
"""
Test the about xblock
"""
from
django.test.utils
import
override_settings
from
django.core.urlresolvers
import
reverse
from
.helpers
import
LoginEnrollmentTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
courseware.tests.modulestore_config
import
TEST_DATA_MIXED_MODULESTORE
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
class
AboutTestCase
(
LoginEnrollmentTestCase
,
ModuleStoreTestCase
):
def
setUp
(
self
):
self
.
course
=
CourseFactory
.
create
()
self
.
about
=
ItemFactory
.
create
(
category
=
"about"
,
parent_location
=
self
.
course
.
location
,
data
=
"OOGIE BLOOGIE"
,
display_name
=
"overview"
)
def
test_logged_in
(
self
):
self
.
setup_user
()
url
=
reverse
(
'about_course'
,
args
=
[
self
.
course
.
id
])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
def
test_anonymous_user
(
self
):
url
=
reverse
(
'about_course'
,
args
=
[
self
.
course
.
id
])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
lms/djangoapps/courseware/tests/test_course_info.py
0 → 100644
View file @
d999d0af
"""
Test the course_info xblock
"""
from
django.test.utils
import
override_settings
from
django.core.urlresolvers
import
reverse
from
.helpers
import
LoginEnrollmentTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
courseware.tests.modulestore_config
import
TEST_DATA_MIXED_MODULESTORE
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
class
CourseInfoTestCase
(
LoginEnrollmentTestCase
,
ModuleStoreTestCase
):
def
setUp
(
self
):
self
.
course
=
CourseFactory
.
create
()
self
.
page
=
ItemFactory
.
create
(
category
=
"course_info"
,
parent_location
=
self
.
course
.
location
,
data
=
"OOGIE BLOOGIE"
,
display_name
=
"updates"
)
def
test_logged_in
(
self
):
self
.
setup_user
()
url
=
reverse
(
'info'
,
args
=
[
self
.
course
.
id
])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
def
test_anonymous_user
(
self
):
url
=
reverse
(
'info'
,
args
=
[
self
.
course
.
id
])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertNotIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
lms/djangoapps/courseware/tests/test_tabs.py
View file @
d999d0af
...
...
@@ -8,8 +8,9 @@ from django.test.utils import override_settings
from
django.core.urlresolvers
import
reverse
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
courseware.tests.modulestore_config
import
TEST_DATA_MIXED_MODULESTORE
from
.helpers
import
LoginEnrollmentTestCase
FAKE_REQUEST
=
None
...
...
@@ -146,6 +147,29 @@ class StaticTabTestCase(TestCase):
)
self
.
assertEqual
(
tab_list
[
0
]
.
is_active
,
False
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
class
StaticTabDateTestCase
(
LoginEnrollmentTestCase
,
ModuleStoreTestCase
):
def
setUp
(
self
):
self
.
course
=
CourseFactory
.
create
()
self
.
page
=
ItemFactory
.
create
(
category
=
"static_tab"
,
parent_location
=
self
.
course
.
location
,
data
=
"OOGIE BLOOGIE"
,
display_name
=
"new_tab"
)
def
test_logged_in
(
self
):
self
.
setup_user
()
url
=
reverse
(
'static_tab'
,
args
=
[
self
.
course
.
id
,
'new_tab'
])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
def
test_anonymous_user
(
self
):
url
=
reverse
(
'static_tab'
,
args
=
[
self
.
course
.
id
,
'new_tab'
])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
class
TextbooksTestCase
(
TestCase
):
def
setUp
(
self
):
...
...
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