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
cd868efc
Commit
cd868efc
authored
Nov 06, 2013
by
Christina Roberts
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1580 from edx/christina/item
Change delete_item to RESTful URL.
parents
f17ab1ec
16766a5e
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
155 additions
and
89 deletions
+155
-89
cms/djangoapps/auth/authz.py
+5
-1
cms/djangoapps/contentstore/tests/test_contentstore.py
+13
-21
cms/djangoapps/contentstore/tests/test_item.py
+3
-6
cms/djangoapps/contentstore/views/component.py
+15
-4
cms/djangoapps/contentstore/views/item.py
+37
-19
cms/djangoapps/contentstore/views/tabs.py
+7
-1
cms/static/coffee/src/views/module_edit.coffee
+1
-0
cms/static/coffee/src/views/tabs.coffee
+4
-3
cms/static/coffee/src/views/unit.coffee
+8
-7
cms/static/js/base.js
+5
-6
cms/templates/edit-tabs.html
+2
-2
cms/templates/overview.html
+15
-2
cms/templates/unit.html
+3
-3
cms/templates/widgets/units.html
+9
-2
cms/urls.py
+1
-2
common/djangoapps/util/json_request.py
+1
-1
common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py
+14
-2
common/lib/xmodule/xmodule/modulestore/locator.py
+1
-1
common/lib/xmodule/xmodule/modulestore/mongo/draft.py
+5
-5
common/lib/xmodule/xmodule/modulestore/tests/test_location_mapper.py
+5
-1
common/lib/xmodule/xmodule/modulestore/xml_exporter.py
+1
-0
No files found.
cms/djangoapps/auth/authz.py
View file @
cd868efc
...
@@ -11,6 +11,7 @@ from django.conf import settings
...
@@ -11,6 +11,7 @@ from django.conf import settings
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.locator
import
CourseLocator
,
Locator
from
xmodule.modulestore.locator
import
CourseLocator
,
Locator
from
xmodule.modulestore.django
import
loc_mapper
from
xmodule.modulestore.django
import
loc_mapper
from
xmodule.modulestore.exceptions
import
InvalidLocationError
# define a couple of simple roles, we just need ADMIN and EDITOR now for our purposes
# define a couple of simple roles, we just need ADMIN and EDITOR now for our purposes
...
@@ -32,11 +33,14 @@ def get_course_groupname_for_role(location, role):
...
@@ -32,11 +33,14 @@ def get_course_groupname_for_role(location, role):
# if it exists, then use that one, otherwise use a <role>_<course_id> which contains
# if it exists, then use that one, otherwise use a <role>_<course_id> which contains
# more information
# more information
groupnames
=
[]
groupnames
=
[]
try
:
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
location
.
course_id
))
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
location
.
course_id
))
except
InvalidLocationError
:
# will occur on old locations where location is not of category course
pass
if
isinstance
(
location
,
Location
):
if
isinstance
(
location
,
Location
):
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
location
.
course
))
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
location
.
course
))
elif
isinstance
(
location
,
CourseLocator
):
elif
isinstance
(
location
,
CourseLocator
):
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
)
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
,
get_course
=
True
)
if
old_location
:
if
old_location
:
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
old_location
.
course_id
))
groupnames
.
append
(
'{0}_{1}'
.
format
(
role
,
old_location
.
course_id
))
...
...
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
cd868efc
...
@@ -488,11 +488,8 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
...
@@ -488,11 +488,8 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# make sure the parent points to the child object which is to be deleted
# make sure the parent points to the child object which is to be deleted
self
.
assertTrue
(
sequential
.
location
.
url
()
in
chapter
.
children
)
self
.
assertTrue
(
sequential
.
location
.
url
()
in
chapter
.
children
)
self
.
client
.
post
(
location
=
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
sequential
.
location
,
False
,
True
)
reverse
(
'delete_item'
),
self
.
client
.
delete
(
location
.
url_reverse
(
'xblock'
),
{
'recurse'
:
True
,
'all_versions'
:
True
})
json
.
dumps
({
'id'
:
sequential
.
location
.
url
(),
'delete_children'
:
'true'
,
'delete_all_versions'
:
'true'
}),
"application/json"
)
found
=
False
found
=
False
try
:
try
:
...
@@ -1640,29 +1637,24 @@ class ContentStoreTest(ModuleStoreTestCase):
...
@@ -1640,29 +1637,24 @@ class ContentStoreTest(ModuleStoreTestCase):
kwargs
=
{
'location'
:
unit_location
.
url
()}))
kwargs
=
{
'location'
:
unit_location
.
url
()}))
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# delete a component
def
delete_item
(
category
,
name
):
del_loc
=
loc
.
replace
(
category
=
'html'
,
name
=
'test_html'
)
""" Helper method for testing the deletion of an xblock item. """
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
del_loc
=
loc
.
replace
(
category
=
category
,
name
=
name
)
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
del_location
=
loc_mapper
()
.
translate_location
(
loc
.
course_id
,
del_loc
,
False
,
True
)
resp
=
self
.
client
.
delete
(
del_location
.
url_reverse
(
'xblock'
))
self
.
assertEqual
(
resp
.
status_code
,
204
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
# delete a component
delete_item
(
category
=
'html'
,
name
=
'test_html'
)
# delete a unit
# delete a unit
del_loc
=
loc
.
replace
(
category
=
'vertical'
,
name
=
'test_vertical'
)
delete_item
(
category
=
'vertical'
,
name
=
'test_vertical'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
# delete a unit
# delete a unit
del_loc
=
loc
.
replace
(
category
=
'sequential'
,
name
=
'test_sequence'
)
delete_item
(
category
=
'sequential'
,
name
=
'test_sequence'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
# delete a chapter
# delete a chapter
del_loc
=
loc
.
replace
(
category
=
'chapter'
,
name
=
'chapter_2'
)
delete_item
(
category
=
'chapter'
,
name
=
'chapter_2'
)
resp
=
self
.
client
.
post
(
reverse
(
'delete_item'
),
json
.
dumps
({
'id'
:
del_loc
.
url
()}),
"application/json"
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
def
test_import_into_new_course_id
(
self
):
def
test_import_into_new_course_id
(
self
):
module_store
=
modulestore
(
'direct'
)
module_store
=
modulestore
(
'direct'
)
...
...
cms/djangoapps/contentstore/tests/test_item.py
View file @
cd868efc
...
@@ -12,7 +12,7 @@ from xmodule.modulestore.django import modulestore
...
@@ -12,7 +12,7 @@ from xmodule.modulestore.django import modulestore
class
DeleteItem
(
CourseTestCase
):
class
DeleteItem
(
CourseTestCase
):
"""Tests for '/
delete_item'
url."""
"""Tests for '/
xblock' DELETE
url."""
def
setUp
(
self
):
def
setUp
(
self
):
""" Creates the test course with a static page in it. """
""" Creates the test course with a static page in it. """
super
(
DeleteItem
,
self
)
.
setUp
()
super
(
DeleteItem
,
self
)
.
setUp
()
...
@@ -33,11 +33,8 @@ class DeleteItem(CourseTestCase):
...
@@ -33,11 +33,8 @@ class DeleteItem(CourseTestCase):
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# Now delete it. There was a bug that the delete was failing (static tabs do not exist in draft modulestore).
# Now delete it. There was a bug that the delete was failing (static tabs do not exist in draft modulestore).
resp
=
self
.
client
.
post
(
resp_content
=
json
.
loads
(
resp
.
content
)
reverse
(
'delete_item'
),
resp
=
self
.
client
.
delete
(
resp_content
[
'update_url'
])
resp
.
content
,
"application/json"
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
self
.
assertEqual
(
resp
.
status_code
,
204
)
...
...
cms/djangoapps/contentstore/views/component.py
View file @
cd868efc
...
@@ -16,6 +16,7 @@ from mitxmako.shortcuts import render_to_response
...
@@ -16,6 +16,7 @@ from mitxmako.shortcuts import render_to_response
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.util.date_utils
import
get_default_time_display
from
xmodule.util.date_utils
import
get_default_time_display
from
xmodule.modulestore.django
import
loc_mapper
from
xblock.fields
import
Scope
from
xblock.fields
import
Scope
from
util.json_request
import
expect_json
,
JsonResponse
from
util.json_request
import
expect_json
,
JsonResponse
...
@@ -174,6 +175,12 @@ def edit_unit(request, location):
...
@@ -174,6 +175,12 @@ def edit_unit(request, location):
course_id
=
course
.
location
.
course_id
course_id
=
course
.
location
.
course_id
)
)
# Note that the unit_state (draft, public, private) does not match up with the published value
# passed to translate_location. The two concepts are different at this point.
unit_update_url
=
loc_mapper
()
.
translate_location
(
course
.
location
.
course_id
,
Location
(
location
),
False
,
True
)
.
url_reverse
(
"xblock"
,
""
)
component_templates
=
defaultdict
(
list
)
component_templates
=
defaultdict
(
list
)
for
category
in
COMPONENT_TYPES
:
for
category
in
COMPONENT_TYPES
:
component_class
=
load_mixed_class
(
category
)
component_class
=
load_mixed_class
(
category
)
...
@@ -238,7 +245,12 @@ def edit_unit(request, location):
...
@@ -238,7 +245,12 @@ def edit_unit(request, location):
)
)
components
=
[
components
=
[
component
.
location
.
url
()
[
component
.
location
.
url
(),
loc_mapper
()
.
translate_location
(
course
.
location
.
course_id
,
component
.
location
,
False
,
True
)
.
url_reverse
(
"xblock"
)
]
for
component
for
component
in
item
.
get_children
()
in
item
.
get_children
()
]
]
...
@@ -283,12 +295,11 @@ def edit_unit(request, location):
...
@@ -283,12 +295,11 @@ def edit_unit(request, location):
index
=
index
index
=
index
)
)
unit_state
=
compute_unit_state
(
item
)
return
render_to_response
(
'unit.html'
,
{
return
render_to_response
(
'unit.html'
,
{
'context_course'
:
course
,
'context_course'
:
course
,
'unit'
:
item
,
'unit'
:
item
,
'unit_location'
:
location
,
'unit_location'
:
location
,
'unit_update_url'
:
unit_update_url
,
'components'
:
components
,
'components'
:
components
,
'component_templates'
:
component_templates
,
'component_templates'
:
component_templates
,
'draft_preview_link'
:
preview_lms_link
,
'draft_preview_link'
:
preview_lms_link
,
...
@@ -300,7 +311,7 @@ def edit_unit(request, location):
...
@@ -300,7 +311,7 @@ def edit_unit(request, location):
),
),
'section'
:
containing_section
,
'section'
:
containing_section
,
'new_unit_category'
:
'vertical'
,
'new_unit_category'
:
'vertical'
,
'unit_state'
:
unit_state
,
'unit_state'
:
compute_unit_state
(
item
)
,
'published_date'
:
(
'published_date'
:
(
get_default_time_display
(
item
.
published_date
)
get_default_time_display
(
item
.
published_date
)
if
item
.
published_date
is
not
None
else
None
if
item
.
published_date
is
not
None
else
None
...
...
cms/djangoapps/contentstore/views/item.py
View file @
cd868efc
...
@@ -16,16 +16,16 @@ from util.json_request import expect_json, JsonResponse
...
@@ -16,16 +16,16 @@ from util.json_request import expect_json, JsonResponse
from
..transcripts_utils
import
manage_video_subtitles_save
from
..transcripts_utils
import
manage_video_subtitles_save
from
..utils
import
get_modulestore
from
..utils
import
get_modulestore
,
get_course_for_item
from
.access
import
has_access
from
.access
import
has_access
from
.helpers
import
_xmodule_recurse
from
.helpers
import
_xmodule_recurse
from
xmodule.x_module
import
XModuleDescriptor
from
xmodule.x_module
import
XModuleDescriptor
from
django.views.decorators.http
import
require_http_methods
from
django.views.decorators.http
import
require_http_methods
from
xmodule.modulestore.locator
import
CourseLocator
,
BlockUsageLocator
from
xmodule.modulestore.locator
import
BlockUsageLocator
from
student.models
import
CourseEnrollment
from
student.models
import
CourseEnrollment
__all__
=
[
'save_item'
,
'create_item'
,
'
delete_item'
,
'orphan
'
]
__all__
=
[
'save_item'
,
'create_item'
,
'
orphan'
,
'xblock_handler
'
]
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -33,6 +33,31 @@ log = logging.getLogger(__name__)
...
@@ -33,6 +33,31 @@ log = logging.getLogger(__name__)
DETACHED_CATEGORIES
=
[
'about'
,
'static_tab'
,
'course_info'
]
DETACHED_CATEGORIES
=
[
'about'
,
'static_tab'
,
'course_info'
]
@require_http_methods
((
"DELETE"
))
@login_required
@expect_json
def
xblock_handler
(
request
,
tag
=
None
,
course_id
=
None
,
branch
=
None
,
version_guid
=
None
,
block
=
None
):
"""
The restful handler for xblock requests.
DELETE
json: delete this xblock instance from the course. Supports query parameters "recurse" to delete
all children and "all_versions" to delete from all (mongo) versions.
"""
if
request
.
method
==
'DELETE'
:
location
=
BlockUsageLocator
(
course_id
=
course_id
,
branch
=
branch
,
version_guid
=
version_guid
,
usage_id
=
block
)
if
not
has_access
(
request
.
user
,
location
):
raise
PermissionDenied
()
old_location
=
loc_mapper
()
.
translate_locator_to_location
(
location
)
delete_children
=
bool
(
request
.
REQUEST
.
get
(
'recurse'
,
False
))
delete_all_versions
=
bool
(
request
.
REQUEST
.
get
(
'all_versions'
,
False
))
_delete_item_at_location
(
old_location
,
delete_children
,
delete_all_versions
)
return
JsonResponse
()
@login_required
@login_required
@expect_json
@expect_json
def
save_item
(
request
):
def
save_item
(
request
):
...
@@ -171,24 +196,18 @@ def create_item(request):
...
@@ -171,24 +196,18 @@ def create_item(request):
if
category
not
in
DETACHED_CATEGORIES
:
if
category
not
in
DETACHED_CATEGORIES
:
get_modulestore
(
parent
.
location
)
.
update_children
(
parent_location
,
parent
.
children
+
[
dest_location
.
url
()])
get_modulestore
(
parent
.
location
)
.
update_children
(
parent_location
,
parent
.
children
+
[
dest_location
.
url
()])
return
JsonResponse
({
'id'
:
dest_location
.
url
()})
locator
=
loc_mapper
()
.
translate_location
(
get_course_for_item
(
parent_location
)
.
location
.
course_id
,
dest_location
,
False
,
True
)
return
JsonResponse
({
'id'
:
dest_location
.
url
(),
"update_url"
:
locator
.
url_reverse
(
"xblock"
)})
@login_required
def
_delete_item_at_location
(
item_location
,
delete_children
=
False
,
delete_all_versions
=
False
):
@expect_json
"""
def
delete_item
(
request
):
Deletes the item at with the given Location.
"""View for removing items."""
item_location
=
request
.
json
[
'id'
]
item_location
=
Location
(
item_location
)
# check permissions for this user within this course
if
not
has_access
(
request
.
user
,
item_location
):
raise
PermissionDenied
()
# optional parameter to delete all children (default False)
delete_children
=
request
.
json
.
get
(
'delete_children'
,
False
)
delete_all_versions
=
request
.
json
.
get
(
'delete_all_versions'
,
False
)
It is assumed that course permissions have already been checked.
"""
store
=
get_modulestore
(
item_location
)
store
=
get_modulestore
(
item_location
)
item
=
store
.
get_item
(
item_location
)
item
=
store
.
get_item
(
item_location
)
...
@@ -211,7 +230,6 @@ def delete_item(request):
...
@@ -211,7 +230,6 @@ def delete_item(request):
parent
.
children
=
children
parent
.
children
=
children
modulestore
(
'direct'
)
.
update_children
(
parent
.
location
,
parent
.
children
)
modulestore
(
'direct'
)
.
update_children
(
parent
.
location
,
parent
.
children
)
return
JsonResponse
()
# pylint: disable=W0613
# pylint: disable=W0613
@login_required
@login_required
...
...
cms/djangoapps/contentstore/views/tabs.py
View file @
cd868efc
...
@@ -12,6 +12,7 @@ from mitxmako.shortcuts import render_to_response
...
@@ -12,6 +12,7 @@ from mitxmako.shortcuts import render_to_response
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
loc_mapper
from
..utils
import
get_course_for_item
,
get_modulestore
from
..utils
import
get_course_for_item
,
get_modulestore
...
@@ -117,7 +118,12 @@ def edit_tabs(request, org, course, coursename):
...
@@ -117,7 +118,12 @@ def edit_tabs(request, org, course, coursename):
static_tabs
.
append
(
modulestore
(
'direct'
)
.
get_item
(
static_tab_loc
))
static_tabs
.
append
(
modulestore
(
'direct'
)
.
get_item
(
static_tab_loc
))
components
=
[
components
=
[
static_tab
.
location
.
url
()
[
static_tab
.
location
.
url
(),
loc_mapper
()
.
translate_location
(
course_item
.
location
.
course_id
,
static_tab
.
location
,
False
,
True
)
.
url_reverse
(
"xblock"
)
]
for
static_tab
for
static_tab
in
static_tabs
in
static_tabs
]
]
...
...
cms/static/coffee/src/views/module_edit.coffee
View file @
cd868efc
...
@@ -70,6 +70,7 @@ define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
...
@@ -70,6 +70,7 @@ define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
(
data
)
=>
(
data
)
=>
@
model
.
set
(
id
:
data
.
id
)
@
model
.
set
(
id
:
data
.
id
)
@
$el
.
data
(
'id'
,
data
.
id
)
@
$el
.
data
(
'id'
,
data
.
id
)
@
$el
.
data
(
'update_url'
,
data
.
update_url
)
@
render
()
@
render
()
)
)
...
...
cms/static/coffee/src/views/tabs.coffee
View file @
cd868efc
...
@@ -82,9 +82,10 @@ define ["jquery", "jquery.ui", "backbone", "js/views/feedback_prompt", "js/views
...
@@ -82,9 +82,10 @@ define ["jquery", "jquery.ui", "backbone", "js/views/feedback_prompt", "js/views
deleting
=
new
NotificationView
.
Mini
deleting
=
new
NotificationView
.
Mini
title
:
gettext
(
'Deleting…'
)
title
:
gettext
(
'Deleting…'
)
deleting
.
show
()
deleting
.
show
()
$
.
postJSON
(
'/delete_item'
,
{
$
.
ajax
({
id
:
$component
.
data
(
'id'
)
type
:
'DELETE'
,
},
=>
url
:
$component
.
data
(
'update_url'
)
}).
success
(
=>
$component
.
remove
()
$component
.
remove
()
deleting
.
hide
()
deleting
.
hide
()
)
)
...
...
cms/static/coffee/src/views/unit.coffee
View file @
cd868efc
...
@@ -134,9 +134,10 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
...
@@ -134,9 +134,10 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
title
:
gettext
(
'Deleting…'
),
title
:
gettext
(
'Deleting…'
),
deleting
.
show
()
deleting
.
show
()
$component
=
$
(
event
.
currentTarget
).
parents
(
'.component'
)
$component
=
$
(
event
.
currentTarget
).
parents
(
'.component'
)
$
.
postJSON
(
'/delete_item'
,
{
$
.
ajax
({
id
:
$component
.
data
(
'id'
)
type
:
'DELETE'
,
},
=>
url
:
$component
.
data
(
'update_url'
)
}).
success
(
=>
deleting
.
hide
()
deleting
.
hide
()
analytics
.
track
"Deleted a Component"
,
analytics
.
track
"Deleted a Component"
,
course
:
course_location_analytics
course
:
course_location_analytics
...
@@ -162,11 +163,11 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
...
@@ -162,11 +163,11 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
deleteDraft
:
(
event
)
->
deleteDraft
:
(
event
)
->
@
wait
(
true
)
@
wait
(
true
)
$
.
ajax
({
type
:
'DELETE'
,
url
:
@
$el
.
data
(
'update_url'
)
+
"?"
+
$
.
param
({
recurse
:
true
})
}).
success
(
=>
$
.
postJSON
(
'/delete_item'
,
{
id
:
@
$el
.
data
(
'id'
)
delete_children
:
true
},
=>
analytics
.
track
"Deleted Draft"
,
analytics
.
track
"Deleted Draft"
,
course
:
course_location_analytics
course
:
course_location_analytics
unit_id
:
unit_location_analytics
unit_id
:
unit_location_analytics
...
...
cms/static/js/base.js
View file @
cd868efc
...
@@ -279,15 +279,14 @@ function _deleteItem($el, type) {
...
@@ -279,15 +279,14 @@ function _deleteItem($el, type) {
});
});
deleting
.
show
();
deleting
.
show
();
$
.
postJSON
(
'/delete_item'
,
$
.
ajax
({
{
'id'
:
id
,
type
:
'DELETE'
,
'delete_children'
:
true
,
url
:
$el
.
data
(
'update_url'
)
+
'?'
+
$
.
param
({
recurse
:
true
,
all_versions
:
true
}),
'delete_all_versions'
:
true
},
success
:
function
()
{
function
(
data
)
{
$el
.
remove
();
$el
.
remove
();
deleting
.
hide
();
deleting
.
hide
();
}
}
);
}
);
}
}
},
},
secondary
:
{
secondary
:
{
...
...
cms/templates/edit-tabs.html
View file @
cd868efc
...
@@ -61,8 +61,8 @@ require(["coffee/src/views/tabs", "coffee/src/models/module"], function(TabsEdit
...
@@ -61,8 +61,8 @@ require(["coffee/src/views/tabs", "coffee/src/models/module"], function(TabsEdit
<div
class=
"tab-list"
>
<div
class=
"tab-list"
>
<ol
class=
'components'
>
<ol
class=
'components'
>
% for id in components:
% for id
, update_url
in components:
<li
class=
"component"
data-id=
"${id}"
/>
<li
class=
"component"
data-id=
"${id}"
data-update_url=
"${update_url}"
/>
% endfor
% endfor
<li
class=
"new-component-item"
>
<li
class=
"new-component-item"
>
...
...
cms/templates/overview.html
View file @
cd868efc
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
from
xmodule
.
util
import
date_utils
from
xmodule
.
util
import
date_utils
from
django
.
utils
.
translation
import
ugettext
as
_
from
django
.
utils
.
translation
import
ugettext
as
_
from
django
.
core
.
urlresolvers
import
reverse
from
django
.
core
.
urlresolvers
import
reverse
from
xmodule
.
modulestore
.
django
import
loc_mapper
%
>
%
>
<
%
block
name=
"title"
>
${_("Course Outline")}
</
%
block>
<
%
block
name=
"title"
>
${_("Course Outline")}
</
%
block>
<
%
block
name=
"bodyclass"
>
is-signedin course view-outline
</
%
block>
<
%
block
name=
"bodyclass"
>
is-signedin course view-outline
</
%
block>
...
@@ -141,7 +142,13 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v
...
@@ -141,7 +142,13 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v
<div
class=
"wrapper-dnd"
>
<div
class=
"wrapper-dnd"
>
<article
class=
"courseware-overview"
data-id=
"${context_course.location.url()}"
>
<article
class=
"courseware-overview"
data-id=
"${context_course.location.url()}"
>
% for section in sections:
% for section in sections:
<section
class=
"courseware-section branch is-draggable"
data-id=
"${section.location}"
data-parent-id=
"${context_course.location.url()}"
>
<
%
section_update_url =
loc_mapper().translate_location(
context_course
.
location
.
course_id
,
section
.
location
,
False
,
True
).
url_reverse
('
xblock
')
%
>
<section
class=
"courseware-section branch is-draggable"
data-id=
"${section.location}"
data-parent-id=
"${context_course.location.url()}"
data-update_url=
"${section_update_url}"
>
<
%
include
file=
"widgets/_ui-dnd-indicator-before.html"
/>
<
%
include
file=
"widgets/_ui-dnd-indicator-before.html"
/>
...
@@ -184,7 +191,13 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v
...
@@ -184,7 +191,13 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v
</div>
</div>
<ol
class=
"sortable-subsection-list"
data-id=
"${section.location.url()}"
>
<ol
class=
"sortable-subsection-list"
data-id=
"${section.location.url()}"
>
% for subsection in section.get_children():
% for subsection in section.get_children():
<li
class=
"courseware-subsection branch collapsed id-holder is-draggable"
data-id=
"${subsection.location}"
data-parent-id=
"${section.location.url()}"
>
<
%
subsection_update_url =
loc_mapper().translate_location(
context_course
.
location
.
course_id
,
subsection
.
location
,
False
,
True
).
url_reverse
('
xblock
')
%
>
<li
class=
"courseware-subsection branch collapsed id-holder is-draggable"
data-id=
"${subsection.location}"
data-parent-id=
"${section.location.url()}"
data-update_url=
"${subsection_update_url}"
>
<
%
include
file=
"widgets/_ui-dnd-indicator-before.html"
/>
<
%
include
file=
"widgets/_ui-dnd-indicator-before.html"
/>
...
...
cms/templates/unit.html
View file @
cd868efc
...
@@ -34,7 +34,7 @@ require(["domReady!", "jquery", "coffee/src/models/module", "coffee/src/views/un
...
@@ -34,7 +34,7 @@ require(["domReady!", "jquery", "coffee/src/models/module", "coffee/src/views/un
</
%
block>
</
%
block>
<
%
block
name=
"content"
>
<
%
block
name=
"content"
>
<div
class=
"main-wrapper edit-state-${unit_state}"
data-id=
"${unit_location}"
>
<div
class=
"main-wrapper edit-state-${unit_state}"
data-id=
"${unit_location}"
data-update_url=
"${unit_update_url}"
>
<div
class=
"inner-wrapper"
>
<div
class=
"inner-wrapper"
>
<div
class=
"alert editing-draft-alert"
>
<div
class=
"alert editing-draft-alert"
>
<p
class=
"alert-message"
><strong>
${_("You are editing a draft.")}
</strong>
<p
class=
"alert-message"
><strong>
${_("You are editing a draft.")}
</strong>
...
@@ -48,8 +48,8 @@ require(["domReady!", "jquery", "coffee/src/models/module", "coffee/src/views/un
...
@@ -48,8 +48,8 @@ require(["domReady!", "jquery", "coffee/src/models/module", "coffee/src/views/un
<article
class=
"unit-body window"
>
<article
class=
"unit-body window"
>
<p
class=
"unit-name-input"
><label>
${_("Display Name:")}
</label><input
type=
"text"
value=
"${unit.display_name_with_default | h}"
class=
"unit-display-name-input"
/></p>
<p
class=
"unit-name-input"
><label>
${_("Display Name:")}
</label><input
type=
"text"
value=
"${unit.display_name_with_default | h}"
class=
"unit-display-name-input"
/></p>
<ol
class=
"components"
>
<ol
class=
"components"
>
% for id in components:
% for id
, component_update_url
in components:
<li
class=
"component"
data-id=
"${id}"
/>
<li
class=
"component"
data-id=
"${id}"
data-update_url=
"${component_update_url}"
/>
% endfor
% endfor
<li
class=
"new-component-item adding"
>
<li
class=
"new-component-item adding"
>
<div
class=
"new-component"
>
<div
class=
"new-component"
>
...
...
cms/templates/widgets/units.html
View file @
cd868efc
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
contentstore
.
utils
import
compute_unit_state
%
>
<
%!
from
contentstore
.
utils
import
compute_unit_state
%
>
<
%!
from
xmodule
.
modulestore
.
django
import
loc_mapper
%
>
<!--
<!--
This def will enumerate through a passed in subsection and list all of the units
This def will enumerate through a passed in subsection and list all of the units
...
@@ -11,7 +12,11 @@ This def will enumerate through a passed in subsection and list all of the units
...
@@ -11,7 +12,11 @@ This def will enumerate through a passed in subsection and list all of the units
subsection_units =
subsection.get_children()
subsection_units =
subsection.get_children()
%
>
%
>
% for unit in subsection_units:
% for unit in subsection_units:
<li
class=
"courseware-unit leaf unit is-draggable"
data-id=
"${unit.location}"
data-parent-id=
"${subsection.location.url()}"
>
<
%
unit_update_url =
loc_mapper().translate_location(context_course.location.course_id,
unit
.
location
,
False
,
True
).
url_reverse
('
xblock
')
%
>
<li
class=
"courseware-unit leaf unit is-draggable"
data-id=
"${unit.location}"
data-parent-id=
"${subsection.location.url()}"
data-update_url=
"${unit_update_url}"
>
<
%
include
file=
"_ui-dnd-indicator-before.html"
/>
<
%
include
file=
"_ui-dnd-indicator-before.html"
/>
...
@@ -29,7 +34,9 @@ This def will enumerate through a passed in subsection and list all of the units
...
@@ -29,7 +34,9 @@ This def will enumerate through a passed in subsection and list all of the units
</a>
</a>
% if actions:
% if actions:
<div
class=
"item-actions"
>
<div
class=
"item-actions"
>
<a
href=
"#"
data-tooltip=
"Delete this unit"
class=
"delete-button"
data-id=
"${unit.location}"
><span
class=
"delete-icon"
></span></a>
<a
href=
"#"
data-tooltip=
"Delete this unit"
class=
"delete-button"
data-id=
"${unit.location}"
data-update_url=
"${unit_update_url}"
>
<span
class=
"delete-icon"
></span></a>
<span
data-tooltip=
"Drag to sort"
class=
"drag-handle unit-drag-handle"
></span>
<span
data-tooltip=
"Drag to sort"
class=
"drag-handle unit-drag-handle"
></span>
</div>
</div>
% endif
% endif
...
...
cms/urls.py
View file @
cd868efc
import
re
from
django.conf
import
settings
from
django.conf
import
settings
from
django.conf.urls
import
patterns
,
include
,
url
from
django.conf.urls
import
patterns
,
include
,
url
...
@@ -17,7 +16,6 @@ urlpatterns = patterns('', # nopep8
...
@@ -17,7 +16,6 @@ urlpatterns = patterns('', # nopep8
url
(
r'^subsection/(?P<location>.*?)$'
,
'contentstore.views.edit_subsection'
,
name
=
'edit_subsection'
),
url
(
r'^subsection/(?P<location>.*?)$'
,
'contentstore.views.edit_subsection'
,
name
=
'edit_subsection'
),
url
(
r'^preview_component/(?P<location>.*?)$'
,
'contentstore.views.preview_component'
,
name
=
'preview_component'
),
url
(
r'^preview_component/(?P<location>.*?)$'
,
'contentstore.views.preview_component'
,
name
=
'preview_component'
),
url
(
r'^save_item$'
,
'contentstore.views.save_item'
,
name
=
'save_item'
),
url
(
r'^save_item$'
,
'contentstore.views.save_item'
,
name
=
'save_item'
),
url
(
r'^delete_item$'
,
'contentstore.views.delete_item'
,
name
=
'delete_item'
),
url
(
r'^create_item$'
,
'contentstore.views.create_item'
,
name
=
'create_item'
),
url
(
r'^create_item$'
,
'contentstore.views.create_item'
,
name
=
'create_item'
),
url
(
r'^transcripts/upload$'
,
'contentstore.views.upload_transcripts'
,
name
=
'upload_transcripts'
),
url
(
r'^transcripts/upload$'
,
'contentstore.views.upload_transcripts'
,
name
=
'upload_transcripts'
),
...
@@ -121,6 +119,7 @@ urlpatterns += patterns(
...
@@ -121,6 +119,7 @@ urlpatterns += patterns(
url
(
r'(?ix)^import/{}$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'import_handler'
),
url
(
r'(?ix)^import/{}$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'import_handler'
),
url
(
r'(?ix)^import_status/{}/(?P<filename>.+)$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'import_status_handler'
),
url
(
r'(?ix)^import_status/{}/(?P<filename>.+)$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'import_status_handler'
),
url
(
r'(?ix)^export/{}$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'export_handler'
),
url
(
r'(?ix)^export/{}$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'export_handler'
),
url
(
r'(?ix)^xblock/{}$'
.
format
(
parsers
.
URL_RE_SOURCE
),
'xblock_handler'
),
)
)
js_info_dict
=
{
js_info_dict
=
{
...
...
common/djangoapps/util/json_request.py
View file @
cd868efc
...
@@ -17,7 +17,7 @@ def expect_json(view_function):
...
@@ -17,7 +17,7 @@ def expect_json(view_function):
def
parse_json_into_request
(
request
,
*
args
,
**
kwargs
):
def
parse_json_into_request
(
request
,
*
args
,
**
kwargs
):
# cdodge: fix postback errors in CMS. The POST 'content-type' header can include additional information
# cdodge: fix postback errors in CMS. The POST 'content-type' header can include additional information
# e.g. 'charset', so we can't do a direct string compare
# e.g. 'charset', so we can't do a direct string compare
if
"application/json"
in
request
.
META
.
get
(
'CONTENT_TYPE'
,
''
):
if
"application/json"
in
request
.
META
.
get
(
'CONTENT_TYPE'
,
''
)
and
request
.
body
:
request
.
json
=
json
.
loads
(
request
.
body
)
request
.
json
=
json
.
loads
(
request
.
body
)
else
:
else
:
request
.
json
=
{}
request
.
json
=
{}
...
...
common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py
View file @
cd868efc
...
@@ -167,7 +167,7 @@ class LocMapperStore(object):
...
@@ -167,7 +167,7 @@ class LocMapperStore(object):
return
BlockUsageLocator
(
course_id
=
entry
[
'course_id'
],
branch
=
branch
,
usage_id
=
usage_id
)
return
BlockUsageLocator
(
course_id
=
entry
[
'course_id'
],
branch
=
branch
,
usage_id
=
usage_id
)
def
translate_locator_to_location
(
self
,
locator
):
def
translate_locator_to_location
(
self
,
locator
,
get_course
=
False
):
"""
"""
Returns an old style Location for the given Locator if there's an appropriate entry in the
Returns an old style Location for the given Locator if there's an appropriate entry in the
mapping collection. Note, it requires that the course was previously mapped (a side effect of
mapping collection. Note, it requires that the course was previously mapped (a side effect of
...
@@ -175,6 +175,9 @@ class LocMapperStore(object):
...
@@ -175,6 +175,9 @@ class LocMapperStore(object):
the block's usage_id was previously stored in the
the block's usage_id was previously stored in the
map (a side effect of translate_location or via add|update_block_location).
map (a side effect of translate_location or via add|update_block_location).
If get_course, then rather than finding the map for this locator, it finds the 'course' root
for the mapped course.
If there are no matches, it returns None.
If there are no matches, it returns None.
If there's more than one location to locator mapping to the same course_id, it looks for the first
If there's more than one location to locator mapping to the same course_id, it looks for the first
...
@@ -191,7 +194,16 @@ class LocMapperStore(object):
...
@@ -191,7 +194,16 @@ class LocMapperStore(object):
for
candidate
in
maps
:
for
candidate
in
maps
:
for
old_name
,
cat_to_usage
in
candidate
[
'block_map'
]
.
iteritems
():
for
old_name
,
cat_to_usage
in
candidate
[
'block_map'
]
.
iteritems
():
for
category
,
usage_id
in
cat_to_usage
.
iteritems
():
for
category
,
usage_id
in
cat_to_usage
.
iteritems
():
if
usage_id
==
locator
.
usage_id
:
if
get_course
:
if
category
==
'course'
:
return
Location
(
'i4x'
,
candidate
[
'_id'
][
'org'
],
candidate
[
'_id'
][
'course'
],
'course'
,
self
.
_decode_from_mongo
(
old_name
),
None
)
elif
usage_id
==
locator
.
usage_id
:
# figure out revision
# figure out revision
# enforce the draft only if category in [..] logic
# enforce the draft only if category in [..] logic
if
category
in
draft
.
DIRECT_ONLY_CATEGORIES
:
if
category
in
draft
.
DIRECT_ONLY_CATEGORIES
:
...
...
common/lib/xmodule/xmodule/modulestore/locator.py
View file @
cd868efc
...
@@ -263,7 +263,7 @@ class CourseLocator(Locator):
...
@@ -263,7 +263,7 @@ class CourseLocator(Locator):
version_guid
=
self
.
version_guid
,
version_guid
=
self
.
version_guid
,
branch
=
self
.
branch
)
branch
=
self
.
branch
)
def
url_reverse
(
self
,
prefix
,
postfix
):
def
url_reverse
(
self
,
prefix
,
postfix
=
''
):
"""
"""
Do what reverse is supposed to do but seems unable to do. Generate a url using prefix unicode(self) postfix
Do what reverse is supposed to do but seems unable to do. Generate a url using prefix unicode(self) postfix
:param prefix: the beginning of the url (will be forced to begin and end with / if non-empty)
:param prefix: the beginning of the url (will be forced to begin and end with / if non-empty)
...
...
common/lib/xmodule/xmodule/modulestore/mongo/draft.py
View file @
cd868efc
...
@@ -81,7 +81,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -81,7 +81,7 @@ class DraftModuleStore(MongoModuleStore):
try
:
try
:
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_item
(
as_draft
(
location
),
depth
=
depth
))
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_item
(
as_draft
(
location
),
depth
=
depth
))
except
ItemNotFoundError
:
except
ItemNotFoundError
:
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_item
(
location
,
depth
=
depth
))
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_item
(
as_published
(
location
)
,
depth
=
depth
))
def
get_instance
(
self
,
course_id
,
location
,
depth
=
0
):
def
get_instance
(
self
,
course_id
,
location
,
depth
=
0
):
"""
"""
...
@@ -169,7 +169,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -169,7 +169,7 @@ class DraftModuleStore(MongoModuleStore):
try
:
try
:
draft_item
=
self
.
get_item
(
location
)
draft_item
=
self
.
get_item
(
location
)
if
not
getattr
(
draft_item
,
'is_draft'
,
False
):
if
not
getattr
(
draft_item
,
'is_draft'
,
False
):
self
.
convert_to_draft
(
location
)
self
.
convert_to_draft
(
as_published
(
location
)
)
except
ItemNotFoundError
,
e
:
except
ItemNotFoundError
,
e
:
if
not
allow_not_found
:
if
not
allow_not_found
:
raise
e
raise
e
...
@@ -187,7 +187,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -187,7 +187,7 @@ class DraftModuleStore(MongoModuleStore):
draft_loc
=
as_draft
(
location
)
draft_loc
=
as_draft
(
location
)
draft_item
=
self
.
get_item
(
location
)
draft_item
=
self
.
get_item
(
location
)
if
not
getattr
(
draft_item
,
'is_draft'
,
False
):
if
not
getattr
(
draft_item
,
'is_draft'
,
False
):
self
.
convert_to_draft
(
location
)
self
.
convert_to_draft
(
as_published
(
location
)
)
return
super
(
DraftModuleStore
,
self
)
.
update_children
(
draft_loc
,
children
)
return
super
(
DraftModuleStore
,
self
)
.
update_children
(
draft_loc
,
children
)
...
@@ -203,7 +203,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -203,7 +203,7 @@ class DraftModuleStore(MongoModuleStore):
draft_item
=
self
.
get_item
(
location
)
draft_item
=
self
.
get_item
(
location
)
if
not
getattr
(
draft_item
,
'is_draft'
,
False
):
if
not
getattr
(
draft_item
,
'is_draft'
,
False
):
self
.
convert_to_draft
(
location
)
self
.
convert_to_draft
(
as_published
(
location
)
)
if
'is_draft'
in
metadata
:
if
'is_draft'
in
metadata
:
del
metadata
[
'is_draft'
]
del
metadata
[
'is_draft'
]
...
@@ -262,7 +262,7 @@ class DraftModuleStore(MongoModuleStore):
...
@@ -262,7 +262,7 @@ class DraftModuleStore(MongoModuleStore):
"""
"""
Turn the published version into a draft, removing the published version
Turn the published version into a draft, removing the published version
"""
"""
self
.
convert_to_draft
(
location
)
self
.
convert_to_draft
(
as_published
(
location
)
)
super
(
DraftModuleStore
,
self
)
.
delete_item
(
location
)
super
(
DraftModuleStore
,
self
)
.
delete_item
(
location
)
def
_query_children_for_cache_children
(
self
,
items
):
def
_query_children_for_cache_children
(
self
,
items
):
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_location_mapper.py
View file @
cd868efc
...
@@ -258,13 +258,17 @@ class TestLocationMapper(unittest.TestCase):
...
@@ -258,13 +258,17 @@ class TestLocationMapper(unittest.TestCase):
new_style_course_id
,
new_style_course_id
,
block_map
=
{
block_map
=
{
'abc123'
:
{
'problem'
:
'problem2'
},
'abc123'
:
{
'problem'
:
'problem2'
},
'48f23a10395384929234'
:
{
'chapter'
:
'chapter48f'
}
'48f23a10395384929234'
:
{
'chapter'
:
'chapter48f'
},
'baz_run'
:
{
'course'
:
'root'
},
}
}
)
)
# only one course matches
# only one course matches
prob_location
=
loc_mapper
()
.
translate_locator_to_location
(
prob_locator
)
prob_location
=
loc_mapper
()
.
translate_locator_to_location
(
prob_locator
)
# default branch
# default branch
self
.
assertEqual
(
prob_location
,
Location
(
'i4x'
,
org
,
course
,
'problem'
,
'abc123'
,
None
))
self
.
assertEqual
(
prob_location
,
Location
(
'i4x'
,
org
,
course
,
'problem'
,
'abc123'
,
None
))
# test get_course keyword
prob_location
=
loc_mapper
()
.
translate_locator_to_location
(
prob_locator
,
get_course
=
True
)
self
.
assertEqual
(
prob_location
,
Location
(
'i4x'
,
org
,
course
,
'course'
,
'baz_run'
,
None
))
# explicit branch
# explicit branch
prob_locator
=
BlockUsageLocator
(
prob_locator
=
BlockUsageLocator
(
course_id
=
prob_locator
.
course_id
,
branch
=
'draft'
,
usage_id
=
prob_locator
.
usage_id
course_id
=
prob_locator
.
course_id
,
branch
=
'draft'
,
usage_id
=
prob_locator
.
usage_id
...
...
common/lib/xmodule/xmodule/modulestore/xml_exporter.py
View file @
cd868efc
...
@@ -97,6 +97,7 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d
...
@@ -97,6 +97,7 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d
if
len
(
draft_verticals
)
>
0
:
if
len
(
draft_verticals
)
>
0
:
draft_course_dir
=
export_fs
.
makeopendir
(
'drafts'
)
draft_course_dir
=
export_fs
.
makeopendir
(
'drafts'
)
for
draft_vertical
in
draft_verticals
:
for
draft_vertical
in
draft_verticals
:
if
getattr
(
draft_vertical
,
'is_draft'
,
False
):
parent_locs
=
draft_modulestore
.
get_parent_locations
(
draft_vertical
.
location
,
course
.
location
.
course_id
)
parent_locs
=
draft_modulestore
.
get_parent_locations
(
draft_vertical
.
location
,
course
.
location
.
course_id
)
# Don't try to export orphaned items.
# Don't try to export orphaned items.
if
len
(
parent_locs
)
>
0
:
if
len
(
parent_locs
)
>
0
:
...
...
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