From 02a325b01829432bb3b6f49ab4162bdeb4465fda Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 11 Oct 2012 16:02:58 -0400 Subject: [PATCH] First stab at an import page. Needs styling --- cms/djangoapps/contentstore/views.py | 75 ++++++++++++++++++---------- cms/static/sass/_header.scss | 9 ++++ cms/templates/course_index.html | 2 - cms/templates/index.html | 2 - cms/templates/overview.html | 1 - cms/templates/widgets/header.html | 2 +- cms/urls.py | 8 ++- 7 files changed, 64 insertions(+), 35 deletions(-) diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 535862a784..435729a78a 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -12,6 +12,7 @@ import tarfile import shutil from collections import defaultdict from uuid import uuid4 +from lxml import etree # to install PIL on MacOSX: 'easy_install http://dist.repoze.org/PIL-1.1.6.tar.gz' from PIL import Image @@ -24,6 +25,7 @@ from django_future.csrf import ensure_csrf_cookie from django.core.urlresolvers import reverse from django.conf import settings from django import forms +from django.shortcuts import redirect from xmodule.modulestore import Location from xmodule.x_module import ModuleSystem @@ -51,6 +53,7 @@ from .utils import get_course_location_for_item, get_lms_link_for_item, compute_ from xmodule.templates import all_templates from xmodule.modulestore.xml_importer import import_from_xml +from xmodule.modulestore.xml import edx_xml_parser log = logging.getLogger(__name__) @@ -259,7 +262,8 @@ def edit_unit(request, location): published_date = None return render_to_response('unit.html', { - 'context_course': course, + 'context_course': item, + 'active_tab': 'courseware', 'unit': item, 'unit_location': location, 'components': components, @@ -845,45 +849,62 @@ def asset_index(request, org, course, name): def edge(request): return render_to_response('university_profiles/edge.html', {}) -def import_course(request): - if request.method != 'POST': - # (cdodge) @todo: Is there a way to do a - say - 'raise Http400'? - return HttpResponseBadRequest() - filename = request.FILES['file'].name +def import_course(request, org, course, name): - if not filename.endswith('.tar.gz'): - return HttpResponse(json.dumps({'ErrMsg': 'We only support uploading a .tar.gz file.'})) + location = ['i4x', org, course, 'course', name] - temp_filepath = settings.GITHUB_REPO_ROOT + '/' + filename + # check that logged in user has permissions to this item + if not has_access(request.user, location): + raise PermissionDenied() - logging.debug('importing course to {0}'.format(temp_filepath)) + if request.method == 'POST': + filename = request.FILES['file'].name - # stream out the uploaded files in chunks to disk - temp_file = open(temp_filepath, 'wb+') - for chunk in request.FILES['file'].chunks(): - temp_file.write(chunk) - temp_file.close() + if not filename.endswith('.tar.gz'): + return HttpResponse(json.dumps({'ErrMsg': 'We only support uploading a .tar.gz file.'})) - tf = tarfile.open(temp_filepath) - tf.extractall(settings.GITHUB_REPO_ROOT + '/') + temp_filepath = settings.GITHUB_REPO_ROOT + '/' + filename - os.remove(temp_filepath) # remove the .tar.gz file + logging.debug('importing course to {0}'.format(temp_filepath)) - # @todo: don't assume the top-level directory that was unziped was the same name (but without .tar.gz) + # stream out the uploaded files in chunks to disk + temp_file = open(temp_filepath, 'wb+') + for chunk in request.FILES['file'].chunks(): + temp_file.write(chunk) + temp_file.close() - course_dir = filename.replace('.tar.gz','') + tf = tarfile.open(temp_filepath) + tf.extractall(settings.GITHUB_REPO_ROOT + '/') - module_store, course_items = import_from_xml(modulestore('direct'), settings.GITHUB_REPO_ROOT, - [course_dir], load_error_modules=False,static_content_store=contentstore()) + os.remove(temp_filepath) # remove the .tar.gz file - # remove content directory - we *shouldn't* need this any longer :-) - shutil.rmtree(temp_filepath.replace('.tar.gz', '')) + # @todo: don't assume the top-level directory that was unziped was the same name (but without .tar.gz) - logging.debug('new course at {0}'.format(course_items[0].location)) + course_dir = filename.replace('.tar.gz', '') - create_all_course_groups(request.user, course_items[0].location) + with open(temp_filepath / course_dir / 'course.xml', 'rw') as course_file: + course_data = etree.parse(course_file, parser=edx_xml_parser).getroot() + course_data.set('org', org) + course_data.set('course', course) + course_data.set('url_name', name) + course_data.write(course_file) + module_store, course_items = import_from_xml(modulestore('direct'), settings.GITHUB_REPO_ROOT, + [course_dir], load_error_modules=False, static_content_store=contentstore()) + # remove content directory - we *shouldn't* need this any longer :-) + shutil.rmtree(temp_filepath.replace('.tar.gz', '')) - return HttpResponse(json.dumps({'Status' : 'OK'})) + logging.debug('new course at {0}'.format(course_items[0].location)) + + create_all_course_groups(request.user, course_items[0].location) + + return HttpResponse(json.dumps({'Status': 'OK'})) + else: + course_module = modulestore().get_item(location) + + return render_to_response('import.html', { + 'context_course': course_module, + 'active_tab': 'import', + }) diff --git a/cms/static/sass/_header.scss b/cms/static/sass/_header.scss index be207c600f..061ba759d1 100644 --- a/cms/static/sass/_header.scss +++ b/cms/static/sass/_header.scss @@ -38,6 +38,15 @@ body.no-header { @include active; } + #import-tab { + @include box-shadow(1px 0 0 #787981 inset, -1px 0 0 #3d3e44 inset, 1px 0 0 #787981, -1px 0 0 #3d3e44); + background: rgba(255, 0, 0, .5); + + &:hover { + background: rgba(255, 0, 0, .7); + } + } + .left { width: 700px; } diff --git a/cms/templates/course_index.html b/cms/templates/course_index.html index 37b5a8b371..e490ad7817 100644 --- a/cms/templates/course_index.html +++ b/cms/templates/course_index.html @@ -10,7 +10,5 @@
- <%include file="widgets/upload_assets.html"/> - diff --git a/cms/templates/index.html b/cms/templates/index.html index e63bbbb84d..4b721a0865 100644 --- a/cms/templates/index.html +++ b/cms/templates/index.html @@ -28,6 +28,4 @@ -<%include file="widgets/import-course.html"/> - diff --git a/cms/templates/overview.html b/cms/templates/overview.html index e89d94b9c6..eb114b785f 100644 --- a/cms/templates/overview.html +++ b/cms/templates/overview.html @@ -92,7 +92,6 @@ % endfor - <%include file="widgets/upload_assets.html"/>
diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index b46baebae3..08e998381a 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -13,7 +13,7 @@
  • Pages
  • Assets
  • Users
  • -
  • Import
  • +
  • Import
  • % endif diff --git a/cms/urls.py b/cms/urls.py index 2fd4ed25e8..1c2e70b35d 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -16,8 +16,14 @@ urlpatterns = ('', url(r'^create_draft$', 'contentstore.views.create_draft', name='create_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[^/]+)/(?P[^/]+)/course/(?P[^/]+)$', 'contentstore.views.course_index', name='course_index'), + url(r'^(?P[^/]+)/(?P[^/]+)/import/(?P[^/]+)$', + 'contentstore.views.import_course', name='import_course'), + url(r'^github_service_hook$', 'github_sync.views.github_post_receive'), url(r'^preview/modx/(?P[^/]*)/(?P.*?)/(?P[^/]*)$', 'contentstore.views.preview_dispatch', name='preview_dispatch'), @@ -46,8 +52,6 @@ urlpatterns = ('', url(r'^edge$', 'contentstore.views.edge', name='edge'), url(r'^heartbeat$', include('heartbeat.urls')), - - url(r'import_course$', 'contentstore.views.import_course', name='import_course'), ) # User creation and updating views