From ac71da1535528ed9ab21a613397a13ed0c688d98 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 11 Oct 2012 14:18:02 -0400 Subject: [PATCH 1/6] Make header tabs work --- cms/djangoapps/contentstore/views.py | 27 +++++++++++++++++++++++++- cms/static/sass/_header.scss | 29 ++++++++++++++++++++++++---- cms/templates/base.html | 3 +-- cms/templates/manage_users.html | 1 - cms/templates/overview.html | 2 +- cms/templates/widgets/header.html | 17 ++++++++++------ 6 files changed, 64 insertions(+), 15 deletions(-) diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 85d0253a7e..535862a784 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -157,6 +157,8 @@ def course_index(request, org, course, name): sections = course.get_children() return render_to_response('overview.html', { + 'active_tab': 'courseware', + 'context_course': course, 'sections': sections, 'parent_location': course.location, 'new_section_template': Location('i4x', 'edx', 'templates', 'chapter', 'Empty'), @@ -198,6 +200,7 @@ def edit_subsection(request, location): return render_to_response('edit_subsection.html', {'subsection': item, + 'context_course': course, 'create_new_unit_template': Location('i4x', 'edx', 'templates', 'vertical', 'Empty'), 'lms_link': lms_link, 'parent_item' : parent, @@ -256,6 +259,7 @@ def edit_unit(request, location): published_date = None return render_to_response('unit.html', { + 'context_course': course, 'unit': item, 'unit_location': location, 'components': components, @@ -679,7 +683,11 @@ def manage_users(request, location): if not has_access(request.user, location, role=INSTRUCTOR_ROLE_NAME): raise PermissionDenied() + course_module = modulestore().get_item(location) + return render_to_response('manage_users.html', { + 'active_tab': 'users', + 'context_course': course_module, 'staff': get_users_in_course_group_by_role(location, STAFF_ROLE_NAME), 'add_user_postback_url' : reverse('add_user', args=[location]).rstrip('/'), 'remove_user_postback_url' : reverse('remove_user', args=[location]).rstrip('/') @@ -755,7 +763,19 @@ def landing(request, org, course, coursename): def static_pages(request, org, course, coursename): - return render_to_response('static-pages.html', {}) + + location = ['i4x', org, course, 'course', coursename] + + # check that logged in user has permissions to this item + if not has_access(request.user, location): + raise PermissionDenied() + + course = modulestore().get_item(location) + + return render_to_response('static-pages.html', { + 'active_tab': 'pages', + 'context_course': course, + }) def edit_static(request, org, course, coursename): @@ -784,11 +804,14 @@ def asset_index(request, org, course, name): if not has_access(request.user, location): raise PermissionDenied() + upload_asset_callback_url = reverse('upload_asset', kwargs = { 'org' : org, 'course' : course, 'coursename' : name }) + + course_module = modulestore().get_item(location) course_reference = StaticContent.compute_location(org, course, name) assets = contentstore().get_all_content_for_course(course_reference) @@ -811,6 +834,8 @@ def asset_index(request, org, course, name): asset_display.append(display_info) return render_to_response('asset_index.html', { + 'active_tab': 'assets', + 'context_course': course_module, 'assets': asset_display, 'upload_asset_callback_url': upload_asset_callback_url }) diff --git a/cms/static/sass/_header.scss b/cms/static/sass/_header.scss index d70f53b4df..be207c600f 100644 --- a/cms/static/sass/_header.scss +++ b/cms/static/sass/_header.scss @@ -4,6 +4,11 @@ body.no-header { } } +@mixin active { + @include linear-gradient(top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.3)); + @include box-shadow(0 2px 8px rgba(0, 0, 0, .7) inset); +} + .primary-header { width: 100%; height: 36px; @@ -13,6 +18,26 @@ body.no-header { color: #fff; @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.2), 0 -1px 0px rgba(255, 255, 255, 0.05) inset); + &.active-tab-courseware #courseware-tab { + @include active; + } + + &.active-tab-assets #assets-tab { + @include active; + } + + &.active-tab-pages #pages-tab { + @include active; + } + + &.active-tab-users #users-tab { + @include active; + } + + &.active-tab-import #import-tab { + @include active; + } + .left { width: 700px; } @@ -48,9 +73,5 @@ body.no-header { background: rgba(255, 255, 255, .1); } - &.active { - @include linear-gradient(top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.3)); - @include box-shadow(0 2px 8px rgba(0, 0, 0, .7) inset); - } } } \ No newline at end of file diff --git a/cms/templates/base.html b/cms/templates/base.html index f847ad6f7b..f839cb9753 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -18,8 +18,7 @@ - - <%include file="widgets/header.html"/> + <%include file="widgets/header.html" args="active_tab=active_tab"/> <%include file="courseware_vendor_js.html"/> diff --git a/cms/templates/manage_users.html b/cms/templates/manage_users.html index e479bc0942..142afc2304 100644 --- a/cms/templates/manage_users.html +++ b/cms/templates/manage_users.html @@ -1,7 +1,6 @@ <%inherit file="base.html" /> <%block name="title">Course Staff Manager <%block name="bodyclass">users -<%include file="widgets/header.html"/> <%block name="content">
diff --git a/cms/templates/overview.html b/cms/templates/overview.html index d31e1e4823..e89d94b9c6 100644 --- a/cms/templates/overview.html +++ b/cms/templates/overview.html @@ -83,7 +83,7 @@
- ${units.enum_units(subsection)} + ${units.enum_units(subsection)} % endfor diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index fb436ddde2..b46baebae3 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -1,16 +1,21 @@ <%! from django.core.urlresolvers import reverse %> -
+<% active_tab_class = 'active-tab-' + active_tab if active_tab else '' %> +
- 6.002x Circuits and Electronics + % if context_course: + <% ctx_loc = context_course.location %> + ${context_course.display_name}
    -
  • Courseware
  • -
  • Pages
  • -
  • Assets
  • -
  • Users
  • +
  • Courseware
  • +
  • Pages
  • +
  • Assets
  • +
  • Users
  • +
  • Import
+ % endif
${ user.username } From 02a325b01829432bb3b6f49ab4162bdeb4465fda Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 11 Oct 2012 16:02:58 -0400 Subject: [PATCH 2/6] 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 From c2abd4b537f78a972dbc51c42addd15de00f7231 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 12 Oct 2012 09:03:13 -0400 Subject: [PATCH 3/6] Add import page template --- cms/templates/import.html | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 cms/templates/import.html diff --git a/cms/templates/import.html b/cms/templates/import.html new file mode 100644 index 0000000000..b2385b2baf --- /dev/null +++ b/cms/templates/import.html @@ -0,0 +1,21 @@ +<%inherit file="base.html" /> +<%! from django.core.urlresolvers import reverse %> +<%block name="title">Import +<%block name="bodyclass">import + +<%block name="content"> +
    +
    +

    Import

    +
    +

    Importing a new course will delete all course content currently associated with your course + and replace it with the contents of the uploaded file.

    +

    File uploads must be zip files containing, at a minimum, a

    course.xml
    file.

    +

    Please note that if your course has any problems with auto-generated

    url_name
    s, + re-importing your course could cause the loss of student data associated with those problems.

    +

    Course to import:

    + + +
    +
    + \ No newline at end of file From c7cdaf8080d04a7546c505f1772b3455c8e7beff Mon Sep 17 00:00:00 2001 From: Tom Giannattasio Date: Fri, 12 Oct 2012 10:36:02 -0400 Subject: [PATCH 4/6] styled import page --- cms/static/js/base.js | 14 +++++++ cms/static/sass/_base.scss | 7 ++++ cms/static/sass/_import.scss | 70 +++++++++++++++++++++++++++++++++ cms/static/sass/base-style.scss | 1 + cms/templates/import.html | 25 +++++++----- 5 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 cms/static/sass/_import.scss diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 9cb09d733c..8602770d24 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -51,8 +51,22 @@ $(document).ready(function() { $('.remove-policy-data').bind('click', removePolicyMetadata); $('.sync-date').bind('click', syncReleaseDate); + + // import form setup + $('.import .file-input').bind('change', showImportSubmit); + $('.import .choose-file-button, .import .choose-file-button-inline').bind('click', function(e) { + e.preventDefault(); + $('.import .file-input').click(); + }); }); +function showImportSubmit(e) { + $('.file-name').html($(this).val()) + $('.file-name-block').show(); + $('.import .choose-file-button').hide(); + $('.submit-button').show(); +} + function syncReleaseDate(e) { e.preventDefault(); $("#start_date").val(""); diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss index 05e40c9483..69b51b727e 100644 --- a/cms/static/sass/_base.scss +++ b/cms/static/sass/_base.scss @@ -119,6 +119,13 @@ label { font-size: 12px; } +code { + padding: 0 4px; + border-radius: 3px; + background: #eee; + font-family: Monaco, monospace; +} + .text-editor { width: 100%; min-height: 80px; diff --git a/cms/static/sass/_import.scss b/cms/static/sass/_import.scss new file mode 100644 index 0000000000..f9480a6d46 --- /dev/null +++ b/cms/static/sass/_import.scss @@ -0,0 +1,70 @@ +.import { + .import-overview { + @extend .window; + @include clearfix; + padding: 30px 40px; + } + + .description { + float: left; + width: 62%; + margin-right: 3%; + font-size: 14px; + + h3 { + margin-bottom: 20px; + font-size: 18px; + font-weight: 700; + color: $error-red; + } + + p + p { + margin-top: 20px; + } + } + + .import-form { + float: left; + width: 35%; + padding: 25px 30px 35px; + @include box-sizing(border-box); + border: 1px solid $mediumGrey; + border-radius: 3px; + background: $lightGrey; + text-align: center; + + h2 { + margin-bottom: 30px; + font-size: 26px; + font-weight: 300; + } + + .file-name-block { + display: none; + margin-bottom: 15px; + font-size: 13px; + } + + .choose-file-button { + @include blue-button; + padding: 10px 50px 11px; + font-size: 17px; + } + + .choose-file-button-inline { + display: block; + } + + .file-input { + display: none; + } + + .submit-button { + @include orange-button; + display: none; + max-width: 100%; + padding: 8px 20px 10px; + white-space: normal; + } + } +} \ No newline at end of file diff --git a/cms/static/sass/base-style.scss b/cms/static/sass/base-style.scss index f2256f97ed..0824cc380d 100644 --- a/cms/static/sass/base-style.scss +++ b/cms/static/sass/base-style.scss @@ -16,6 +16,7 @@ @import "assets"; @import "static-pages"; @import "users"; +@import "import"; @import "course-info"; @import "landing"; @import "graphics"; diff --git a/cms/templates/import.html b/cms/templates/import.html index b2385b2baf..dadb02763e 100644 --- a/cms/templates/import.html +++ b/cms/templates/import.html @@ -7,15 +7,22 @@

    Import

    -
    -

    Importing a new course will delete all course content currently associated with your course - and replace it with the contents of the uploaded file.

    -

    File uploads must be zip files containing, at a minimum, a

    course.xml
    file.

    -

    Please note that if your course has any problems with auto-generated

    url_name
    s, - re-importing your course could cause the loss of student data associated with those problems.

    -

    Course to import:

    - - +
    +
    +

    Importing a new course will delete all course content currently associated with your course + and replace it with the contents of the uploaded file.

    +

    File uploads must be zip files containing, at a minimum, a course.xml file.

    +

    Please note that if your course has any problems with auto-generated url_name nodes, + re-importing your course could cause the loss of student data associated with those problems.

    +
    +
    +

    Course to import:

    + Choose File +

    change

    + + +
    +
    \ No newline at end of file From 3d2a1c2493fb11c7abaec460880776e58f9e00bf Mon Sep 17 00:00:00 2001 From: Tom Giannattasio Date: Fri, 12 Oct 2012 10:39:43 -0400 Subject: [PATCH 5/6] =?UTF-8?q?removed=20red=20import=20button=20=E2=80=93?= =?UTF-8?q?=20drawing=20too=20much=20attention;=20this=20will=20be=20rewor?= =?UTF-8?q?ked=20onto=20a=20different=20page=20at=20some=20point=20anyways?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cms/static/sass/_header.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cms/static/sass/_header.scss b/cms/static/sass/_header.scss index 061ba759d1..5255819a60 100644 --- a/cms/static/sass/_header.scss +++ b/cms/static/sass/_header.scss @@ -40,11 +40,6 @@ body.no-header { #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 { From c70f29e83a00c92dcbdb9dd46d82f831b9e79816 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 12 Oct 2012 12:40:03 -0400 Subject: [PATCH 6/6] Wire up import to the frontend, and make sure that it puts it into the already extant course --- cms/djangoapps/contentstore/views.py | 35 +++++++++++++++++----------- cms/templates/import.html | 31 +++++++++++++++++++++++- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 435729a78a..6375f90d4e 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -13,6 +13,8 @@ import shutil from collections import defaultdict from uuid import uuid4 from lxml import etree +from path import path +from shutil import rmtree # to install PIL on MacOSX: 'easy_install http://dist.repoze.org/PIL-1.1.6.tar.gz' from PIL import Image @@ -849,7 +851,8 @@ def asset_index(request, org, course, name): def edge(request): return render_to_response('university_profiles/edge.html', {}) - +@ensure_csrf_cookie +@login_required def import_course(request, org, course, name): location = ['i4x', org, course, 'course', name] @@ -859,42 +862,48 @@ def import_course(request, org, course, name): raise PermissionDenied() if request.method == 'POST': - filename = request.FILES['file'].name + filename = request.FILES['course-data'].name if not filename.endswith('.tar.gz'): return HttpResponse(json.dumps({'ErrMsg': 'We only support uploading a .tar.gz file.'})) - temp_filepath = settings.GITHUB_REPO_ROOT + '/' + filename + data_root = path(settings.GITHUB_REPO_ROOT) + + temp_filepath = data_root / filename logging.debug('importing course to {0}'.format(temp_filepath)) # stream out the uploaded files in chunks to disk temp_file = open(temp_filepath, 'wb+') - for chunk in request.FILES['file'].chunks(): + for chunk in request.FILES['course-data'].chunks(): temp_file.write(chunk) temp_file.close() + # @todo: don't assume the top-level directory that was unziped was the same name (but without .tar.gz) + course_dir = filename.replace('.tar.gz', '') + tf = tarfile.open(temp_filepath) - tf.extractall(settings.GITHUB_REPO_ROOT + '/') + shutil.rmtree(data_root / course_dir) + tf.extractall(data_root + '/') os.remove(temp_filepath) # remove the .tar.gz file - # @todo: don't assume the top-level directory that was unziped was the same name (but without .tar.gz) - course_dir = filename.replace('.tar.gz', '') + with open(data_root / course_dir / 'course.xml', 'r') as course_file: + course_data = etree.parse(course_file, parser=edx_xml_parser) + course_data_root = course_data.getroot() + course_data_root.set('org', org) + course_data_root.set('course', course) + course_data_root.set('url_name', name) - 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) + with open(data_root / course_dir / 'course.xml', 'w') as course_file: 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', '')) + shutil.rmtree(data_root / course_dir) logging.debug('new course at {0}'.format(course_items[0].location)) diff --git a/cms/templates/import.html b/cms/templates/import.html index dadb02763e..16e1353870 100644 --- a/cms/templates/import.html +++ b/cms/templates/import.html @@ -15,7 +15,7 @@

    Please note that if your course has any problems with auto-generated url_name nodes, re-importing your course could cause the loss of student data associated with those problems.

    -
    +

    Course to import:

    Choose File

    change

    @@ -25,4 +25,33 @@ + + +<%block name="jsextra"> + + \ No newline at end of file