Commit 85e6c233 by Chris Dodge

work-in-flight for uploading/serving of static content for courses

parent 702c26ea
......@@ -2,14 +2,16 @@ from util.json_request import expect_json
import json
import logging
import sys
import mimetypes
from collections import defaultdict
from django.http import HttpResponse, Http404
from django.http import HttpResponse, Http404, HttpResponseBadRequest, HttpResponseForbidden
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf
from django_future.csrf import ensure_csrf_cookie
from django.core.urlresolvers import reverse
from django.conf import settings
from django import forms
from xmodule.modulestore import Location
from xmodule.x_module import ModuleSystem
......@@ -26,6 +28,13 @@ from functools import partial
from itertools import groupby
from operator import attrgetter
from xmodule.contentstore.django import contentstore
from xmodule.contentstore import StaticContent
#from django.core.cache import cache
from cache_toolbox.core import set_cached_content, get_cached_content
log = logging.getLogger(__name__)
......@@ -89,9 +98,19 @@ def course_index(request, org, course, name):
raise Http404 # TODO (vshnayder): better error
# TODO (cpennington): These need to be read in from the active user
course = modulestore().get_item(location)
weeks = course.get_children()
return render_to_response('course_index.html', {'weeks': weeks})
_course = modulestore().get_item(location)
weeks = _course.get_children()
upload_asset_callback_url = "/{org}/{course}/course/{name}/upload_asset".format(
org = org,
course = course,
name = name
)
return render_to_response('course_index.html', {
'weeks': weeks,
'upload_asset_callback_url': upload_asset_callback_url
})
@login_required
......@@ -115,12 +134,13 @@ def edit_item(request):
lms_link = "{lms_base}/courses/{course_id}/jump_to/{location}".format(
lms_base=settings.LMS_BASE,
# TODO: These will need to be changed to point to the particular instance of this problem in the particular course
course_id=modulestore().get_containing_courses(item.location)[0].id,
course_id= modulestore().get_containing_courses(item.location)[0].id,
location=item.location,
)
else:
lms_link = None
return render_to_response('unit.html', {
'contents': item.get_html(),
'js_module': item.js_module_name,
......@@ -390,3 +410,55 @@ def clone_item(request):
modulestore().update_children(parent_location, parent.definition.get('children', []) + [new_item.location.url()])
return HttpResponse()
'''
cdodge: this method allows for POST uploading of files into the course asset library, which will
be supported by GridFS in MongoDB.
'''
#@login_required
#@ensure_csrf_cookie
def upload_asset(request, org, course, coursename):
if request.method != 'POST':
# (cdodge) @todo: Is there a way to do a - say - 'raise Http400'?
return HttpResponseBadRequest()
# construct a location from the passed in path
location = ['i4x', org, course, 'course', coursename]
if not has_access(request.user, location):
return HttpResponseForbidden()
# Does the course actually exist?!?
try:
item = modulestore().get_item(location)
except:
# no return it as a Bad Request response
logging.error('Could not find course' + location)
return HttpResponseBadRequest()
# compute a 'filename' which is similar to the location formatting, we're using the 'filename'
# nomenclature since we're using a FileSystem paradigm here. We're just imposing
# the Location string formatting expectations to keep things a bit more consistent
name = request.FILES['file'].name
mime_type = request.FILES['file'].content_type
filedata = request.FILES['file'].read()
file_location = StaticContent.compute_location_filename(org, course, name)
content = StaticContent(file_location, name, mime_type, filedata)
# first commit to the DB
contentstore().update(content)
# then update the cache so we're not serving up stale content
set_cached_content(content)
return HttpResponse('Upload completed')
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
......@@ -118,6 +118,7 @@ TEMPLATE_LOADERS = (
)
MIDDLEWARE_CLASSES = (
'contentserver.middleware.StaticContentServer',
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
......@@ -130,7 +131,7 @@ MIDDLEWARE_CLASSES = (
'track.middleware.TrackMiddleware',
'mitxmako.middleware.MakoMiddleware',
'django.middleware.transaction.TransactionMiddleware',
'django.middleware.transaction.TransactionMiddleware'
)
############################ SIGNAL HANDLERS ################################
......
......@@ -28,6 +28,17 @@ MODULESTORE = {
}
}
# cdodge: This is the specifier for the MongoDB (using GridFS) backed static content store
# This is for static content for courseware, not system static content (e.g. javascript, css, edX branding, etc)
CONTENTSTORE = {
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore',
'OPTIONS': {
'host': 'localhost',
'db' : 'xcontent',
}
}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
......
......@@ -7,8 +7,11 @@
<%include file="widgets/navigation.html"/>
<%include file="widgets/upload_assets.html"/>
<section class="main-content">
</section>
</section>
</%block>
......@@ -17,7 +17,9 @@ urlpatterns = ('',
'contentstore.views.course_index', name='course_index'),
url(r'^github_service_hook$', 'github_sync.views.github_post_receive'),
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$',
'contentstore.views.upload_asset', name='upload_asset')
)
# User creation and updating views
......
......@@ -10,6 +10,7 @@ Core methods
from django.core.cache import cache
from django.db import DEFAULT_DB_ALIAS
from xmodule.contentstore import StaticContent
from . import app_settings
......@@ -107,3 +108,19 @@ def instance_key(model, instance_or_pk):
model._meta.module_name,
getattr(instance_or_pk, 'pk', instance_or_pk),
)
def content_key(filename):
return 'content:%s' % (filename)
def set_cached_content(content):
cache.set(content_key(content.filename), content)
def get_cached_content(filename):
return cache.get(content_key(filename))
#def set_cached_content(filename, content_type, data):
# cache.set(content_key(filename), (filename, content_type, data))
#def get_cached_content(filename):
# return cache.get(content_key(filename))
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