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
25544132
Commit
25544132
authored
Sep 19, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Hook up link to create modules from templates
parent
912d6cd6
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
183 additions
and
35 deletions
+183
-35
cms/__init__.py
+3
-0
cms/djangoapps/contentstore/views.py
+51
-1
cms/envs/common.py
+1
-1
cms/static/coffee/src/models/new_module.coffee
+5
-0
cms/static/coffee/src/views/module.coffee
+5
-4
cms/static/coffee/src/views/module_add.coffee
+26
-0
cms/static/coffee/src/views/module_edit.coffee
+1
-1
cms/static/coffee/src/views/week.coffee
+7
-0
cms/templates/new_item.html
+19
-0
cms/templates/widgets/module-dropdown.html
+1
-1
cms/urls.py
+2
-0
common/lib/xmodule/xmodule/html_module.py
+5
-1
common/lib/xmodule/xmodule/modulestore/__init__.py
+5
-2
common/lib/xmodule/xmodule/modulestore/mongo.py
+7
-11
common/lib/xmodule/xmodule/modulestore/xml.py
+0
-4
common/lib/xmodule/xmodule/modulestore/xml_importer.py
+0
-7
common/lib/xmodule/xmodule/templates.py
+30
-0
common/lib/xmodule/xmodule/x_module.py
+14
-1
lms/envs/common.py
+1
-1
No files found.
cms/__init__.py
View file @
25544132
from
xmodule.templates
import
update_templates
update_templates
()
cms/djangoapps/contentstore/views.py
View file @
25544132
...
...
@@ -20,6 +20,8 @@ from xmodule.modulestore.django import modulestore
from
xmodule_modifiers
import
replace_static_urls
,
wrap_xmodule
from
xmodule.exceptions
import
NotFoundError
from
functools
import
partial
from
itertools
import
groupby
from
operator
import
attrgetter
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -128,6 +130,33 @@ def edit_item(request):
})
@login_required
def
new_item
(
request
):
"""
Display a page where the user can create a new item from a template
Expects a GET request with the parameter 'parent_location', which is the element to add
the newly created item to as a child.
parent_location: A Location URL
"""
parent_location
=
request
.
GET
[
'parent_location'
]
if
not
has_access
(
request
.
user
,
parent_location
):
raise
Http404
parent
=
modulestore
()
.
get_item
(
parent_location
)
templates
=
modulestore
()
.
get_items
(
Location
(
'i4x'
,
'edx'
,
'templates'
))
templates
.
sort
(
key
=
attrgetter
(
'location.category'
,
'display_name'
))
return
render_to_response
(
'new_item.html'
,
{
'parent_name'
:
parent
.
display_name
,
'parent_location'
:
parent
.
location
.
url
(),
'templates'
:
groupby
(
templates
,
attrgetter
(
'location.category'
)),
})
def
user_author_string
(
user
):
'''Get an author string for commits by this user. Format:
first last <email@email.com>.
...
...
@@ -262,7 +291,7 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_
module
=
descriptor
.
xmodule_constructor
(
system
)(
instance_state
,
shared_state
)
module
.
get_html
=
replace_static_urls
(
wrap_xmodule
(
module
.
get_html
,
module
,
"xmodule_display.html"
),
module
.
metadata
[
'data_dir'
]
module
.
metadata
.
get
(
'data_dir'
,
module
.
location
.
course
)
)
save_preview_state
(
request
,
preview_id
,
descriptor
.
location
.
url
(),
module
.
get_instance_state
(),
module
.
get_shared_state
())
...
...
@@ -326,3 +355,24 @@ def save_item(request):
preview_html
=
get_module_previews
(
request
,
descriptor
)
return
HttpResponse
(
json
.
dumps
(
preview_html
))
@login_required
@expect_json
def
clone_item
(
request
):
parent_location
=
Location
(
request
.
POST
[
'parent_location'
])
template
=
Location
(
request
.
POST
[
'template'
])
display_name
=
request
.
POST
[
'name'
]
if
not
has_access
(
request
.
user
,
parent_location
):
raise
Http404
# TODO (vshnayder): better error
parent
=
modulestore
()
.
get_item
(
parent_location
)
dest_location
=
parent_location
.
_replace
(
category
=
template
.
category
,
name
=
Location
.
clean_for_url_name
(
display_name
))
new_item
=
modulestore
()
.
clone_item
(
template
,
dest_location
)
new_item
.
metadata
[
'display_name'
]
=
display_name
modulestore
()
.
update_metadata
(
new_item
.
location
.
url
(),
new_item
.
own_metadata
)
modulestore
()
.
update_children
(
parent_location
,
parent
.
definition
.
get
(
'children'
,
[])
+
[
new_item
.
location
.
url
()])
return
HttpResponse
()
cms/envs/common.py
View file @
25544132
...
...
@@ -210,7 +210,7 @@ for dir_ in (js_file_dir, css_file_dir):
js_fragments
=
set
()
css_fragments
=
defaultdict
(
set
)
for
descriptor
in
XModuleDescriptor
.
load_classes
()
+
[
RawDescriptor
]:
for
_
,
descriptor
in
XModuleDescriptor
.
load_classes
()
+
[(
None
,
RawDescriptor
)
]:
descriptor_js
=
descriptor
.
get_javascript
()
module_js
=
descriptor
.
module_class
.
get_javascript
()
...
...
cms/static/coffee/src/models/new_module.coffee
0 → 100644
View file @
25544132
class
CMS
.
Models
.
NewModule
extends
Backbone
.
Model
url
:
'/clone_item'
newUrl
:
->
"/new_item?
#{
$
.
param
(
parent_location
:
@
get
(
'parent_location'
))
}
"
cms/static/coffee/src/views/module.coffee
View file @
25544132
...
...
@@ -7,7 +7,8 @@ class CMS.Views.Module extends Backbone.View
previewType
=
@
$el
.
data
(
'preview-type'
)
moduleType
=
@
$el
.
data
(
'type'
)
CMS
.
replaceView
new
CMS
.
Views
.
ModuleEdit
model
:
new
CMS
.
Models
.
Module
id
:
@
$el
.
data
(
'id'
)
type
:
if
moduleType
==
'None'
then
null
else
moduleType
previewType
:
if
previewType
==
'None'
then
null
else
previewType
model
:
new
CMS
.
Models
.
Module
id
:
@
$el
.
data
(
'id'
)
type
:
if
moduleType
==
'None'
then
null
else
moduleType
previewType
:
if
previewType
==
'None'
then
null
else
previewType
cms/static/coffee/src/views/module_add.coffee
0 → 100644
View file @
25544132
class
CMS
.
Views
.
ModuleAdd
extends
Backbone
.
View
tagName
:
'section'
className
:
'add-pane'
events
:
'click .cancel'
:
'cancel'
'click .save'
:
'save'
initialize
:
->
@
$el
.
load
@
model
.
newUrl
()
save
:
(
event
)
->
event
.
preventDefault
()
@
model
.
save
({
name
:
@
$el
.
find
(
'.name'
).
val
()
template
:
$
(
event
.
target
).
data
(
'template-id'
)
},
{
success
:
->
CMS
.
popView
()
error
:
->
alert
(
'Create failed'
)
})
cancel
:
(
event
)
->
event
.
preventDefault
()
CMS
.
popView
()
cms/static/coffee/src/views/module_edit.coffee
View file @
25544132
...
...
@@ -39,7 +39,7 @@ class CMS.Views.ModuleEdit extends Backbone.View
)
XModule
.
loadModules
(
'display'
)
).
fail
(
->
).
fail
(
->
alert
(
"There was an error saving your changes. Please try again."
)
)
...
...
cms/static/coffee/src/views/week.coffee
View file @
25544132
class
CMS
.
Views
.
Week
extends
Backbone
.
View
events
:
'click .week-edit'
:
'edit'
'click .new-module'
:
'new'
initialize
:
->
CMS
.
on
(
'content.show'
,
@
resetHeight
)
...
...
@@ -23,3 +24,9 @@ class CMS.Views.Week extends Backbone.View
resetHeight
:
=>
@
$el
.
height
(
''
)
new
:
(
event
)
=>
event
.
preventDefault
()
CMS
.
replaceView
new
CMS
.
Views
.
ModuleAdd
model
:
new
CMS
.
Models
.
NewModule
parent_location
:
@
$el
.
data
(
'id'
)
cms/templates/new_item.html
0 → 100644
View file @
25544132
<section>
<div>
${parent_name}
</div>
<div>
${parent_location}
</div>
<input
type=
"text"
class=
"name"
/>
<div>
% for module_type, module_templates in templates:
<div>
<div>
${module_type}
</div>
<div>
% for template in module_templates:
<a
class=
"save"
data-template-id=
"${template.location.url()}"
>
${template.display_name}
</a>
% endfor
</div>
</div>
% endfor
</div>
<a
class=
'cancel'
>
Cancel
</a>
</section>
cms/templates/widgets/module-dropdown.html
View file @
25544132
...
...
@@ -7,7 +7,7 @@
<form>
<ul>
<li>
<input
type=
"text"
name=
""
id=
""
placeholder=
"Mo
l
dule title"
/>
<input
type=
"text"
name=
""
id=
""
placeholder=
"Module title"
/>
</li>
<li>
<select>
...
...
cms/urls.py
View file @
25544132
...
...
@@ -9,8 +9,10 @@ import django.contrib.auth.views
urlpatterns
=
(
''
,
url
(
r'^$'
,
'contentstore.views.index'
,
name
=
'index'
),
url
(
r'^new_item$'
,
'contentstore.views.new_item'
,
name
=
'new_item'
),
url
(
r'^edit_item$'
,
'contentstore.views.edit_item'
,
name
=
'edit_item'
),
url
(
r'^save_item$'
,
'contentstore.views.save_item'
,
name
=
'save_item'
),
url
(
r'^clone_item$'
,
'contentstore.views.clone_item'
,
name
=
'clone_item'
),
url
(
r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)$'
,
'contentstore.views.course_index'
,
name
=
'course_index'
),
url
(
r'^github_service_hook$'
,
'github_sync.views.github_post_receive'
),
...
...
common/lib/xmodule/xmodule/html_module.py
View file @
25544132
...
...
@@ -6,7 +6,7 @@ import sys
from
lxml
import
etree
from
path
import
path
from
.x_module
import
XModule
from
.x_module
import
XModule
,
Template
from
.xml_module
import
XmlDescriptor
,
name_to_pathname
from
.editing_module
import
EditingDescriptor
from
.stringify
import
stringify_children
...
...
@@ -34,6 +34,10 @@ class HtmlDescriptor(XmlDescriptor, EditingDescriptor):
module_class
=
HtmlModule
filename_extension
=
"xml"
templates
=
[
Template
(
'Empty'
,
''
,
[])
]
# VS[compat] TODO (cpennington): Delete this method once all fall 2012 course
# are being edited in the cms
@classmethod
...
...
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
25544132
...
...
@@ -297,8 +297,11 @@ class ModuleStore(object):
"""
raise
NotImplementedError
# TODO (cpennington): Replace with clone_item
def
create_item
(
self
,
location
,
editor
):
def
clone_item
(
self
,
source
,
location
):
"""
Clone a new item that is a copy of the item at the location `source`
and writes it to `location`
"""
raise
NotImplementedError
def
update_item
(
self
,
location
,
data
):
...
...
common/lib/xmodule/xmodule/modulestore/mongo.py
View file @
25544132
...
...
@@ -237,20 +237,16 @@ class MongoModuleStore(ModuleStoreBase):
return
self
.
_load_items
(
list
(
items
),
depth
)
# TODO (cpennington): This needs to be replaced by clone_item as soon as we allow
# creation of items from the cms
def
create_item
(
self
,
location
):
def
clone_item
(
self
,
source
,
location
):
"""
Create an empty item at the specified location.
If that location already exists, raises a DuplicateItemError
location: Something that can be passed to Location
Clone a new item that is a copy of the item at the location `source`
and writes it to `location`
"""
try
:
self
.
collection
.
insert
({
'_id'
:
Location
(
location
)
.
dict
(),
})
source_item
=
self
.
collection
.
find_one
(
location_to_query
(
source
))
source_item
[
'_id'
]
=
Location
(
location
)
.
dict
()
self
.
collection
.
insert
(
source_item
)
return
self
.
_load_items
([
source_item
])[
0
]
except
pymongo
.
errors
.
DuplicateKeyError
:
raise
DuplicateItemError
(
location
)
...
...
common/lib/xmodule/xmodule/modulestore/xml.py
View file @
25544132
...
...
@@ -471,10 +471,6 @@ class XMLModuleStore(ModuleStoreBase):
"""
return
dict
(
(
k
,
self
.
errored_courses
[
k
]
.
errors
)
for
k
in
self
.
errored_courses
)
def
create_item
(
self
,
location
):
raise
NotImplementedError
(
"XMLModuleStores are read-only"
)
def
update_item
(
self
,
location
,
data
):
"""
Set the data in the item specified by the location to
...
...
common/lib/xmodule/xmodule/modulestore/xml_importer.py
View file @
25544132
...
...
@@ -24,13 +24,6 @@ def import_from_xml(store, data_dir, course_dirs=None,
for
course_id
in
module_store
.
modules
.
keys
():
for
module
in
module_store
.
modules
[
course_id
]
.
itervalues
():
# TODO (cpennington): This forces import to overrite the same items.
# This should in the future create new revisions of the items on import
try
:
store
.
create_item
(
module
.
location
)
except
DuplicateItemError
:
log
.
exception
(
'Item already exists at
%
s'
%
module
.
location
.
url
())
pass
if
'data'
in
module
.
definition
:
store
.
update_item
(
module
.
location
,
module
.
definition
[
'data'
])
if
'children'
in
module
.
definition
:
...
...
common/lib/xmodule/xmodule/templates.py
0 → 100644
View file @
25544132
from
collections
import
defaultdict
from
.x_module
import
XModuleDescriptor
from
.modulestore
import
Location
from
.modulestore.django
import
modulestore
def
all_templates
():
"""
Returns all templates for enabled modules, grouped by descriptor type
"""
templates
=
defaultdict
(
list
)
for
category
,
descriptor
in
XModuleDescriptor
.
load_classes
():
templates
[
category
]
=
descriptor
.
templates
return
templates
def
update_templates
():
"""
Updates the set of templates in the modulestore with all templates currently
available from the installed plugins
"""
for
category
,
templates
in
all_templates
()
.
items
():
for
template
in
templates
:
template_location
=
Location
(
'i4x'
,
'edx'
,
'templates'
,
category
,
Location
.
clean_for_url_name
(
template
.
name
))
modulestore
()
.
update_item
(
template_location
,
template
.
data
)
modulestore
()
.
update_children
(
template_location
,
template
.
children
)
modulestore
()
.
update_metadata
(
template_location
,
{
'display_name'
:
template
.
name
})
common/lib/xmodule/xmodule/x_module.py
View file @
25544132
...
...
@@ -7,6 +7,7 @@ from functools import partial
from
lxml
import
etree
from
lxml.etree
import
XMLSyntaxError
from
pprint
import
pprint
from
collections
import
namedtuple
from
xmodule.errortracker
import
exc_info_to_str
from
xmodule.modulestore
import
Location
...
...
@@ -71,7 +72,11 @@ class Plugin(object):
@classmethod
def
load_classes
(
cls
):
return
[
class_
.
load
()
"""
Returns a list of containing the identifiers and their corresponding classes for all
of the available instances of this plugin
"""
return
[(
class_
.
name
,
class_
.
load
())
for
class_
in
pkg_resources
.
iter_entry_points
(
cls
.
entry_point
)]
...
...
@@ -321,6 +326,9 @@ def policy_key(location):
return
'{cat}/{name}'
.
format
(
cat
=
location
.
category
,
name
=
location
.
name
)
Template
=
namedtuple
(
"Template"
,
"name data children"
)
class
XModuleDescriptor
(
Plugin
,
HTMLSnippet
):
"""
An XModuleDescriptor is a specification for an element of a course. This
...
...
@@ -361,6 +369,11 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
equality_attributes
=
(
'definition'
,
'metadata'
,
'location'
,
'shared_state_key'
,
'_inherited_metadata'
)
# A list of Template objects that describe possible templates that can be used
# to create a module of this type.
# If no templates are provided, there will be no way to create a module of this type
templates
=
[]
# ============================= STRUCTURAL MANIPULATION ===================
def
__init__
(
self
,
system
,
...
...
lms/envs/common.py
View file @
25544132
...
...
@@ -468,7 +468,7 @@ for dir_ in (js_file_dir, css_file_dir):
js_fragments
=
set
()
css_fragments
=
defaultdict
(
set
)
for
descriptor
in
XModuleDescriptor
.
load_classes
()
+
[
HiddenDescriptor
]:
for
_
,
descriptor
in
XModuleDescriptor
.
load_classes
()
+
[(
None
,
HiddenDescriptor
)
]:
module_js
=
descriptor
.
module_class
.
get_javascript
()
for
filetype
in
(
'coffee'
,
'js'
):
for
idx
,
fragment
in
enumerate
(
module_js
.
get
(
filetype
,
[])):
...
...
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