Commit 91a91f4d by Don Mitchell

Hopefully the course-info changes I had made w/o link destruction

parent 336caa0f
......@@ -33,6 +33,31 @@ def get_course_location_for_item(location):
return location
def get_course_for_item(location):
'''
cdodge: for a given Xmodule, return the course that it belongs to
NOTE: This makes a lot of assumptions about the format of the course location
Also we have to assert that this module maps to only one course item - it'll throw an
assert if not
'''
item_loc = Location(location)
# @hack! We need to find the course location however, we don't
# know the 'name' parameter in this context, so we have
# to assume there's only one item in this query even though we are not specifying a name
course_search_location = ['i4x', item_loc.org, item_loc.course, 'course', None]
courses = modulestore().get_items(course_search_location)
# make sure we found exactly one match on this above course search
found_cnt = len(courses)
if found_cnt == 0:
raise BaseException('Could not find course at {0}'.format(course_search_location))
if found_cnt > 1:
raise BaseException('Found more than one course at {0}. There should only be one!!! Dump = {1}'.format(course_search_location, courses))
return courses[0]
def get_lms_link_for_item(location, preview=False):
location = Location(location)
......
......@@ -42,6 +42,8 @@ import shutil
import sys
import tarfile
import time
from contentstore.course_info_model import get_course_updates,\
update_course_updates, delete_course_update
# to install PIL on MacOSX: 'easy_install http://dist.repoze.org/PIL-1.1.6.tar.gz'
......@@ -336,7 +338,7 @@ def edit_unit(request, location):
def preview_component(request, location):
# TODO (vshnayder): change name from id to location in coffee+html as well.
if not has_access(request.user, location):
raise Http404 # TODO (vshnayder): better error
raise HttpResponseForbidden()
component = modulestore().get_item(location)
......@@ -869,6 +871,9 @@ def edit_static(request, org, course, coursename):
return render_to_response('edit-static-page.html', {})
def settings(request, org, course, coursename):
return render_to_response('settings.html', {})
def edit_tabs(request, org, course, coursename):
location = ['i4x', org, course, 'course', coursename]
course_item = modulestore().get_item(location)
......@@ -898,6 +903,61 @@ def server_error(request):
@login_required
@ensure_csrf_cookie
def course_info(request, org, course, name, provided_id=None):
"""
Send models and views as well as html for editing the course info to the client.
org, course, name: Attributes of the Location for the item to edit
"""
location = ['i4x', org, course, 'course', name]
# check that logged in user has permissions to this item
if not has_access(request.user, location):
raise PermissionDenied()
course_module = modulestore().get_item(location)
# get current updates
location = ['i4x', org, course, 'course_info', "updates"]
return render_to_response('course_info.html', {
'active_tab': 'courseinfo-tab',
'context_course': course_module,
'url_base' : "/" + org + "/" + course + "/",
'course_updates' : json.dumps(get_course_updates(location))
})
@expect_json
@login_required
@ensure_csrf_cookie
def course_info_updates(request, org, course, provided_id=None):
"""
restful CRUD operations on course_info updates.
org, course: Attributes of the Location for the item to edit
provided_id should be none if it's new (create) and a composite of the update db id + index otherwise.
"""
# ??? No way to check for access permission afaik
# get current updates
location = ['i4x', org, course, 'course_info', "updates"]
# NB: we're setting Backbone.emulateHTTP to true on the client so everything comes as a post!!!
if request.method == 'POST' and 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META:
real_method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE']
else:
real_method = request.method
if request.method == 'GET':
return HttpResponse(json.dumps(get_course_updates(location)), mimetype="application/json")
elif real_method == 'POST':
# new instance (unless django makes PUT a POST): updates are coming as POST. Not sure why.
return HttpResponse(json.dumps(update_course_updates(location, request.POST, provided_id)), mimetype="application/json")
elif real_method == 'PUT':
return HttpResponse(json.dumps(update_course_updates(location, request.POST, provided_id)), mimetype="application/json")
elif real_method == 'DELETE': # coming as POST need to pull from Request Header X-HTTP-Method-Override DELETE
return HttpResponse(json.dumps(delete_course_update(location, request.POST, provided_id)), mimetype="application/json")
@login_required
@ensure_csrf_cookie
def asset_index(request, org, course, name):
"""
Display an editable asset library
......
## Derived from and should inherit from a common ancestor w/ ModuleEdit
class CMS.Views.CourseInfoEdit extends Backbone.View
tagName: 'div'
className: 'component'
events:
"click .component-editor .cancel-button": 'clickCancelButton'
"click .component-editor .save-button": 'clickSaveButton'
"click .component-actions .edit-button": 'clickEditButton'
"click .component-actions .delete-button": 'onDelete'
initialize: ->
@render()
$component_editor: => @$el.find('.component-editor')
loadDisplay: ->
XModule.loadModule(@$el.find('.xmodule_display'))
loadEdit: ->
if not @module
@module = XModule.loadModule(@$el.find('.xmodule_edit'))
# don't show metadata (deprecated for course_info)
render: ->
if @model.id
@$el.load("/preview_component/#{@model.id}", =>
@loadDisplay()
@delegateEvents()
)
clickSaveButton: (event) =>
event.preventDefault()
data = @module.save()
@model.save(data).done( =>
# # showToastMessage("Your changes have been saved.", null, 3)
@module = null
@render()
@$el.removeClass('editing')
).fail( ->
showToastMessage("There was an error saving your changes. Please try again.", null, 3)
)
clickCancelButton: (event) ->
event.preventDefault()
@$el.removeClass('editing')
@$component_editor().slideUp(150)
clickEditButton: (event) ->
event.preventDefault()
@$el.addClass('editing')
@$component_editor().slideDown(150)
@loadEdit()
onDelete: (event) ->
# clear contents, don't delete
@model.definition.data = "<ol></ol>"
# TODO change label to 'clear'
onNew: (event) ->
ele = $(@model.definition.data).find("ol")
if (ele)
ele = $(ele).first().prepend("<li><h2>" + $.datepicker.formatDate('MM d', new Date()) + "</h2>/n</li>");
\ No newline at end of file
<%inherit file="base.html" />
<!-- TODO decode course # from context_course into title -->
<%block name="title">Course Info</%block>
<%block name="jsextra">
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
editor = new CMS.Views.CourseInfoEdit({
el: $('.course-updates'),
model : new CMS.Models.Module({id : '${course_updates.location.url()}'})
});
$(".new-update-button").bind('click', editor.onNew);
});
</script>
</%block>
<%block name="content">
<div class="main-wrapper">
<div class="inner-wrapper">
<h1>Course Info</h1>
<div class="main-column">
<div class="window">
<h2>Updates</h2>
<a href="#" class="new-update-button">New Update</a>
<div class="course-updates"></div>
<!-- probably replace w/ a vertical where each element of the vertical is a separate update w/ a date and html field -->
</div>
</div>
<div class="sidebar window">
</div>
</div>
</div>
</%block>
\ No newline at end of file
......@@ -10,6 +10,7 @@
<a href="${reverse('course_index', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" class="class-name">${context_course.display_name}</a>
<ul class="class-nav">
<li><a href="${reverse('course_index', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" id='courseware-tab'>Courseware</a></li>
<li><a href="${reverse('course_info', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" id='courseinfo-tab'>Course Info</a></li>
<li><a href="${reverse('edit_tabs', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, coursename=ctx_loc.name))}" id='pages-tab'>Tabs</a></li>
<li><a href="${reverse('asset_index', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" id='assets-tab'>Assets</a></li>
<li><a href="${reverse('manage_users', kwargs=dict(location=ctx_loc))}" id='users-tab'>Users</a></li>
......
......@@ -34,7 +34,12 @@ urlpatterns = ('',
'contentstore.views.remove_user', name='remove_user'),
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)/remove_user$',
'contentstore.views.remove_user', name='remove_user'),
url(r'^pages/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.static_pages', name='static_pages'),
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/info/(?P<name>[^/]+)$', 'contentstore.views.course_info', name='course_info'),
# ??? Is the following necessary or will the one below work w/ id=None if not sent?
# url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course_info/updates$', 'contentstore.views.course_info_updates', name='course_info'),
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course_info/updates/(?P<provided_id>.*)$', 'contentstore.views.course_info_updates', name='course_info'),
url(r'^pages/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.static_pages',
name='static_pages'),
url(r'^edit_static/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.edit_static', name='edit_static'),
url(r'^edit_tabs/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.edit_tabs', name='edit_tabs'),
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/assets/(?P<name>[^/]+)$', 'contentstore.views.asset_index', name='asset_index'),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment