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
310f26a6
Commit
310f26a6
authored
Oct 05, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Basic implementation of draft, public and private modes
parent
2b030f7a
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
100 additions
and
30 deletions
+100
-30
cms/djangoapps/contentstore/utils.py
+2
-2
cms/djangoapps/contentstore/views.py
+15
-0
cms/static/coffee/src/views/unit.coffee
+34
-7
cms/static/sass/_unit.scss
+0
-1
cms/templates/unit.html
+5
-4
cms/urls.py
+3
-4
common/lib/xmodule/xmodule/modulestore/draft.py
+41
-12
No files found.
cms/djangoapps/contentstore/utils.py
View file @
310f26a6
...
@@ -59,9 +59,9 @@ def compute_unit_state(unit):
...
@@ -59,9 +59,9 @@ def compute_unit_state(unit):
'private' content is editabled and not visible in the LMS
'private' content is editabled and not visible in the LMS
"""
"""
if
unit
.
location
.
revision
==
DRAFT
:
if
unit
.
metadata
.
get
(
'is_draft'
,
False
)
:
try
:
try
:
modulestore
(
'direct'
)
.
get_item
(
unit
.
location
.
_replace
(
revision
=
None
)
)
modulestore
(
'direct'
)
.
get_item
(
unit
.
location
)
return
'draft'
return
'draft'
except
ItemNotFoundError
:
except
ItemNotFoundError
:
return
'private'
return
'private'
...
...
cms/djangoapps/contentstore/views.py
View file @
310f26a6
...
@@ -521,6 +521,21 @@ def publish_draft(request):
...
@@ -521,6 +521,21 @@ def publish_draft(request):
return
HttpResponse
()
return
HttpResponse
()
@login_required
@expect_json
def
unpublish_unit
(
request
):
location
=
request
.
POST
[
'id'
]
# check permissions for this user within this course
if
not
has_access
(
request
.
user
,
location
):
raise
PermissionDenied
()
modulestore
()
.
unpublish
(
location
)
return
HttpResponse
()
@login_required
@login_required
@expect_json
@expect_json
def
clone_item
(
request
):
def
clone_item
(
request
):
...
...
cms/static/coffee/src/views/unit.coffee
View file @
310f26a6
...
@@ -9,8 +9,15 @@ class CMS.Views.UnitEdit extends Backbone.View
...
@@ -9,8 +9,15 @@ class CMS.Views.UnitEdit extends Backbone.View
'click #delete-draft'
:
'deleteDraft'
'click #delete-draft'
:
'deleteDraft'
'click #create-draft'
:
'createDraft'
'click #create-draft'
:
'createDraft'
'click #publish-draft'
:
'publishDraft'
'click #publish-draft'
:
'publishDraft'
'change #visibility'
:
'setVisibility'
initialize
:
=>
initialize
:
=>
@
visibility_view
=
new
CMS
.
Views
.
UnitEdit
.
Visibility
(
el
:
@
$
(
'#visibility'
)
model
:
@
model
)
@
visibility_view
.
render
()
@
$newComponentItem
=
@
$
(
'.new-component-item'
)
@
$newComponentItem
=
@
$
(
'.new-component-item'
)
@
$newComponentTypePicker
=
@
$
(
'.new-component'
)
@
$newComponentTypePicker
=
@
$
(
'.new-component'
)
@
$newComponentTemplatePickers
=
@
$
(
'.new-component-templates'
)
@
$newComponentTemplatePickers
=
@
$
(
'.new-component-templates'
)
...
@@ -18,6 +25,7 @@ class CMS.Views.UnitEdit extends Backbone.View
...
@@ -18,6 +25,7 @@ class CMS.Views.UnitEdit extends Backbone.View
@
$
(
'.components'
).
sortable
(
@
$
(
'.components'
).
sortable
(
handle
:
'.drag-handle'
handle
:
'.drag-handle'
update
:
(
event
,
ui
)
=>
@
model
.
set
(
'children'
,
@
components
())
)
)
@
$
(
'.component'
).
each
((
idx
,
element
)
=>
@
$
(
'.component'
).
each
((
idx
,
element
)
=>
...
@@ -28,10 +36,9 @@ class CMS.Views.UnitEdit extends Backbone.View
...
@@ -28,10 +36,9 @@ class CMS.Views.UnitEdit extends Backbone.View
id
:
$
(
element
).
data
(
'id'
),
id
:
$
(
element
).
data
(
'id'
),
)
)
)
)
update
:
(
event
,
ui
)
=>
@
model
.
set
(
'children'
,
@
components
())
)
)
@
model
.
components
=
@
components
()
# New component creation
# New component creation
showNewComponentForm
:
(
event
)
=>
showNewComponentForm
:
(
event
)
=>
event
.
preventDefault
()
event
.
preventDefault
()
...
@@ -75,9 +82,7 @@ class CMS.Views.UnitEdit extends Backbone.View
...
@@ -75,9 +82,7 @@ class CMS.Views.UnitEdit extends Backbone.View
components
:
=>
@
$
(
'.component'
).
map
((
idx
,
el
)
->
$
(
el
).
data
(
'id'
)).
get
()
components
:
=>
@
$
(
'.component'
).
map
((
idx
,
el
)
->
$
(
el
).
data
(
'id'
)).
get
()
saveDraft
:
=>
saveDraft
:
=>
@
model
.
save
(
@
model
.
save
()
children
:
@
components
()
)
deleteComponent
:
(
event
)
=>
deleteComponent
:
(
event
)
=>
$component
=
$
(
event
.
currentTarget
).
parents
(
'.component'
)
$component
=
$
(
event
.
currentTarget
).
parents
(
'.component'
)
...
@@ -101,6 +106,7 @@ class CMS.Views.UnitEdit extends Backbone.View
...
@@ -101,6 +106,7 @@ class CMS.Views.UnitEdit extends Backbone.View
id
:
@
$el
.
data
(
'id'
)
id
:
@
$el
.
data
(
'id'
)
},
=>
},
=>
@
$el
.
toggleClass
(
'edit-state-public edit-state-draft'
)
@
$el
.
toggleClass
(
'edit-state-public edit-state-draft'
)
@
model
.
set
(
'state'
,
'draft'
)
)
)
publishDraft
:
(
event
)
->
publishDraft
:
(
event
)
->
...
@@ -108,4 +114,26 @@ class CMS.Views.UnitEdit extends Backbone.View
...
@@ -108,4 +114,26 @@ class CMS.Views.UnitEdit extends Backbone.View
id
:
@
$el
.
data
(
'id'
)
id
:
@
$el
.
data
(
'id'
)
},
=>
},
=>
@
$el
.
toggleClass
(
'edit-state-public edit-state-draft'
)
@
$el
.
toggleClass
(
'edit-state-public edit-state-draft'
)
)
@
model
.
set
(
'state'
,
'public'
)
\ No newline at end of file
)
setVisibility
:
(
event
)
->
if
@
$
(
'#visibility'
).
val
()
==
'private'
target_url
=
'/unpublish_unit'
else
target_url
=
'/publish_draft'
$
.
post
(
target_url
,
{
id
:
@
$el
.
data
(
'id'
)
},
=>
@
$el
.
toggleClass
(
'edit-state-public edit-state-private'
)
@
model
.
set
(
'state'
,
@
$
(
'#visibility'
).
val
())
)
class
CMS
.
Views
.
UnitEdit
.
Visibility
extends
Backbone
.
View
initialize
:
=>
@
model
.
on
(
'change:state'
,
@
render
)
render
:
=>
@
$el
.
val
(
@
model
.
get
(
'state'
))
cms/static/sass/_unit.scss
View file @
310f26a6
...
@@ -421,7 +421,6 @@
...
@@ -421,7 +421,6 @@
}
}
.edit-state-private
{
.edit-state-private
{
#save-draft
,
#delete-draft
,
#delete-draft
,
#publish-draft
,
#publish-draft
,
#published-alert
,
#published-alert
,
...
...
cms/templates/unit.html
View file @
310f26a6
...
@@ -8,7 +8,8 @@
...
@@ -8,7 +8,8 @@
new
CMS
.
Views
.
UnitEdit
({
new
CMS
.
Views
.
UnitEdit
({
el
:
$
(
'.main-wrapper'
),
el
:
$
(
'.main-wrapper'
),
model
:
new
CMS
.
Models
.
Module
({
model
:
new
CMS
.
Models
.
Module
({
id
:
'${unit_location}'
id
:
'${unit_location}'
,
state
:
'${unit_state}'
})
})
});
});
</script>
</script>
...
@@ -74,9 +75,9 @@
...
@@ -74,9 +75,9 @@
<div
class=
"window-contents"
>
<div
class=
"window-contents"
>
<div
class=
"row visibility"
>
<div
class=
"row visibility"
>
<label
class=
"inline-label"
>
Visibility:
</label>
<label
class=
"inline-label"
>
Visibility:
</label>
<select>
<select
id=
'visibility'
>
<option>
Public
</option>
<option
value=
"public"
>
Public
</option>
<option>
Private
</option>
<option
value=
"private"
>
Private
</option>
</select>
</select>
</div>
</div>
<a
id=
"create-draft"
href=
"#"
>
This unit has been published. Click here to edit it.
</a>
<a
id=
"create-draft"
href=
"#"
>
This unit has been published. Click here to edit it.
</a>
...
...
cms/urls.py
View file @
310f26a6
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
import
django.contrib.auth.views
# Uncomment the next two lines to enable the admin:
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# from django.contrib import admin
# admin.autodiscover()
# admin.autodiscover()
...
@@ -17,12 +15,13 @@ urlpatterns = ('',
...
@@ -17,12 +15,13 @@ urlpatterns = ('',
url
(
r'^clone_item$'
,
'contentstore.views.clone_item'
,
name
=
'clone_item'
),
url
(
r'^clone_item$'
,
'contentstore.views.clone_item'
,
name
=
'clone_item'
),
url
(
r'^create_draft$'
,
'contentstore.views.create_draft'
,
name
=
'create_draft'
),
url
(
r'^create_draft$'
,
'contentstore.views.create_draft'
,
name
=
'create_draft'
),
url
(
r'^publish_draft$'
,
'contentstore.views.publish_draft'
,
name
=
'publish_draft'
),
url
(
r'^publish_draft$'
,
'contentstore.views.publish_draft'
,
name
=
'publish_draft'
),
url
(
r'^unpublish_unit$'
,
'contentstore.views.unpublish_unit'
,
name
=
'unpublish_unit'
),
url
(
r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)$'
,
url
(
r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)$'
,
'contentstore.views.course_index'
,
name
=
'course_index'
),
'contentstore.views.course_index'
,
name
=
'course_index'
),
url
(
r'^github_service_hook$'
,
'github_sync.views.github_post_receive'
),
url
(
r'^github_service_hook$'
,
'github_sync.views.github_post_receive'
),
url
(
r'^preview/modx/(?P<preview_id>[^/]*)/(?P<location>.*?)/(?P<dispatch>[^/]*)$'
,
url
(
r'^preview/modx/(?P<preview_id>[^/]*)/(?P<location>.*?)/(?P<dispatch>[^/]*)$'
,
'contentstore.views.preview_dispatch'
,
name
=
'preview_dispatch'
),
'contentstore.views.preview_dispatch'
,
name
=
'preview_dispatch'
),
url
(
r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)/upload_asset$'
,
url
(
r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)/upload_asset$'
,
'contentstore.views.upload_asset'
,
name
=
'upload_asset'
),
'contentstore.views.upload_asset'
,
name
=
'upload_asset'
),
url
(
r'^manage_users/(?P<location>.*?)$'
,
'contentstore.views.manage_users'
,
name
=
'manage_users'
),
url
(
r'^manage_users/(?P<location>.*?)$'
,
'contentstore.views.manage_users'
,
name
=
'manage_users'
),
url
(
r'^add_user/(?P<location>.*?)$'
,
url
(
r'^add_user/(?P<location>.*?)$'
,
...
@@ -56,6 +55,6 @@ urlpatterns += (
...
@@ -56,6 +55,6 @@ urlpatterns += (
if
settings
.
DEBUG
:
if
settings
.
DEBUG
:
## Jasmine
## Jasmine
urlpatterns
=
urlpatterns
+
(
url
(
r'^_jasmine/'
,
include
(
'django_jasmine.urls'
)),)
urlpatterns
=
urlpatterns
+
(
url
(
r'^_jasmine/'
,
include
(
'django_jasmine.urls'
)),)
urlpatterns
=
patterns
(
*
urlpatterns
)
urlpatterns
=
patterns
(
*
urlpatterns
)
common/lib/xmodule/xmodule/modulestore/draft.py
View file @
310f26a6
...
@@ -6,6 +6,24 @@ from .exceptions import ItemNotFoundError
...
@@ -6,6 +6,24 @@ from .exceptions import ItemNotFoundError
DRAFT
=
'draft'
DRAFT
=
'draft'
def
as_draft
(
location
):
"""
Returns the Location that is the draft for `location`
"""
return
Location
(
location
)
.
_replace
(
revision
=
DRAFT
)
def
wrap_draft
(
item
):
"""
Sets `item.metadata['is_draft']` to `True` if the item is a
draft, and false otherwise. Sets the item's location to the
non-draft location in either case
"""
item
.
metadata
[
'is_draft'
]
=
item
.
location
.
revision
==
DRAFT
item
.
location
=
item
.
location
.
_replace
(
revision
=
None
)
return
item
class
DraftModuleStore
(
ModuleStoreBase
):
class
DraftModuleStore
(
ModuleStoreBase
):
"""
"""
This mixin modifies a modulestore to give it draft semantics.
This mixin modifies a modulestore to give it draft semantics.
...
@@ -37,9 +55,9 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -37,9 +55,9 @@ class DraftModuleStore(ModuleStoreBase):
get_children() to cache. None indicates to cache all descendents
get_children() to cache. None indicates to cache all descendents
"""
"""
try
:
try
:
return
super
(
DraftModuleStore
,
self
)
.
get_item
(
Location
(
location
)
.
_replace
(
revision
=
DRAFT
),
depth
)
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_item
(
as_draft
(
location
),
depth
)
)
except
ItemNotFoundError
:
except
ItemNotFoundError
:
return
super
(
DraftModuleStore
,
self
)
.
get_item
(
location
,
depth
)
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_item
(
location
,
depth
)
)
def
get_instance
(
self
,
course_id
,
location
):
def
get_instance
(
self
,
course_id
,
location
):
"""
"""
...
@@ -47,9 +65,9 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -47,9 +65,9 @@ class DraftModuleStore(ModuleStoreBase):
TODO (vshnayder): this may want to live outside the modulestore eventually
TODO (vshnayder): this may want to live outside the modulestore eventually
"""
"""
try
:
try
:
return
super
(
DraftModuleStore
,
self
)
.
get_instance
(
course_id
,
Location
(
location
)
.
_replace
(
revision
=
DRAFT
))
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_instance
(
course_id
,
as_draft
(
location
)
))
except
ItemNotFoundError
:
except
ItemNotFoundError
:
return
super
(
DraftModuleStore
,
self
)
.
get_instance
(
course_id
,
location
)
return
wrap_draft
(
super
(
DraftModuleStore
,
self
)
.
get_instance
(
course_id
,
location
)
)
def
get_items
(
self
,
location
,
depth
=
0
):
def
get_items
(
self
,
location
,
depth
=
0
):
"""
"""
...
@@ -64,7 +82,7 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -64,7 +82,7 @@ class DraftModuleStore(ModuleStoreBase):
in the request. The depth is counted in the number of calls to
in the request. The depth is counted in the number of calls to
get_children() to cache. None indicates to cache all descendents
get_children() to cache. None indicates to cache all descendents
"""
"""
draft_loc
=
Location
(
location
)
.
_replace
(
revision
=
DRAFT
)
draft_loc
=
as_draft
(
location
)
draft_items
=
super
(
DraftModuleStore
,
self
)
.
get_items
(
draft_loc
,
depth
)
draft_items
=
super
(
DraftModuleStore
,
self
)
.
get_items
(
draft_loc
,
depth
)
items
=
super
(
DraftModuleStore
,
self
)
.
get_items
(
location
,
depth
)
items
=
super
(
DraftModuleStore
,
self
)
.
get_items
(
location
,
depth
)
...
@@ -75,14 +93,14 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -75,14 +93,14 @@ class DraftModuleStore(ModuleStoreBase):
if
(
item
.
location
.
revision
!=
DRAFT
if
(
item
.
location
.
revision
!=
DRAFT
and
item
.
location
.
_replace
(
revision
=
None
)
not
in
draft_locs_found
)
and
item
.
location
.
_replace
(
revision
=
None
)
not
in
draft_locs_found
)
]
]
return
draft_items
+
non_draft_items
return
[
wrap_draft
(
item
)
for
item
in
draft_items
+
non_draft_items
]
def
clone_item
(
self
,
source
,
location
):
def
clone_item
(
self
,
source
,
location
):
"""
"""
Clone a new item that is a copy of the item at the location `source`
Clone a new item that is a copy of the item at the location `source`
and writes it to `location`
and writes it to `location`
"""
"""
return
super
(
DraftModuleStore
,
self
)
.
clone_item
(
source
,
Location
(
location
)
.
_replace
(
revision
=
DRAFT
))
return
super
(
DraftModuleStore
,
self
)
.
clone_item
(
source
,
as_draft
(
location
))
def
update_item
(
self
,
location
,
data
):
def
update_item
(
self
,
location
,
data
):
"""
"""
...
@@ -92,7 +110,7 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -92,7 +110,7 @@ class DraftModuleStore(ModuleStoreBase):
location: Something that can be passed to Location
location: Something that can be passed to Location
data: A nested dictionary of problem data
data: A nested dictionary of problem data
"""
"""
draft_loc
=
Location
(
location
)
.
_replace
(
revision
=
DRAFT
)
draft_loc
=
as_draft
(
location
)
draft_item
=
self
.
get_item
(
location
)
draft_item
=
self
.
get_item
(
location
)
if
draft_item
.
location
.
revision
!=
DRAFT
:
if
draft_item
.
location
.
revision
!=
DRAFT
:
self
.
clone_item
(
location
,
draft_loc
)
self
.
clone_item
(
location
,
draft_loc
)
...
@@ -107,9 +125,9 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -107,9 +125,9 @@ class DraftModuleStore(ModuleStoreBase):
location: Something that can be passed to Location
location: Something that can be passed to Location
children: A list of child item identifiers
children: A list of child item identifiers
"""
"""
draft_loc
=
Location
(
location
)
.
_replace
(
revision
=
DRAFT
)
draft_loc
=
as_draft
(
location
)
draft_item
=
self
.
get_item
(
location
)
draft_item
=
self
.
get_item
(
location
)
if
draft_item
.
location
.
revision
!=
DRAFT
:
if
not
draft_item
.
metadata
[
'is_draft'
]
:
self
.
clone_item
(
location
,
draft_loc
)
self
.
clone_item
(
location
,
draft_loc
)
return
super
(
DraftModuleStore
,
self
)
.
update_children
(
draft_loc
,
children
)
return
super
(
DraftModuleStore
,
self
)
.
update_children
(
draft_loc
,
children
)
...
@@ -122,8 +140,12 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -122,8 +140,12 @@ class DraftModuleStore(ModuleStoreBase):
location: Something that can be passed to Location
location: Something that can be passed to Location
metadata: A nested dictionary of module metadata
metadata: A nested dictionary of module metadata
"""
"""
draft_loc
=
Location
(
location
)
.
_replace
(
revision
=
DRAFT
)
draft_loc
=
as_draft
(
location
)
draft_item
=
self
.
get_item
(
location
)
draft_item
=
self
.
get_item
(
location
)
if
'is_draft'
in
metadata
:
del
metadata
[
'is_draft'
]
if
draft_item
.
location
.
revision
!=
DRAFT
:
if
draft_item
.
location
.
revision
!=
DRAFT
:
self
.
clone_item
(
location
,
draft_loc
)
self
.
clone_item
(
location
,
draft_loc
)
...
@@ -135,7 +157,7 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -135,7 +157,7 @@ class DraftModuleStore(ModuleStoreBase):
location: Something that can be passed to Location
location: Something that can be passed to Location
"""
"""
return
super
(
DraftModuleStore
,
self
)
.
delete_item
(
Location
(
location
)
.
_replace
(
revision
=
DRAFT
))
return
super
(
DraftModuleStore
,
self
)
.
delete_item
(
as_draft
(
location
))
def
publish
(
self
,
location
):
def
publish
(
self
,
location
):
"""
"""
...
@@ -149,3 +171,10 @@ class DraftModuleStore(ModuleStoreBase):
...
@@ -149,3 +171,10 @@ class DraftModuleStore(ModuleStoreBase):
super
(
DraftModuleStore
,
self
)
.
update_children
(
location
,
draft
.
definition
.
get
(
'children'
,
[]))
super
(
DraftModuleStore
,
self
)
.
update_children
(
location
,
draft
.
definition
.
get
(
'children'
,
[]))
super
(
DraftModuleStore
,
self
)
.
update_metadata
(
location
,
metadata
)
super
(
DraftModuleStore
,
self
)
.
update_metadata
(
location
,
metadata
)
self
.
delete_item
(
location
)
self
.
delete_item
(
location
)
def
unpublish
(
self
,
location
):
"""
Turn the published version into a draft, removing the published version
"""
super
(
DraftModuleStore
,
self
)
.
clone_item
(
location
,
as_draft
(
location
))
super
(
DraftModuleStore
,
self
)
.
delete_item
(
location
)
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