Skip to content

Commit

Permalink
Merge pull request openedx#163 from MITx/dormsbee/multicourse
Browse files Browse the repository at this point in the history
Enable multicourse
  • Loading branch information
cpennington committed Jul 11, 2012
2 parents b73b9ee + cc31882 commit f231f91
Show file tree
Hide file tree
Showing 2,442 changed files with 80,283 additions and 6,569 deletions.
11 changes: 8 additions & 3 deletions cms/djangoapps/contentstore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
log = logging.getLogger(__name__)


def import_from_xml(org, course, data_dir):
def import_from_xml(data_dir, course_dirs=None):
"""
Import the specified xml data_dir into the django defined modulestore,
using org and course as the location org and course.
"""
module_store = XMLModuleStore(org, course, data_dir, 'xmodule.raw_module.RawDescriptor', eager=True)
module_store = XMLModuleStore(
data_dir,
default_class='xmodule.raw_module.RawDescriptor',
eager=True,
course_dirs=course_dirs
)
for module in module_store.modules.itervalues():

# TODO (cpennington): This forces import to overrite the same items.
Expand All @@ -26,4 +31,4 @@ def import_from_xml(org, course, data_dir):
modulestore().update_children(module.location, module.definition['children'])
modulestore().update_metadata(module.location, dict(module.metadata))

return module_store.course
return module_store
12 changes: 8 additions & 4 deletions cms/djangoapps/contentstore/management/commands/import.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ class Command(BaseCommand):
'''Import the specified data directory into the default ModuleStore'''

def handle(self, *args, **options):
if len(args) != 3:
raise CommandError("import requires 3 arguments: <org> <course> <data directory>")
if len(args) == 0:
raise CommandError("import requires at least one argument: <data directory> [<course dir>...]")

org, course, data_dir = args
import_from_xml(org, course, data_dir)
data_dir = args[0]
if len(args) > 1:
course_dirs = args[1:]
else:
course_dirs = None
import_from_xml(data_dir, course_dirs)
7 changes: 4 additions & 3 deletions cms/djangoapps/contentstore/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from fs.osfs import OSFS
from django.core.urlresolvers import reverse
from xmodule.modulestore import Location
from github_sync import repo_path_from_location, export_to_github
from github_sync import export_to_github

from mitxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore
Expand Down Expand Up @@ -51,11 +51,12 @@ def save_item(request):
modulestore().update_item(item_id, data)

# Export the course back to github
# This uses wildcarding to find the course, which requires handling
# multiple courses returned, but there should only ever be one
course_location = Location(item_id)._replace(category='course', name=None)
courses = modulestore().get_items(course_location)
for course in courses:
repo_path = repo_path_from_location(course.location)
export_to_github(course, repo_path, "CMS Edit")
export_to_github(course, "CMS Edit")

return HttpResponse(json.dumps({}))

Expand Down
18 changes: 6 additions & 12 deletions cms/djangoapps/github_sync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@

log = logging.getLogger(__name__)


def import_from_github(repo_settings):
"""
Imports data into the modulestore based on the XML stored on github
repo_settings is a dictionary with the following keys:
path: file system path to the local git repo
branch: name of the branch to track on github
org: name of the organization to use in the imported course
course: name of the coures to use in the imported course
"""
repo_path = repo_settings['path']
data_dir, course_dir = os.path.split(repo_path)

if not os.path.isdir(repo_path):
Repo.clone_from(repo_settings['origin'], repo_path)
Expand All @@ -34,18 +34,12 @@ def import_from_github(repo_settings):
# Do a hard reset to the remote branch so that we have a clean import
git_repo.git.checkout(repo_settings['branch'])
git_repo.head.reset('origin/%s' % repo_settings['branch'], index=True, working_tree=True)

return git_repo.head.commit.hexsha, import_from_xml(repo_settings['org'], repo_settings['course'], repo_path)


def repo_path_from_location(location):
location = Location(location)
for name, repo in settings.REPOS.items():
if repo['org'] == location.org and repo['course'] == location.course:
return repo['path']
module_store = import_from_xml(data_dir, course_dirs=[course_dir])
return git_repo.head.commit.hexsha, module_store.courses[course_dir]


def export_to_github(course, repo_path, commit_message):
def export_to_github(course, commit_message):
repo_path = settings.DATA_DIR / course.metadata.get('course_dir', course.location.course)
fs = OSFS(repo_path)
xml = course.export_to_xml(fs)

Expand Down
24 changes: 6 additions & 18 deletions cms/djangoapps/github_sync/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.test import TestCase
from path import path
import shutil
from github_sync import import_from_github, export_to_github, repo_path_from_location
from github_sync import import_from_github, export_to_github
from git import Repo
from django.conf import settings
from xmodule.modulestore.django import modulestore
Expand All @@ -10,6 +10,7 @@
from github_sync.exceptions import GithubSyncError


@override_settings(DATA_DIR=path('test_root'))
class GithubSyncTestCase(TestCase):

def setUp(self):
Expand All @@ -29,8 +30,6 @@ def setUp(self):
'path': self.repo_dir,
'origin': self.remote_dir,
'branch': 'master',
'org': 'org',
'course': 'course'
})

def tearDown(self):
Expand All @@ -49,7 +48,7 @@ def test_import_contents(self):
"""
self.assertEquals('Toy Course', self.import_course.metadata['display_name'])
self.assertIn(
Location('i4x://org/course/chapter/Overview'),
Location('i4x://edx/local_repo/chapter/Overview'),
[child.location for child in self.import_course.get_children()])
self.assertEquals(1, len(self.import_course.get_children()))

Expand All @@ -58,7 +57,7 @@ def test_export_no_pash(self):
"""
Test that with the GITHUB_PUSH feature disabled, no content is pushed to the remote
"""
export_to_github(self.import_course, self.repo_dir, 'Test no-push')
export_to_github(self.import_course, 'Test no-push')
self.assertEquals(1, Repo(self.remote_dir).head.commit.count())

@override_settings(MITX_FEATURES={'GITHUB_PUSH': True})
Expand All @@ -67,7 +66,7 @@ def test_export_push(self):
Test that with GITHUB_PUSH enabled, content is pushed to the remote
"""
self.import_course.metadata['display_name'] = 'Changed display name'
export_to_github(self.import_course, self.repo_dir, 'Test push')
export_to_github(self.import_course, 'Test push')
self.assertEquals(2, Repo(self.remote_dir).head.commit.count())

@override_settings(MITX_FEATURES={'GITHUB_PUSH': True})
Expand All @@ -80,17 +79,6 @@ def test_export_conflict(self):
remote = Repo(self.remote_dir)
remote.git.commit(allow_empty=True, m="Testing conflict commit")

self.assertRaises(GithubSyncError, export_to_github, self.import_course, self.repo_dir, 'Test push')
self.assertRaises(GithubSyncError, export_to_github, self.import_course, 'Test push')
self.assertEquals(2, remote.head.reference.commit.count())
self.assertEquals("Testing conflict commit\n", remote.head.reference.commit.message)


@override_settings(REPOS={'namea': {'path': 'patha', 'org': 'orga', 'course': 'coursea'},
'nameb': {'path': 'pathb', 'org': 'orgb', 'course': 'courseb'}})
class RepoPathLookupTestCase(TestCase):
def test_successful_lookup(self):
self.assertEquals('patha', repo_path_from_location('i4x://orga/coursea/course/foo'))
self.assertEquals('pathb', repo_path_from_location('i4x://orgb/courseb/course/foo'))

def test_failed_lookup(self):
self.assertEquals(None, repo_path_from_location('i4x://c/c/course/foo'))
9 changes: 5 additions & 4 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@

############################# SET PATH INFORMATION #############################
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /mitx/cms
COMMON_ROOT = PROJECT_ROOT.dirname() / "common"
ENV_ROOT = PROJECT_ROOT.dirname().dirname() # virtualenv dir /mitx is in
REPO_ROOT = PROJECT_ROOT.dirname()
COMMON_ROOT = REPO_ROOT / "common"
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /mitx is in
COURSES_ROOT = ENV_ROOT / "data"

# FIXME: To support multiple courses, we should walk the courses dir at startup
DATA_DIR = COURSES_ROOT

sys.path.append(ENV_ROOT)
sys.path.append(REPO_ROOT)
sys.path.append(PROJECT_ROOT / 'djangoapps')
sys.path.append(PROJECT_ROOT / 'lib')
sys.path.append(COMMON_ROOT / 'djangoapps')
Expand Down Expand Up @@ -118,7 +119,7 @@
SITE_ID = 1
SITE_NAME = "localhost:8000"
HTTPS = 'on'
ROOT_URLCONF = 'mitx.cms.urls'
ROOT_URLCONF = 'cms.urls'
IGNORABLE_404_ENDS = ('favicon.ico')

# Email
Expand Down
85 changes: 85 additions & 0 deletions cms/static/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
$(document).ready(function(){
$('section.main-content').children().hide();

$(function(){
$('.editable').inlineEdit();
$('.editable-textarea').inlineEdit({control: 'textarea'});
});

var heighest = 0;
$('.cal ol > li').each(function(){
heighest = ($(this).height() > heighest) ? $(this).height() : heighest;

});

$('.cal ol > li').css('height',heighest + 'px');

$('.add-new-section').click(function() {
return false;
});

$('.new-week .close').click( function(){
$(this).parents('.new-week').hide();
$('p.add-new-week').show();
return false;
});

$('.save-update').click(function(){
$(this).parent().parent().hide();
return false;
});

setHeight = function(){
var windowHeight = $(this).height();
var contentHeight = windowHeight - 29;

$('section.main-content > section').css('min-height', contentHeight);
$('body.content .cal').css('height', contentHeight);

$('.edit-week').click( function() {
$('body').addClass('content');
$('body.content .cal').css('height', contentHeight);
$('section.week-new').show();
return false;
});

$('.cal ol li header h1 a').click( function() {
$('body').addClass('content');
$('body.content .cal').css('height', contentHeight);
$('section.week-edit').show();
return false;
});

$('a.sequence-edit').click(function(){
$('body').addClass('content');
$('body.content .cal').css('height', contentHeight);
$('section.sequence-edit').show();
return false;
});
}

$(document).ready(setHeight);
$(window).bind('resize', setHeight);

$('.video-new a').click(function(){
$('section.video-new').show();
return false;
});

$('a.video-edit').click(function(){
$('section.video-edit').show();
return false;
});

$('.problem-new a').click(function(){
$('section.problem-new').show();
return false;
});

$('a.problem-edit').click(function(){
$('section.problem-edit').show();
return false;
});

});

Loading

0 comments on commit f231f91

Please sign in to comment.