From 630607d34554aef03f4e74adbdf26f0dd3b01496 Mon Sep 17 00:00:00 2001 From: ichuang Date: Tue, 5 Feb 2013 00:21:04 +0000 Subject: [PATCH 01/66] fix forum management commands (assign_default_role moved); add reload_forum_users --- .../commands/assign_roles_for_course.py | 3 +- .../commands/create_roles_for_existing.py | 3 +- .../management/commands/reload_forum_users.py | 29 +++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 lms/djangoapps/django_comment_client/management/commands/reload_forum_users.py diff --git a/lms/djangoapps/django_comment_client/management/commands/assign_roles_for_course.py b/lms/djangoapps/django_comment_client/management/commands/assign_roles_for_course.py index 82f2290bc7..64378108b6 100644 --- a/lms/djangoapps/django_comment_client/management/commands/assign_roles_for_course.py +++ b/lms/djangoapps/django_comment_client/management/commands/assign_roles_for_course.py @@ -6,7 +6,8 @@ Enrollments. """ from django.core.management.base import BaseCommand, CommandError -from student.models import CourseEnrollment, assign_default_role +from student.models import CourseEnrollment +from django_comment_client.models import assign_default_role class Command(BaseCommand): args = 'course_id' diff --git a/lms/djangoapps/django_comment_client/management/commands/create_roles_for_existing.py b/lms/djangoapps/django_comment_client/management/commands/create_roles_for_existing.py index d1244a6690..3ec2d0646e 100644 --- a/lms/djangoapps/django_comment_client/management/commands/create_roles_for_existing.py +++ b/lms/djangoapps/django_comment_client/management/commands/create_roles_for_existing.py @@ -6,7 +6,8 @@ Enrollments. """ from django.core.management.base import BaseCommand, CommandError -from student.models import CourseEnrollment, assign_default_role +from student.models import CourseEnrollment +from django_comment_client.models import assign_default_role class Command(BaseCommand): args = 'course_id' diff --git a/lms/djangoapps/django_comment_client/management/commands/reload_forum_users.py b/lms/djangoapps/django_comment_client/management/commands/reload_forum_users.py new file mode 100644 index 0000000000..5e7e268270 --- /dev/null +++ b/lms/djangoapps/django_comment_client/management/commands/reload_forum_users.py @@ -0,0 +1,29 @@ +""" +Reload forum (comment client) users from existing users. +""" +from django.core.management.base import BaseCommand, CommandError + +from django.contrib.auth.models import User +import comment_client as cc + +class Command(BaseCommand): + help = 'Reload forum (comment client) users from existing users' + + def adduser(self,user): + print user + try: + cc_user = cc.User.from_django_user(user) + cc_user.save() + except Exception as err: + print "update user info to discussion failed for user with id: %s" % user + + def handle(self, *args, **options): + if len(args) != 0: + uset = [User.objects.get(username=x) for x in args] + else: + uset = User.objects.all() + + for user in uset: + self.adduser(user) + + \ No newline at end of file From b3f00a672504e70e66a38d9d35f85df48ff70afd Mon Sep 17 00:00:00 2001 From: ichuang Date: Sun, 31 Mar 2013 12:22:00 +0000 Subject: [PATCH 02/66] add default message to conditional --- common/lib/xmodule/xmodule/conditional_module.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py index b3e0e0e06b..2433a143ed 100644 --- a/common/lib/xmodule/xmodule/conditional_module.py +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -125,7 +125,8 @@ class ConditionalModule(ConditionalFields, XModule): an AJAX call. """ if not self.is_condition_satisfied(): - message = self.descriptor.xml_attributes.get('message') + defmsg = "{link} must be attempted before this will become visible." + message = self.descriptor.xml_attributes.get('message', defmsg) context = {'module': self, 'message': message} html = self.system.render_template('conditional_module.html', From 14899b90667902aca65732acd942b04f22764b04 Mon Sep 17 00:00:00 2001 From: ichuang Date: Sat, 30 Mar 2013 03:40:40 +0000 Subject: [PATCH 03/66] fix lms migration to be compatible with xblock --- lms/djangoapps/lms_migration/migrate.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lms/djangoapps/lms_migration/migrate.py b/lms/djangoapps/lms_migration/migrate.py index 569129f469..a677383035 100644 --- a/lms/djangoapps/lms_migration/migrate.py +++ b/lms/djangoapps/lms_migration/migrate.py @@ -39,12 +39,14 @@ def getip(request): def get_commit_id(course): - return course.metadata.get('GIT_COMMIT_ID', 'No commit id') + #return course.metadata.get('GIT_COMMIT_ID', 'No commit id') + return getattr(course, 'GIT_COMMIT_ID', 'No commit id') # getattr(def_ms.courses[reload_dir], 'GIT_COMMIT_ID','No commit id') def set_commit_id(course, commit_id): - course.metadata['GIT_COMMIT_ID'] = commit_id + #course.metadata['GIT_COMMIT_ID'] = commit_id + setattr(course, 'GIT_COMMIT_ID', commit_id) # setattr(def_ms.courses[reload_dir], 'GIT_COMMIT_ID', new_commit_id) @@ -124,7 +126,8 @@ def manage_modulestores(request, reload_dir=None, commit_id=None): #---------------------------------------- - dumpfields = ['definition', 'location', 'metadata'] + #dumpfields = ['definition', 'location', 'metadata'] + dumpfields = ['location', 'metadata'] for cdir, course in def_ms.courses.items(): html += '
' @@ -133,7 +136,7 @@ def manage_modulestores(request, reload_dir=None, commit_id=None): html += '

commit_id=%s

' % get_commit_id(course) for field in dumpfields: - data = getattr(course, field) + data = getattr(course, field, None) html += '

%s

' % field if type(data) == dict: html += '
    ' From f1cc6e85976c634dc0a79ee5f9b3a5fbd753bf85 Mon Sep 17 00:00:00 2001 From: ichuang Date: Sat, 30 Mar 2013 02:01:32 +0000 Subject: [PATCH 04/66] fix psychoanalyze - make compatible with xblock --- common/lib/xmodule/xmodule/capa_module.py | 2 +- lms/djangoapps/psychometrics/psychoanalyze.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index b437478ecc..83710fd121 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -755,7 +755,7 @@ class CapaModule(CapaFields, XModule): self.system.track_function('save_problem_check', event_info) if hasattr(self.system, 'psychometrics_handler'): # update PsychometricsData using callback - self.system.psychometrics_handler(self.get_instance_state()) + self.system.psychometrics_handler(self.get_state_for_lcp()) # render problem into HTML html = self.get_problem_html(encapsulate=False) diff --git a/lms/djangoapps/psychometrics/psychoanalyze.py b/lms/djangoapps/psychometrics/psychoanalyze.py index 3e9edcc997..008a4034a5 100644 --- a/lms/djangoapps/psychometrics/psychoanalyze.py +++ b/lms/djangoapps/psychometrics/psychoanalyze.py @@ -302,12 +302,12 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key): Construct and return a procedure which may be called to update the PsychometricsData instance for the given StudentModule instance. """ - sm = studentmodule.objects.get_or_create( - course_id=course_id, - student=user, - module_state_key=module_state_key, - defaults={'state': '{}', 'module_type': 'problem'}, - ) + sm, status = StudentModule.objects.get_or_create( + course_id=course_id, + student=user, + module_state_key=module_state_key, + defaults={'state': '{}', 'module_type': 'problem'}, + ) try: pmd = PsychometricData.objects.using(db).get(studentmodule=sm) From 26f14aaf6d6be3c7d8fee91c63ef54a838ab5686 Mon Sep 17 00:00:00 2001 From: ichuang Date: Sun, 31 Mar 2013 12:21:22 +0000 Subject: [PATCH 05/66] fix psychoanalyze (compatibility with new xblock) --- lms/djangoapps/psychometrics/psychoanalyze.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/psychometrics/psychoanalyze.py b/lms/djangoapps/psychometrics/psychoanalyze.py index 008a4034a5..b6072ac997 100644 --- a/lms/djangoapps/psychometrics/psychoanalyze.py +++ b/lms/djangoapps/psychometrics/psychoanalyze.py @@ -329,7 +329,11 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key): return pmd.done = done - pmd.attempts = state['attempts'] + try: + pmd.attempts = state.get('attempts',0) + except: + log.exception("no attempts for %s (state=%s)" % (sm,sm.state)) + try: checktimes = eval(pmd.checktimes) # update log of attempt timestamps except: From febcb5113308fc5b9056558150ff70acb8a30cd0 Mon Sep 17 00:00:00 2001 From: ichuang Date: Sun, 31 Mar 2013 12:52:29 +0000 Subject: [PATCH 06/66] make psychometrics curve fitting more robust --- lms/djangoapps/psychometrics/psychoanalyze.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lms/djangoapps/psychometrics/psychoanalyze.py b/lms/djangoapps/psychometrics/psychoanalyze.py index b6072ac997..093051a3bd 100644 --- a/lms/djangoapps/psychometrics/psychoanalyze.py +++ b/lms/djangoapps/psychometrics/psychoanalyze.py @@ -246,13 +246,16 @@ def generate_plots_for_problem(problem): yset['ydat'] = ydat if len(ydat) > 3: # try to fit to logistic function if enough data points - cfp = curve_fit(func_2pl, xdat, ydat, [1.0, max_attempts / 2.0]) - yset['fitparam'] = cfp - yset['fitpts'] = func_2pl(np.array(xdat), *cfp[0]) - yset['fiterr'] = [yd - yf for (yd, yf) in zip(ydat, yset['fitpts'])] - fitx = np.linspace(xdat[0], xdat[-1], 100) - yset['fitx'] = fitx - yset['fity'] = func_2pl(np.array(fitx), *cfp[0]) + try: + cfp = curve_fit(func_2pl, xdat, ydat, [1.0, max_attempts / 2.0]) + yset['fitparam'] = cfp + yset['fitpts'] = func_2pl(np.array(xdat), *cfp[0]) + yset['fiterr'] = [yd - yf for (yd, yf) in zip(ydat, yset['fitpts'])] + fitx = np.linspace(xdat[0], xdat[-1], 100) + yset['fitx'] = fitx + yset['fity'] = func_2pl(np.array(fitx), *cfp[0]) + except Exception as err: + log.debug('Error in psychoanalyze curve fitting: %s' % err) dataset['grade_%d' % grade] = yset From de5fa56b191d37e1a6a2dd5bdb14e20d0a7c6091 Mon Sep 17 00:00:00 2001 From: ichuang Date: Sun, 31 Mar 2013 13:18:54 +0000 Subject: [PATCH 07/66] add dump of description of grading configuration to instructor dashboard --- lms/djangoapps/instructor/views.py | 51 +++++++++++++++++++ .../courseware/instructor_dashboard.html | 1 + 2 files changed, 52 insertions(+) diff --git a/lms/djangoapps/instructor/views.py b/lms/djangoapps/instructor/views.py index 671283db9f..9bae77e82b 100644 --- a/lms/djangoapps/instructor/views.py +++ b/lms/djangoapps/instructor/views.py @@ -208,6 +208,10 @@ def instructor_dashboard(request, course_id): track.views.server_track(request, 'dump-answer-dist-csv', {}, page='idashboard') return return_csv('answer_dist_{0}.csv'.format(course_id), get_answers_distribution(request, course_id)) + elif 'Dump description of graded assignments configuration' in action: + track.views.server_track(request, action, {}, page='idashboard') + msg += dump_grading_context(course) + elif "Reset student's attempts" in action or "Delete student state for problem" in action: # get the form data unique_student_identifier = request.POST.get('unique_student_identifier', '') @@ -1120,3 +1124,50 @@ def compute_course_stats(course): walk(course) stats = dict(counts) # number of each kind of module return stats + + +def dump_grading_context(course): + ''' + Dump information about course grading context (eg which problems are graded in what assignments) + Very useful for debugging grading_policy.json and policy.json + ''' + msg = "-----------------------------------------------------------------------------\n" + msg += "Course grader:\n" + + msg += '%s\n' % course.grader.__class__ + graders = {} + if 'WeightedSubsectionsGrader' in str(course.grader.__class__): + msg += '\n' + msg += "Graded sections:\n" + for subgrader, category, weight in course.grader.sections: + msg += " subgrader=%s, type=%s, category=%s, weight=%s\n" % (subgrader.__class__, subgrader.type, category, weight) + subgrader.index = 1 + graders[subgrader.type] = subgrader + msg += "-----------------------------------------------------------------------------\n" + msg += "Listing grading context for course %s\n" % course.id + + gc = course.grading_context + msg += "graded sections:\n" + + msg += '%s\n' % gc['graded_sections'].keys() + for (gs, gsvals) in gc['graded_sections'].items(): + msg += "--> Section %s:\n" % (gs) + for sec in gsvals: + s = sec['section_descriptor'] + format = getattr(s, 'format', None) + aname = '' + if format in graders: + g = graders[format] + aname = '%s %02d' % (g.short_label, g.index) + g.index += 1 + elif s.display_name in graders: + g = graders[s.display_name] + aname = '%s' % g.short_label + notes = '' + if getattr(s, 'score_by_attempt', False): + notes = ', score by attempt!' + msg += " %s (format=%s, Assignment=%s%s)\n" % (s.display_name, format, aname, notes) + msg += "all descriptors:\n" + msg += "length=%d\n" % len(gc['all_descriptors']) + msg = '
    %s
    ' % msg.replace('<','<') + return msg diff --git a/lms/templates/courseware/instructor_dashboard.html b/lms/templates/courseware/instructor_dashboard.html index 23329c837d..df1d081354 100644 --- a/lms/templates/courseware/instructor_dashboard.html +++ b/lms/templates/courseware/instructor_dashboard.html @@ -156,6 +156,7 @@ function goto( mode)

    +


    From a0fab132a1e8f7dcf7803c0460eaa717761f5a35 Mon Sep 17 00:00:00 2001 From: ichuang Date: Sun, 31 Mar 2013 15:50:00 +0000 Subject: [PATCH 08/66] sort course index in studio my courses page --- cms/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/templates/index.html b/cms/templates/index.html index 9482b9d9af..9ce764ed8d 100644 --- a/cms/templates/index.html +++ b/cms/templates/index.html @@ -67,7 +67,7 @@
    % if user.is_active: From 15d1bc372d44c5b907ac5675acea351569ad95de Mon Sep 17 00:00:00 2001 From: ichuang Date: Sun, 31 Mar 2013 19:28:09 +0000 Subject: [PATCH 10/66] clean up xqueue callback url generation; allow override from settings --- lms/djangoapps/courseware/module_render.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 7a40d5c458..c7c749d2a0 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -177,18 +177,13 @@ def get_module_for_descriptor(user, request, descriptor, model_data_cache, cours # Intended use is as {ajax_url}/{dispatch_command}, so get rid of the trailing slash. ajax_url = ajax_url.rstrip('/') - # Fully qualified callback URL for external queueing system - xqueue_callback_url = '{proto}://{host}'.format( - host=request.get_host(), - proto=request.META.get('HTTP_X_FORWARDED_PROTO', 'https' if request.is_secure() else 'http') - ) - def make_xqueue_callback(dispatch='score_update'): # Fully qualified callback URL for external queueing system xqueue_callback_url = '{proto}://{host}'.format( host=request.get_host(), proto=request.META.get('HTTP_X_FORWARDED_PROTO', 'https' if request.is_secure() else 'http') ) + xqueue_callback_url = settings.XQUEUE_INTERFACE.get('callback_url',xqueue_callback_url) # allow override xqueue_callback_url += reverse('xqueue_callback', kwargs=dict(course_id=course_id, From 025c5df16e5c9c210a9eb74331f69f9a34d5e433 Mon Sep 17 00:00:00 2001 From: ichuang Date: Mon, 1 Apr 2013 21:49:11 +0000 Subject: [PATCH 11/66] fix IntegrityError duplicate entry issue with module_data Scope.student_state update --- lms/djangoapps/courseware/model_data.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/courseware/model_data.py b/lms/djangoapps/courseware/model_data.py index b725f64308..e5c8eec216 100644 --- a/lms/djangoapps/courseware/model_data.py +++ b/lms/djangoapps/courseware/model_data.py @@ -241,9 +241,10 @@ class ModelDataCache(object): field_object, _ = StudentModule.objects.get_or_create( course_id=self.course_id, student=self.user, - module_type=key.block_scope_id.category, module_state_key=key.block_scope_id.url(), - defaults={'state': json.dumps({})}, + defaults={'state': json.dumps({}), + 'module_type': key.block_scope_id.category, + }, ) elif key.scope == Scope.content: field_object, _ = XModuleContentField.objects.get_or_create( From c658c6514925634ad26c676011aaa59835efa56c Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Mon, 25 Mar 2013 15:00:45 -0400 Subject: [PATCH 12/66] Add new Matlab unit tests. --- common/lib/capa/capa/tests/test_inputtypes.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/common/lib/capa/capa/tests/test_inputtypes.py b/common/lib/capa/capa/tests/test_inputtypes.py index 250cedd549..911fdd07d2 100644 --- a/common/lib/capa/capa/tests/test_inputtypes.py +++ b/common/lib/capa/capa/tests/test_inputtypes.py @@ -381,6 +381,32 @@ class MatlabTest(unittest.TestCase): self.assertEqual(context, expected) + def test_rendering_while_queued(self): + state = {'value': 'print "good evening"', + 'status': 'incomplete', + 'input_state': {'queuestate': 'queued'}, + } + elt = etree.fromstring(self.xml) + + input_class = lookup_tag('matlabinput') + the_input = self.input_class(test_system, elt, state) + context = the_input._get_render_context() + expected = {'id': 'prob_1_2', + 'value': 'print "good evening"', + 'status': 'queued', + 'msg': self.input_class.plot_submitted_msg, + 'mode': self.mode, + 'rows': self.rows, + 'cols': self.cols, + 'queue_msg': '', + 'linenumbers': 'true', + 'hidden': '', + 'tabsize': int(self.tabsize), + 'queue_len': '1', + } + + self.assertEqual(context, expected) + def test_plot_data(self): get = {'submission': 'x = 1234;'} response = self.the_input.handle_ajax("plot", get) @@ -391,6 +417,43 @@ class MatlabTest(unittest.TestCase): self.assertTrue(self.the_input.input_state['queuekey'] is not None) self.assertEqual(self.the_input.input_state['queuestate'], 'queued') + def test_ungraded_response_success(self): + queuekey = 'abcd' + input_state = {'queuekey': queuekey, 'queuestate': 'queued'} + state = {'value': 'print "good evening"', + 'status': 'incomplete', + 'input_state': input_state, + 'feedback': {'message': '3'}, } + elt = etree.fromstring(self.xml) + + the_input = self.input_class(test_system, elt, state) + inner_msg = 'hello!' + queue_msg = json.dumps({'msg': inner_msg}) + + the_input.ungraded_response(queue_msg, queuekey) + self.assertTrue(input_state['queuekey'] is None) + self.assertTrue(input_state['queuestate'] is None) + self.assertEqual(input_state['queue_msg'], inner_msg) + + def test_ungraded_response_key_mismatch(self): + queuekey = 'abcd' + input_state = {'queuekey': queuekey, 'queuestate': 'queued'} + state = {'value': 'print "good evening"', + 'status': 'incomplete', + 'input_state': input_state, + 'feedback': {'message': '3'}, } + elt = etree.fromstring(self.xml) + + the_input = self.input_class(test_system, elt, state) + inner_msg = 'hello!' + queue_msg = json.dumps({'msg': inner_msg}) + + the_input.ungraded_response(queue_msg, 'abc') + self.assertEqual(input_state['queuekey'], queuekey) + self.assertEqual(input_state['queuestate'], 'queued') + self.assertFalse('queue_msg' in input_state) + + From 8cd4220b5fb79e211d61ac16555694d68abeb3c1 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Wed, 3 Apr 2013 09:15:38 -0400 Subject: [PATCH 13/66] Fix the conditions by which we show the queueing message for Matlab inputs --- common/lib/capa/capa/inputtypes.py | 6 +++--- common/lib/capa/capa/tests/test_inputtypes.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index b4e9fe1654..901ab25e60 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -655,11 +655,11 @@ class MatlabInput(CodeInput): # Check if problem has been queued self.queuename = 'matlab' self.queue_msg = '' - if 'queue_msg' in self.input_state and self.status in ['queued','incomplete', 'unsubmitted']: + if 'queue_msg' in self.input_state and self.status in ['queued', 'incomplete', 'unsubmitted']: self.queue_msg = self.input_state['queue_msg'] - if 'queued' in self.input_state and self.input_state['queuestate'] is not None: + if 'queuestate' in self.input_state and self.input_state['queuestate'] == 'queued': self.status = 'queued' - self.queue_len = 1 + self.queue_len = '1' self.msg = self.plot_submitted_msg diff --git a/common/lib/capa/capa/tests/test_inputtypes.py b/common/lib/capa/capa/tests/test_inputtypes.py index 911fdd07d2..e7f0b784bc 100644 --- a/common/lib/capa/capa/tests/test_inputtypes.py +++ b/common/lib/capa/capa/tests/test_inputtypes.py @@ -361,7 +361,6 @@ class MatlabTest(unittest.TestCase): 'feedback': {'message': '3'}, } elt = etree.fromstring(self.xml) - input_class = lookup_tag('matlabinput') the_input = self.input_class(test_system, elt, state) context = the_input._get_render_context() @@ -388,7 +387,6 @@ class MatlabTest(unittest.TestCase): } elt = etree.fromstring(self.xml) - input_class = lookup_tag('matlabinput') the_input = self.input_class(test_system, elt, state) context = the_input._get_render_context() expected = {'id': 'prob_1_2', From 9f9748b9fa72c77b66fc4a282e61049ace7342fd Mon Sep 17 00:00:00 2001 From: Victor Shnayder Date: Wed, 3 Apr 2013 14:26:06 -0400 Subject: [PATCH 14/66] Stanford press release --- lms/templates/feed.rss | 11 ++- .../press_releases/stanford_announcement.html | 92 +++++++++++++++++++ lms/urls.py | 3 + 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 lms/templates/static_templates/press_releases/stanford_announcement.html diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index a6fda0d20a..b68a9ceb27 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -6,7 +6,16 @@ EdX Blog - 2013-03-15T14:00:12-07:00 + 2013-04-03T14:00:12-07:00 + + tag:www.edx.org,2012:Post/17 + 2012-12-19T14:00:00-07:00 + 2012-12-19T14:00:00-07:00 + + Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform + <img src="${static.url('images/press/releases/edx-logo_240x180.png')}" /> + <p></p> + tag:www.edx.org,2013:Post/16 2013-03-15T10:00:00-07:00 diff --git a/lms/templates/static_templates/press_releases/stanford_announcement.html b/lms/templates/static_templates/press_releases/stanford_announcement.html new file mode 100644 index 0000000000..be788f319c --- /dev/null +++ b/lms/templates/static_templates/press_releases/stanford_announcement.html @@ -0,0 +1,92 @@ +<%! from django.core.urlresolvers import reverse %> +<%inherit file="../../main.html" /> + +<%namespace name='static' file='../../static_content.html'/> + +<%block name="title">Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform +
    + + +
    +
    +

    Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform

    +
    +
    +

    edX Learning Platform to be open source and available on June 1

    + +

    CAMBRIDGE, MA and STANFORD, CA – April 3, 2013 – + +Stanford University and edX, the not-for-profit online learning enterprise founded by Harvard University and the Massachusetts Institute of Technology (MIT), today announced their collaboration to advance the development of edX’s open source learning platform and provide free and open online learning tools for institutions around the world.

    + +

    As part of this announcement, edX will release the source code for its entire online learning platform on June 1, 2013. In support of that move, Stanford will integrate features of its existing Class2Go platform into the edX platform, use the integration as an internal platform for online coursework for on-campus and distance learners, and work collaboratively with edX and other institutions to further develop the edX platform.

    + +

    “This collaboration brings together two leaders in online education in a common effort to ensure that the world’s universities have the strongest possible not-for-profit, open source platform available to them,” said John Mitchell, vice provost for online learning at Stanford University. “A not-for-profit, open source platform will help universities experiment with different ways to produce and share content, fostering continued innovation through a vibrant community of contributors.”

    + +

    EdX and Stanford will collaborate along with others around the globe on the ongoing development and refinement of the edX online learning platform. As of June 1, developers everywhere will be able to freely access the source code of the edX learning platform, including code for its Learning Management System (LMS); Studio, a course authoring tool; xBlock, an application programming interface (API) for integrating third-party learning objects; and machine grading API’s. EdX will support and nurture the community of developers contributing to the enhancement of the edX platform by providing a rich environment for developer collaboration as well as technical and process guidelines to facilitate developer contributions.

    + +

    “It has been our vision to offer our platform as open source since edX’s founding by Harvard and MIT,” stated Anant Agarwal, president of edX. “We are now realizing that vision, and I am pleased to welcome Stanford University, one of the world’s leading institutions of higher education, to further this global open source solution. I want to acknowledge the key role played by our X Consortium member UC Berkeley, which was instrumental in fostering this collaboration. We believe the edX platform—the Linux of learning—will benefit from all the world’s institutions and communities.”

    + +

    EdX is pursuing an open source vision to enhance access to higher education for the entire world. One of the chief benefits of massive open online courses (MOOCs) is that they bring together a tremendously diverse student body to learn with and from each other. EdX has chosen to extend that perspective to its learning platform as well, knowing that drawing upon the global community of developers is an effective route to both transform and deliver the world’s best and most accessible online and blended learning experience.

    + +

    MOOCs and innovative online teaching approaches on college campuses, such as the “flipped classroom,” use web environments that support interactive video, online discussion, social/cohort interaction, assessment and other functions. Open source online learning platforms will allow universities to develop their own delivery methods, partner with other universities and institutions as they choose, collect data, and control branding of their educational material. Further developing online opportunities through open source technology is a key objective of the partnership between edX and Stanford.

    + +

    Stanford will continue to provide a range of platforms for its instructors to choose from in hosting their online coursework, including continued partnerships with Coursera and other providers. The university will focus its ongoing platform development efforts on the new platform, combining key features from the Class2Go open source platform with the open source edX code base.

    + +

    The edX learning platform source code, as well as platform developments from Stanford, edX and other contributors, will be available on June 1, 2013 and can be accessed from the edX Platform Repository located at https://github.com/edX.

    + + +

    About edX

    + +

    EdX is a not-for-profit enterprise of its founding partners Harvard University and the Massachusetts Institute of Technology focused on transforming online and on-campus learning through groundbreaking methodologies, game-like experiences and cutting-edge research. EdX provides inspirational and transformative knowledge to students of all ages, social status, and income who form worldwide communities of learners. EdX uses its open source technology to transcend physical and social borders. We’re focused on people, not profit. EdX is based in Cambridge, Massachusetts in the USA.

    + +

    About Stanford University

    + +

    +Stanford University is engaged in a variety of efforts to develop online learning – experimenting with coursework for both on-campus and off-campus students, researching key questions around what a digital environment means for teaching and learning, and pursuing platform development. More information on Stanford’s online learning activities is available at http://online.stanford.edu + + +

    +

    Media Contact:

    +

    Dan O'Connell

    +

    oconnell@edx.org

    +

    (617) 480-6585

    +
    + +
    +

    Brad Hayward

    +

    bhayward@stanford.edu

    +

    650-724-0199

    +
    + +
    +

    Lisa Lapin

    +

    lapin@stanford.edu

    +

    650-725-8396

    +
    + + + +
    +
    +
    diff --git a/lms/urls.py b/lms/urls.py index de5c8184fa..4a0608720a 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -153,6 +153,9 @@ urlpatterns = ('', url(r'^press/xblock_announcement$', 'static_template_view.views.render', {'template': 'press_releases/xblock_announcement.html'}, name="press/xblock-announcement"), + url(r'^press/stanford-to-work-with-edx$', 'static_template_view.views.render', + {'template': 'press_releases/stanford_announcement.html'}, + name="press/stanford-to-work-with-edx"), # Should this always update to point to the latest press release? (r'^pressrelease$', 'django.views.generic.simple.redirect_to', From 2230fe3c23fdcc225db23b04e752d0d7f2c3a8d8 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Wed, 3 Apr 2013 15:08:33 -0400 Subject: [PATCH 15/66] Set the queue_len more consistently. --- common/lib/capa/capa/inputtypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 901ab25e60..18bc92f0a3 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -659,7 +659,7 @@ class MatlabInput(CodeInput): self.queue_msg = self.input_state['queue_msg'] if 'queuestate' in self.input_state and self.input_state['queuestate'] == 'queued': self.status = 'queued' - self.queue_len = '1' + self.queue_len = 1 self.msg = self.plot_submitted_msg @@ -702,7 +702,7 @@ class MatlabInput(CodeInput): def _extra_context(self): ''' Set up additional context variables''' extra_context = { - 'queue_len': self.queue_len, + 'queue_len': str(self.queue_len), 'queue_msg': self.queue_msg } return extra_context From eb6f2d8c0980d64fc96841756926a4d65e1ae95b Mon Sep 17 00:00:00 2001 From: Brian Talbot Date: Wed, 3 Apr 2013 15:22:27 -0400 Subject: [PATCH 16/66] studio - revising outline layout per date changes and gradable status UI issue --- cms/static/sass/views/_outline.scss | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cms/static/sass/views/_outline.scss b/cms/static/sass/views/_outline.scss index e5a294467e..6a141fa789 100644 --- a/cms/static/sass/views/_outline.scss +++ b/cms/static/sass/views/_outline.scss @@ -26,7 +26,7 @@ body.course.outline { position: relative; top: -4px; right: 50px; - width: 145px; + width: 100px; .status-label { position: absolute; @@ -62,7 +62,7 @@ body.course.outline { opacity: 0.0; position: absolute; top: -1px; - left: 5px; + right: 0; margin: 0; padding: 8px 12px; background: $white; @@ -160,7 +160,7 @@ body.course.outline { .section-published-date { position: absolute; top: 19px; - right: 90px; + right: 80px; padding: 4px 10px; border-radius: 3px; background: $lightGrey; @@ -271,8 +271,6 @@ body.course.outline { .section-published-date { float: right; - width: 278px; - margin-right: 220px; @include border-radius(3px); background: $lightGrey; From f77aaec392711adbffd5b96c11b04acc2ad1da7c Mon Sep 17 00:00:00 2001 From: cahrens Date: Wed, 3 Apr 2013 15:32:38 -0400 Subject: [PATCH 17/66] Need to mock datetime.datetime.utcnow. --- .../xmodule/tests/test_course_module.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/tests/test_course_module.py b/common/lib/xmodule/xmodule/tests/test_course_module.py index eda9cf386c..17930f1b89 100644 --- a/common/lib/xmodule/xmodule/tests/test_course_module.py +++ b/common/lib/xmodule/xmodule/tests/test_course_module.py @@ -1,11 +1,14 @@ import unittest from time import strptime +import datetime from fs.memoryfs import MemoryFS from mock import Mock, patch from xmodule.modulestore.xml import ImportSystem, XMLModuleStore +import xmodule.course_module +from xmodule.util.date_utils import time_to_datetime ORG = 'test_org' @@ -39,6 +42,17 @@ class DummySystem(ImportSystem): class IsNewCourseTestCase(unittest.TestCase): """Make sure the property is_new works on courses""" + + def setUp(self): + # Needed for test_is_newish + datetime_patcher = patch.object( + xmodule.course_module, 'datetime', + Mock(wraps=datetime.datetime) + ) + mocked_datetime = datetime_patcher.start() + mocked_datetime.utcnow.return_value = time_to_datetime(NOW) + self.addCleanup(datetime_patcher.stop) + @staticmethod def get_dummy_course(start, announcement=None, is_new=None, advertised_start=None): """Get a dummy course""" @@ -126,10 +140,7 @@ class IsNewCourseTestCase(unittest.TestCase): print "Checking start=%s advertised=%s" % (s[0], s[1]) self.assertEqual(d.start_date_text, s[2]) - @patch('xmodule.course_module.time.gmtime') - def test_is_newish(self, gmtime_mock): - gmtime_mock.return_value = NOW - + def test_is_newish(self): descriptor = self.get_dummy_course(start='2012-12-02T12:00', is_new=True) assert(descriptor.is_newish is True) From 7b226c34f8ba533cf745462dbe4f9c56e951a177 Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 15:34:54 -0400 Subject: [PATCH 18/66] Adding new logo for stanford --- .../press/releases/stanford-logo_325x260.gif | Bin 0 -> 5460 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lms/static/images/press/releases/stanford-logo_325x260.gif diff --git a/lms/static/images/press/releases/stanford-logo_325x260.gif b/lms/static/images/press/releases/stanford-logo_325x260.gif new file mode 100644 index 0000000000000000000000000000000000000000..d7532bd81def2dace3df8b8e5597d02acd685a41 GIT binary patch literal 5460 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 literal 0 HcmV?d00001 From b0021e73468cbf480812573f20d03ab872ef6a7d Mon Sep 17 00:00:00 2001 From: Brian Talbot Date: Wed, 3 Apr 2013 15:35:22 -0400 Subject: [PATCH 19/66] studio - resolved z-index issue with release date modal and JQUI timepicker + conslidated all vendor styling overrides/extensions --- cms/static/sass/base-style.scss | 2 +- .../{_jquery-ui-calendar.scss => _vendor.scss} | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) rename cms/static/sass/elements/{_jquery-ui-calendar.scss => _vendor.scss} (87%) diff --git a/cms/static/sass/base-style.scss b/cms/static/sass/base-style.scss index 5c67789f72..b9becc4829 100644 --- a/cms/static/sass/base-style.scss +++ b/cms/static/sass/base-style.scss @@ -27,7 +27,7 @@ @import 'elements/forms'; @import 'elements/modal'; @import 'elements/alerts'; -@import 'elements/jquery-ui-calendar'; +@import 'elements/vendor'; @import 'elements/tender-widget'; // specific views diff --git a/cms/static/sass/elements/_jquery-ui-calendar.scss b/cms/static/sass/elements/_vendor.scss similarity index 87% rename from cms/static/sass/elements/_jquery-ui-calendar.scss rename to cms/static/sass/elements/_vendor.scss index d7d7f093e5..b106f322ab 100644 --- a/cms/static/sass/elements/_jquery-ui-calendar.scss +++ b/cms/static/sass/elements/_vendor.scss @@ -1,6 +1,7 @@ -// studio - elements - JQUI calendar +// studio - elements - vendor overrides // ==================== +// JQUI calendar .ui-datepicker { border-color: $darkGrey; border-radius: 2px; @@ -54,4 +55,11 @@ border-color: $orange; color: #fff; } +} + +// ==================== + +// JQUI timepicker +.ui-timepicker-list { + z-index: 100000 !important; } \ No newline at end of file From 0c81329fa515a64a12db9deea54fb56886937acb Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 15:35:50 -0400 Subject: [PATCH 20/66] updating image link --- lms/templates/feed.rss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index b68a9ceb27..8347155cc0 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -13,7 +13,7 @@ 2012-12-19T14:00:00-07:00 Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform - <img src="${static.url('images/press/releases/edx-logo_240x180.png')}" /> + <img src="${static.url('images/press/releases/stanford-university_240x135.png')}" /> <p></p>
    From 71cfc4441bfee3e395b73ae9547bc9cb2b0ef761 Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 15:37:12 -0400 Subject: [PATCH 21/66] university->logo --- lms/templates/feed.rss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index 8347155cc0..b329092f72 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -13,7 +13,7 @@ 2012-12-19T14:00:00-07:00 Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform - <img src="${static.url('images/press/releases/stanford-university_240x135.png')}" /> + <img src="${static.url('images/press/releases/stanford-logo_240x135.png')}" /> <p></p> From 1c581835f230a59411fe934e4dc4699adef20dbd Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 15:39:11 -0400 Subject: [PATCH 22/66] changing stanford logo --- lms/templates/feed.rss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index b329092f72..8347155cc0 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -13,7 +13,7 @@ 2012-12-19T14:00:00-07:00 Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform - <img src="${static.url('images/press/releases/stanford-logo_240x135.png')}" /> + <img src="${static.url('images/press/releases/stanford-university_240x135.png')}" /> <p></p> From 6d78425a829027711205d06d7039a2f6950a0a3a Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 15:39:22 -0400 Subject: [PATCH 23/66] dding stanford-univ logo --- .../releases/stanford-university_240x135.png | Bin 0 -> 8729 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lms/static/images/press/releases/stanford-university_240x135.png diff --git a/lms/static/images/press/releases/stanford-university_240x135.png b/lms/static/images/press/releases/stanford-university_240x135.png new file mode 100644 index 0000000000000000000000000000000000000000..ba9d2a6e9538304cb9fe47a34910a8bdf9288423 GIT binary patch literal 8729 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 F`Ct3nxAg!3 literal 0 HcmV?d00001 From e8ee6616c44d4cf3e084cb339a10d46f6c415563 Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 15:39:46 -0400 Subject: [PATCH 24/66] removing old logo --- .../press/releases/stanford-logo_325x260.gif | Bin 5460 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lms/static/images/press/releases/stanford-logo_325x260.gif diff --git a/lms/static/images/press/releases/stanford-logo_325x260.gif b/lms/static/images/press/releases/stanford-logo_325x260.gif deleted file mode 100644 index d7532bd81def2dace3df8b8e5597d02acd685a41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5460 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 From b2e8780f9b58d3e14a724f09a9d299227ae4af22 Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 16:01:15 -0400 Subject: [PATCH 25/66] adding a smaller stanford image --- .../releases/stanford-university_102_57.png | Bin 0 -> 2982 bytes lms/templates/feed.rss | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 lms/static/images/press/releases/stanford-university_102_57.png diff --git a/lms/static/images/press/releases/stanford-university_102_57.png b/lms/static/images/press/releases/stanford-university_102_57.png new file mode 100644 index 0000000000000000000000000000000000000000..67910ff5d8da357887b2d60c3935c2ad32d25238 GIT binary patch literal 2982 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 I)4@di0|{WYp#T5? literal 0 HcmV?d00001 diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index 8347155cc0..1ac88ffe34 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -13,7 +13,7 @@ 2012-12-19T14:00:00-07:00 Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform - <img src="${static.url('images/press/releases/stanford-university_240x135.png')}" /> + <img src="${static.url('images/press/releases/stanford-university_102x57.png')}" /> <p></p> From d2313d851a98bbbb474a05c701f7ddb9309f31a7 Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Wed, 3 Apr 2013 16:02:41 -0400 Subject: [PATCH 26/66] renaming image --- ...ty_102_57.png => stanford-university_102x57.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename lms/static/images/press/releases/{stanford-university_102_57.png => stanford-university_102x57.png} (100%) diff --git a/lms/static/images/press/releases/stanford-university_102_57.png b/lms/static/images/press/releases/stanford-university_102x57.png similarity index 100% rename from lms/static/images/press/releases/stanford-university_102_57.png rename to lms/static/images/press/releases/stanford-university_102x57.png From 4265f5b48f4ff8604b3163def81c10adbe0f9c3b Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Wed, 3 Apr 2013 22:07:23 -0400 Subject: [PATCH 27/66] studio: added segment.io tracking --- cms/envs/aws.py | 2 ++ cms/envs/common.py | 3 ++- cms/envs/dev.py | 3 +++ cms/templates/base.html | 2 ++ cms/templates/widgets/segment-io.html | 16 ++++++++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 cms/templates/widgets/segment-io.html diff --git a/cms/envs/aws.py b/cms/envs/aws.py index be7816d21f..ef69c51d12 100644 --- a/cms/envs/aws.py +++ b/cms/envs/aws.py @@ -46,6 +46,8 @@ SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN') for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items(): MITX_FEATURES[feature] = value +SEGMENT_IO_KEY = ENV_TOKENS.get('SEGMENT_IO_KEY') + LOGGING = get_logger_config(LOG_DIR, logging_env=ENV_TOKENS['LOGGING_ENV'], syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514), diff --git a/cms/envs/common.py b/cms/envs/common.py index 5ad9068636..adf5add063 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -34,7 +34,8 @@ MITX_FEATURES = { 'ENABLE_DISCUSSION_SERVICE': False, 'AUTH_USE_MIT_CERTIFICATES': False, 'STUB_VIDEO_FOR_TESTING': False, # do not display video when running automated acceptance tests - 'STUDIO_NPS_SURVEY': True, + 'STUDIO_NPS_SURVEY': True, + 'SEGMENT_IO': True, } ENABLE_JASMINE = False diff --git a/cms/envs/dev.py b/cms/envs/dev.py index ae78b93f06..5489d2d733 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -150,3 +150,6 @@ DEBUG_TOOLBAR_MONGO_STACKTRACES = True # disable NPS survey in dev mode MITX_FEATURES['STUDIO_NPS_SURVEY'] = False + +# segment-io key for dev +SEGMENT_IO_KEY = 'mty8edrrsg' \ No newline at end of file diff --git a/cms/templates/base.html b/cms/templates/base.html index 15f4c556bb..e4f5befd63 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -23,6 +23,8 @@ + <%include file="widgets/segment-io.html" /> + <%block name="header_extras"> diff --git a/cms/templates/widgets/segment-io.html b/cms/templates/widgets/segment-io.html new file mode 100644 index 0000000000..1ccee8cff1 --- /dev/null +++ b/cms/templates/widgets/segment-io.html @@ -0,0 +1,16 @@ +% if settings.MITX_FEATURES.get('SEGMENT_IO'): + + + +% endif \ No newline at end of file From 2e482127151edc697e1d8b9013608d6a238dba5c Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Wed, 3 Apr 2013 22:21:18 -0400 Subject: [PATCH 28/66] newline --- cms/envs/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/envs/dev.py b/cms/envs/dev.py index 5489d2d733..dbf9c5574c 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -152,4 +152,4 @@ DEBUG_TOOLBAR_MONGO_STACKTRACES = True MITX_FEATURES['STUDIO_NPS_SURVEY'] = False # segment-io key for dev -SEGMENT_IO_KEY = 'mty8edrrsg' \ No newline at end of file +SEGMENT_IO_KEY = 'mty8edrrsg' From 1ce2affdd2f8ce267a842f5425fba3da5401570e Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Wed, 3 Apr 2013 23:45:05 -0400 Subject: [PATCH 29/66] outline page event tracking --- cms/static/js/base.js | 48 ++++++++++++++++++++++++++- cms/templates/widgets/segment-io.html | 7 +++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 6ea918cc36..7b930a176b 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -331,6 +331,12 @@ function createNewUnit(e) { var parent = $(this).data('parent'); var template = $(this).data('template'); + analytics.track('Created a Unit', { + 'course': course_location_analytics, + 'parent_location': parent + }); + + $.post('/clone_item', {'parent_location': parent, 'template': template, @@ -363,6 +369,12 @@ function _deleteItem($el) { var id = $el.data('id'); + analytics.track('Deleted an Item', { + 'course': course_location_analytics, + 'id': id + }); + + $.post('/delete_item', {'id': id, 'delete_children': true, 'delete_all_versions': true}, function (data) { @@ -426,6 +438,11 @@ function displayFinishedUpload(xhr) { var html = Mustache.to_html(template, resp); $('table > tbody').prepend(html); + analytics.track('Uploaded a File', { + 'course': course_location_analytics, + 'asset_url': resp.url + }); + } function markAsLoaded() { @@ -555,6 +572,11 @@ function saveNewSection(e) { var template = $saveButton.data('template'); var display_name = $(this).find('.new-section-name').val(); + analytics.track('Created a Section', { + 'course': course_location_analytics, + 'display_name': display_name + }); + $.post('/clone_item', { 'parent_location': parent, 'template': template, @@ -600,6 +622,12 @@ function saveNewCourse(e) { return; } + analytics.track('Created a Course', { + 'org': org, + 'number': number, + 'display_name': display_name + }); + $.post('/create_new_course', { 'template': template, 'org': org, @@ -646,9 +674,14 @@ function saveNewSubsection(e) { var parent = $(this).find('.new-subsection-name-save').data('parent'); var template = $(this).find('.new-subsection-name-save').data('template'); - var display_name = $(this).find('.new-subsection-name-input').val(); + analytics.track('Created a Subsection', { + 'course': course_location_analytics, + 'display_name': display_name + }); + + $.post('/clone_item', { 'parent_location': parent, 'template': template, @@ -702,6 +735,13 @@ function saveEditSectionName(e) { return; } + analytics.track('Edited Section Name', { + 'course': course_location_analytics, + 'display_name': display_name, + 'id': id + }); + + var $_this = $(this); // call into server to commit the new order $.ajax({ @@ -741,6 +781,12 @@ function saveSetSectionScheduleDate(e) { var id = $modal.attr('data-id'); + analytics.track('Edited Section Release Date', { + 'course': course_location_analytics, + 'id': id, + 'start': start + }); + // call into server to commit the new order $.ajax({ url: "/save_item", diff --git a/cms/templates/widgets/segment-io.html b/cms/templates/widgets/segment-io.html index 1ccee8cff1..7d00c731b0 100644 --- a/cms/templates/widgets/segment-io.html +++ b/cms/templates/widgets/segment-io.html @@ -1,6 +1,11 @@ % if settings.MITX_FEATURES.get('SEGMENT_IO'): -% endif \ No newline at end of file +% endif From c6f8b32dd44bcec58b01b23db3b9cc90154d8d12 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 00:34:37 -0400 Subject: [PATCH 30/66] added event tracking to static pages --- cms/static/coffee/src/views/module_edit.coffee | 7 ++++++- cms/static/coffee/src/views/tabs.coffee | 12 ++++++++++++ cms/static/js/views/course_info_edit.js | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee index 9f7e3a5e60..3cb3b1703f 100644 --- a/cms/static/coffee/src/views/module_edit.coffee +++ b/cms/static/coffee/src/views/module_edit.coffee @@ -15,7 +15,7 @@ class CMS.Views.ModuleEdit extends Backbone.View $component_editor: => @$el.find('.component-editor') loadDisplay: -> - XModule.loadModule(@$el.find('.xmodule_display')) + XModule.loadModule(@$el.find('.xmodule_display')) loadEdit: -> if not @module @@ -55,6 +55,11 @@ class CMS.Views.ModuleEdit extends Backbone.View clickSaveButton: (event) => event.preventDefault() data = @module.save() + + analytics.track "Saved Module", + course: course_location_analytics + id: _this.model.id + data.metadata = _.extend(data.metadata || {}, @metadata()) @hideModal() @model.save(data).done( => diff --git a/cms/static/coffee/src/views/tabs.coffee b/cms/static/coffee/src/views/tabs.coffee index 9fbe4e5789..1034fc988e 100644 --- a/cms/static/coffee/src/views/tabs.coffee +++ b/cms/static/coffee/src/views/tabs.coffee @@ -28,6 +28,10 @@ class CMS.Views.TabsEdit extends Backbone.View @$('.component').each((idx, element) => tabs.push($(element).data('id')) ) + + analytics.track "Reordered Static Pages", + course: course_location_analytics + $.ajax({ type:'POST', url: '/reorder_static_tabs', @@ -56,10 +60,18 @@ class CMS.Views.TabsEdit extends Backbone.View 'i4x://edx/templates/static_tab/Empty' ) + analytics.track "Added Static Page", + course: course_location_analytics + deleteTab: (event) => if not confirm 'Are you sure you want to delete this component? This action cannot be undone.' return $component = $(event.currentTarget).parents('.component') + + analytics.track "Deleted Static Page", + course: course_location_analytics + id: $component.data('id') + $.post('/delete_item', { id: $component.data('id') }, => diff --git a/cms/static/js/views/course_info_edit.js b/cms/static/js/views/course_info_edit.js index ce959fd443..a6d42e1927 100644 --- a/cms/static/js/views/course_info_edit.js +++ b/cms/static/js/views/course_info_edit.js @@ -107,6 +107,11 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({ // push change to display, hide the editor, submit the change targetModel.save({}, {error : CMS.ServerError}); this.closeEditor(this); + + analytics.track('Saved Course Update', { + 'course': course_location_analytics, + 'date': this.dateEntry(event).val() + }); }, onCancel: function(event) { @@ -147,6 +152,11 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({ return; } + analytics.track('Deleted Course Update', { + 'course': course_location_analytics, + 'date': this.dateEntry(event).val() + }); + var targetModel = this.eventModel(event); this.modelDom(event).remove(); var cacheThis = this; @@ -284,6 +294,11 @@ CMS.Views.ClassInfoHandoutsView = Backbone.View.extend({ this.model.save({}, {error: CMS.ServerError}); this.$form.hide(); this.closeEditor(this); + + analytics.track('Saved Course Handouts', { + 'course': course_location_analytics + }); + }, onCancel: function(event) { From bab42b1cce9aff0ab45a63f4c268b1d8d50d9fdf Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 00:40:06 -0400 Subject: [PATCH 31/66] instrumented advanced settings --- cms/static/js/views/settings/advanced_view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cms/static/js/views/settings/advanced_view.js b/cms/static/js/views/settings/advanced_view.js index e3ff098efb..52c5ed78d0 100644 --- a/cms/static/js/views/settings/advanced_view.js +++ b/cms/static/js/views/settings/advanced_view.js @@ -137,6 +137,10 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({ success : function() { self.render(); self.showMessage(self.successful_changes); + analytics.track('Saved Advanced Settings', { + 'course': course_location_analytics + }); + }, error : CMS.ServerError }); From 405b18618cbd5a88dc59945cbca2418b54988872 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 00:49:09 -0400 Subject: [PATCH 32/66] instrumented checklists --- cms/static/js/views/checklists_view.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cms/static/js/views/checklists_view.js b/cms/static/js/views/checklists_view.js index e553c7a2ca..85c0f5242b 100644 --- a/cms/static/js/views/checklists_view.js +++ b/cms/static/js/views/checklists_view.js @@ -77,11 +77,18 @@ CMS.Views.Checklists = Backbone.View.extend({ var task_index = $checkbox.data('task'); var model = this.collection.at(checklist_index); model.attributes.items[task_index].is_checked = $task.hasClass(completed); + model.save({}, { success : function() { var updatedTemplate = self.renderTemplate(model, checklist_index); self.$el.find('#course-checklist'+checklist_index).first().replaceWith(updatedTemplate); + + analytics.track('Toggled a Checklist Task', { + 'course': course_location_analytics, + 'task': model.attributes.items[task_index].short_description, + 'state': model.attributes.items[task_index].is_checked + }); }, error : CMS.ServerError }); From 587402cddc6aeab0298e0680e80379c5d5766039 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 01:47:37 -0400 Subject: [PATCH 33/66] added tracking to unit page and components --- cms/static/coffee/src/views/unit.coffee | 38 +++++++++++++++++++++++++ cms/templates/unit.html | 1 + 2 files changed, 39 insertions(+) diff --git a/cms/static/coffee/src/views/unit.coffee b/cms/static/coffee/src/views/unit.coffee index 42127b2800..e23477ccfa 100644 --- a/cms/static/coffee/src/views/unit.coffee +++ b/cms/static/coffee/src/views/unit.coffee @@ -35,6 +35,10 @@ class CMS.Views.UnitEdit extends Backbone.View @$('.components').sortable( handle: '.drag-handle' update: (event, ui) => + analytics.track "Reordered Components", + course: course_location_analytics + id: unit_location_analytics + payload = children : @components() options = success : => @model.unset('children') @model.save(payload, options) @@ -89,6 +93,11 @@ class CMS.Views.UnitEdit extends Backbone.View $(event.currentTarget).data('location') ) + analytics.track "Added a Component", + course: course_location_analytics + unit_id: unit_location_analytics + type: $(event.currentTarget).data('location') + @closeNewComponent(event) components: => @$('.component').map((idx, el) -> $(el).data('id')).get() @@ -111,6 +120,11 @@ class CMS.Views.UnitEdit extends Backbone.View $.post('/delete_item', { id: $component.data('id') }, => + analytics.track "Deleted a Component", + course: course_location_analytics + unit_id: unit_location_analytics + id: $component.data('id') + $component.remove() # b/c we don't vigilantly keep children up to date # get rid of it before it hurts someone @@ -129,6 +143,10 @@ class CMS.Views.UnitEdit extends Backbone.View id: @$el.data('id') delete_children: true }, => + analytics.track "Deleted Draft", + course: course_location_analytics + unit_id: unit_location_analytics + window.location.reload() ) @@ -138,6 +156,10 @@ class CMS.Views.UnitEdit extends Backbone.View $.post('/create_draft', { id: @$el.data('id') }, => + analytics.track "Created Draft", + course: course_location_analytics + unit_id: unit_location_analytics + @model.set('state', 'draft') ) @@ -148,20 +170,31 @@ class CMS.Views.UnitEdit extends Backbone.View $.post('/publish_draft', { id: @$el.data('id') }, => + analytics.track "Published Draft", + course: course_location_analytics + unit_id: unit_location_analytics + @model.set('state', 'public') ) setVisibility: (event) -> if @$('.visibility-select').val() == 'private' target_url = '/unpublish_unit' + visibility = "private" else target_url = '/publish_draft' + visibility = "public" @wait(true) $.post(target_url, { id: @$el.data('id') }, => + analytics.track "Set Unit Visibility", + course: course_location_analytics + unit_id: unit_location_analytics + visibility: visibility + @model.set('state', @$('.visibility-select').val()) ) @@ -193,6 +226,11 @@ class CMS.Views.UnitEdit.NameEdit extends Backbone.View @model.save(metadata: metadata) # Update name shown in the right-hand side location summary. $('.unit-location .editing .unit-name').html(metadata.display_name) + analytics.track "Edited Unit Name", + course: course_location_analytics + unit_id: unit_location_analytics + display_name: metadata.display_name + class CMS.Views.UnitEdit.LocationState extends Backbone.View initialize: => diff --git a/cms/templates/unit.html b/cms/templates/unit.html index e1a020dfca..1b9e49620b 100644 --- a/cms/templates/unit.html +++ b/cms/templates/unit.html @@ -28,6 +28,7 @@ }); }); + var unit_location_analytics = '${unit_location}'; From 8439013f64b2b0738c55fe7bde2f59f7d3478a3c Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Wed, 3 Apr 2013 22:07:23 -0400 Subject: [PATCH 34/66] studio: added segment.io tracking --- cms/envs/aws.py | 2 ++ cms/envs/common.py | 3 ++- cms/envs/dev.py | 3 +++ cms/templates/base.html | 2 ++ cms/templates/widgets/segment-io.html | 16 ++++++++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 cms/templates/widgets/segment-io.html diff --git a/cms/envs/aws.py b/cms/envs/aws.py index be7816d21f..ef69c51d12 100644 --- a/cms/envs/aws.py +++ b/cms/envs/aws.py @@ -46,6 +46,8 @@ SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN') for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items(): MITX_FEATURES[feature] = value +SEGMENT_IO_KEY = ENV_TOKENS.get('SEGMENT_IO_KEY') + LOGGING = get_logger_config(LOG_DIR, logging_env=ENV_TOKENS['LOGGING_ENV'], syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514), diff --git a/cms/envs/common.py b/cms/envs/common.py index 5ad9068636..adf5add063 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -34,7 +34,8 @@ MITX_FEATURES = { 'ENABLE_DISCUSSION_SERVICE': False, 'AUTH_USE_MIT_CERTIFICATES': False, 'STUB_VIDEO_FOR_TESTING': False, # do not display video when running automated acceptance tests - 'STUDIO_NPS_SURVEY': True, + 'STUDIO_NPS_SURVEY': True, + 'SEGMENT_IO': True, } ENABLE_JASMINE = False diff --git a/cms/envs/dev.py b/cms/envs/dev.py index ae78b93f06..5489d2d733 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -150,3 +150,6 @@ DEBUG_TOOLBAR_MONGO_STACKTRACES = True # disable NPS survey in dev mode MITX_FEATURES['STUDIO_NPS_SURVEY'] = False + +# segment-io key for dev +SEGMENT_IO_KEY = 'mty8edrrsg' \ No newline at end of file diff --git a/cms/templates/base.html b/cms/templates/base.html index 15f4c556bb..e4f5befd63 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -23,6 +23,8 @@ + <%include file="widgets/segment-io.html" /> + <%block name="header_extras"> diff --git a/cms/templates/widgets/segment-io.html b/cms/templates/widgets/segment-io.html new file mode 100644 index 0000000000..1ccee8cff1 --- /dev/null +++ b/cms/templates/widgets/segment-io.html @@ -0,0 +1,16 @@ +% if settings.MITX_FEATURES.get('SEGMENT_IO'): + + + +% endif \ No newline at end of file From d9bbed305ef610672f366df522d9caf26d0e1c0e Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Wed, 3 Apr 2013 22:21:18 -0400 Subject: [PATCH 35/66] newline --- cms/envs/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/envs/dev.py b/cms/envs/dev.py index 5489d2d733..dbf9c5574c 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -152,4 +152,4 @@ DEBUG_TOOLBAR_MONGO_STACKTRACES = True MITX_FEATURES['STUDIO_NPS_SURVEY'] = False # segment-io key for dev -SEGMENT_IO_KEY = 'mty8edrrsg' \ No newline at end of file +SEGMENT_IO_KEY = 'mty8edrrsg' From 64b7603d37dc3b765acf30101819f44e68696f87 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Wed, 3 Apr 2013 23:45:05 -0400 Subject: [PATCH 36/66] outline page event tracking --- cms/static/js/base.js | 48 ++++++++++++++++++++++++++- cms/templates/widgets/segment-io.html | 7 +++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 6ea918cc36..7b930a176b 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -331,6 +331,12 @@ function createNewUnit(e) { var parent = $(this).data('parent'); var template = $(this).data('template'); + analytics.track('Created a Unit', { + 'course': course_location_analytics, + 'parent_location': parent + }); + + $.post('/clone_item', {'parent_location': parent, 'template': template, @@ -363,6 +369,12 @@ function _deleteItem($el) { var id = $el.data('id'); + analytics.track('Deleted an Item', { + 'course': course_location_analytics, + 'id': id + }); + + $.post('/delete_item', {'id': id, 'delete_children': true, 'delete_all_versions': true}, function (data) { @@ -426,6 +438,11 @@ function displayFinishedUpload(xhr) { var html = Mustache.to_html(template, resp); $('table > tbody').prepend(html); + analytics.track('Uploaded a File', { + 'course': course_location_analytics, + 'asset_url': resp.url + }); + } function markAsLoaded() { @@ -555,6 +572,11 @@ function saveNewSection(e) { var template = $saveButton.data('template'); var display_name = $(this).find('.new-section-name').val(); + analytics.track('Created a Section', { + 'course': course_location_analytics, + 'display_name': display_name + }); + $.post('/clone_item', { 'parent_location': parent, 'template': template, @@ -600,6 +622,12 @@ function saveNewCourse(e) { return; } + analytics.track('Created a Course', { + 'org': org, + 'number': number, + 'display_name': display_name + }); + $.post('/create_new_course', { 'template': template, 'org': org, @@ -646,9 +674,14 @@ function saveNewSubsection(e) { var parent = $(this).find('.new-subsection-name-save').data('parent'); var template = $(this).find('.new-subsection-name-save').data('template'); - var display_name = $(this).find('.new-subsection-name-input').val(); + analytics.track('Created a Subsection', { + 'course': course_location_analytics, + 'display_name': display_name + }); + + $.post('/clone_item', { 'parent_location': parent, 'template': template, @@ -702,6 +735,13 @@ function saveEditSectionName(e) { return; } + analytics.track('Edited Section Name', { + 'course': course_location_analytics, + 'display_name': display_name, + 'id': id + }); + + var $_this = $(this); // call into server to commit the new order $.ajax({ @@ -741,6 +781,12 @@ function saveSetSectionScheduleDate(e) { var id = $modal.attr('data-id'); + analytics.track('Edited Section Release Date', { + 'course': course_location_analytics, + 'id': id, + 'start': start + }); + // call into server to commit the new order $.ajax({ url: "/save_item", diff --git a/cms/templates/widgets/segment-io.html b/cms/templates/widgets/segment-io.html index 1ccee8cff1..7d00c731b0 100644 --- a/cms/templates/widgets/segment-io.html +++ b/cms/templates/widgets/segment-io.html @@ -1,6 +1,11 @@ % if settings.MITX_FEATURES.get('SEGMENT_IO'): -% endif \ No newline at end of file +% endif From 22bd8da1f2e4a84f45101da61222e687987bb1b2 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 00:34:37 -0400 Subject: [PATCH 37/66] added event tracking to static pages --- cms/static/coffee/src/views/module_edit.coffee | 7 ++++++- cms/static/coffee/src/views/tabs.coffee | 12 ++++++++++++ cms/static/js/views/course_info_edit.js | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee index 9f7e3a5e60..3cb3b1703f 100644 --- a/cms/static/coffee/src/views/module_edit.coffee +++ b/cms/static/coffee/src/views/module_edit.coffee @@ -15,7 +15,7 @@ class CMS.Views.ModuleEdit extends Backbone.View $component_editor: => @$el.find('.component-editor') loadDisplay: -> - XModule.loadModule(@$el.find('.xmodule_display')) + XModule.loadModule(@$el.find('.xmodule_display')) loadEdit: -> if not @module @@ -55,6 +55,11 @@ class CMS.Views.ModuleEdit extends Backbone.View clickSaveButton: (event) => event.preventDefault() data = @module.save() + + analytics.track "Saved Module", + course: course_location_analytics + id: _this.model.id + data.metadata = _.extend(data.metadata || {}, @metadata()) @hideModal() @model.save(data).done( => diff --git a/cms/static/coffee/src/views/tabs.coffee b/cms/static/coffee/src/views/tabs.coffee index 9fbe4e5789..1034fc988e 100644 --- a/cms/static/coffee/src/views/tabs.coffee +++ b/cms/static/coffee/src/views/tabs.coffee @@ -28,6 +28,10 @@ class CMS.Views.TabsEdit extends Backbone.View @$('.component').each((idx, element) => tabs.push($(element).data('id')) ) + + analytics.track "Reordered Static Pages", + course: course_location_analytics + $.ajax({ type:'POST', url: '/reorder_static_tabs', @@ -56,10 +60,18 @@ class CMS.Views.TabsEdit extends Backbone.View 'i4x://edx/templates/static_tab/Empty' ) + analytics.track "Added Static Page", + course: course_location_analytics + deleteTab: (event) => if not confirm 'Are you sure you want to delete this component? This action cannot be undone.' return $component = $(event.currentTarget).parents('.component') + + analytics.track "Deleted Static Page", + course: course_location_analytics + id: $component.data('id') + $.post('/delete_item', { id: $component.data('id') }, => diff --git a/cms/static/js/views/course_info_edit.js b/cms/static/js/views/course_info_edit.js index ce959fd443..a6d42e1927 100644 --- a/cms/static/js/views/course_info_edit.js +++ b/cms/static/js/views/course_info_edit.js @@ -107,6 +107,11 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({ // push change to display, hide the editor, submit the change targetModel.save({}, {error : CMS.ServerError}); this.closeEditor(this); + + analytics.track('Saved Course Update', { + 'course': course_location_analytics, + 'date': this.dateEntry(event).val() + }); }, onCancel: function(event) { @@ -147,6 +152,11 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({ return; } + analytics.track('Deleted Course Update', { + 'course': course_location_analytics, + 'date': this.dateEntry(event).val() + }); + var targetModel = this.eventModel(event); this.modelDom(event).remove(); var cacheThis = this; @@ -284,6 +294,11 @@ CMS.Views.ClassInfoHandoutsView = Backbone.View.extend({ this.model.save({}, {error: CMS.ServerError}); this.$form.hide(); this.closeEditor(this); + + analytics.track('Saved Course Handouts', { + 'course': course_location_analytics + }); + }, onCancel: function(event) { From 7b5ec1bc416ba61202b80b04131db10841d8e2d0 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 00:40:06 -0400 Subject: [PATCH 38/66] instrumented advanced settings --- cms/static/js/views/settings/advanced_view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cms/static/js/views/settings/advanced_view.js b/cms/static/js/views/settings/advanced_view.js index e3ff098efb..52c5ed78d0 100644 --- a/cms/static/js/views/settings/advanced_view.js +++ b/cms/static/js/views/settings/advanced_view.js @@ -137,6 +137,10 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({ success : function() { self.render(); self.showMessage(self.successful_changes); + analytics.track('Saved Advanced Settings', { + 'course': course_location_analytics + }); + }, error : CMS.ServerError }); From 4ce34fa298a5e476ebedbc47f7e32a3f9d5bac62 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 00:49:09 -0400 Subject: [PATCH 39/66] instrumented checklists --- cms/static/js/views/checklists_view.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cms/static/js/views/checklists_view.js b/cms/static/js/views/checklists_view.js index e553c7a2ca..85c0f5242b 100644 --- a/cms/static/js/views/checklists_view.js +++ b/cms/static/js/views/checklists_view.js @@ -77,11 +77,18 @@ CMS.Views.Checklists = Backbone.View.extend({ var task_index = $checkbox.data('task'); var model = this.collection.at(checklist_index); model.attributes.items[task_index].is_checked = $task.hasClass(completed); + model.save({}, { success : function() { var updatedTemplate = self.renderTemplate(model, checklist_index); self.$el.find('#course-checklist'+checklist_index).first().replaceWith(updatedTemplate); + + analytics.track('Toggled a Checklist Task', { + 'course': course_location_analytics, + 'task': model.attributes.items[task_index].short_description, + 'state': model.attributes.items[task_index].is_checked + }); }, error : CMS.ServerError }); From 8fb6ce2ecad28b53ff31f67fa7492367eb669162 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 01:47:37 -0400 Subject: [PATCH 40/66] added tracking to unit page and components --- cms/static/coffee/src/views/unit.coffee | 38 +++++++++++++++++++++++++ cms/templates/unit.html | 1 + 2 files changed, 39 insertions(+) diff --git a/cms/static/coffee/src/views/unit.coffee b/cms/static/coffee/src/views/unit.coffee index 42127b2800..e23477ccfa 100644 --- a/cms/static/coffee/src/views/unit.coffee +++ b/cms/static/coffee/src/views/unit.coffee @@ -35,6 +35,10 @@ class CMS.Views.UnitEdit extends Backbone.View @$('.components').sortable( handle: '.drag-handle' update: (event, ui) => + analytics.track "Reordered Components", + course: course_location_analytics + id: unit_location_analytics + payload = children : @components() options = success : => @model.unset('children') @model.save(payload, options) @@ -89,6 +93,11 @@ class CMS.Views.UnitEdit extends Backbone.View $(event.currentTarget).data('location') ) + analytics.track "Added a Component", + course: course_location_analytics + unit_id: unit_location_analytics + type: $(event.currentTarget).data('location') + @closeNewComponent(event) components: => @$('.component').map((idx, el) -> $(el).data('id')).get() @@ -111,6 +120,11 @@ class CMS.Views.UnitEdit extends Backbone.View $.post('/delete_item', { id: $component.data('id') }, => + analytics.track "Deleted a Component", + course: course_location_analytics + unit_id: unit_location_analytics + id: $component.data('id') + $component.remove() # b/c we don't vigilantly keep children up to date # get rid of it before it hurts someone @@ -129,6 +143,10 @@ class CMS.Views.UnitEdit extends Backbone.View id: @$el.data('id') delete_children: true }, => + analytics.track "Deleted Draft", + course: course_location_analytics + unit_id: unit_location_analytics + window.location.reload() ) @@ -138,6 +156,10 @@ class CMS.Views.UnitEdit extends Backbone.View $.post('/create_draft', { id: @$el.data('id') }, => + analytics.track "Created Draft", + course: course_location_analytics + unit_id: unit_location_analytics + @model.set('state', 'draft') ) @@ -148,20 +170,31 @@ class CMS.Views.UnitEdit extends Backbone.View $.post('/publish_draft', { id: @$el.data('id') }, => + analytics.track "Published Draft", + course: course_location_analytics + unit_id: unit_location_analytics + @model.set('state', 'public') ) setVisibility: (event) -> if @$('.visibility-select').val() == 'private' target_url = '/unpublish_unit' + visibility = "private" else target_url = '/publish_draft' + visibility = "public" @wait(true) $.post(target_url, { id: @$el.data('id') }, => + analytics.track "Set Unit Visibility", + course: course_location_analytics + unit_id: unit_location_analytics + visibility: visibility + @model.set('state', @$('.visibility-select').val()) ) @@ -193,6 +226,11 @@ class CMS.Views.UnitEdit.NameEdit extends Backbone.View @model.save(metadata: metadata) # Update name shown in the right-hand side location summary. $('.unit-location .editing .unit-name').html(metadata.display_name) + analytics.track "Edited Unit Name", + course: course_location_analytics + unit_id: unit_location_analytics + display_name: metadata.display_name + class CMS.Views.UnitEdit.LocationState extends Backbone.View initialize: => diff --git a/cms/templates/unit.html b/cms/templates/unit.html index e1a020dfca..1b9e49620b 100644 --- a/cms/templates/unit.html +++ b/cms/templates/unit.html @@ -28,6 +28,7 @@ }); }); + var unit_location_analytics = '${unit_location}'; From ac010795021e8e9103992b4b77c0ad51ba52aac9 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Thu, 4 Apr 2013 09:35:35 -0400 Subject: [PATCH 41/66] add a command line utility to walk through the course and find common errors --- .../management/commands/check_course.py | 74 +++++++++++++++++++ .../xmodule/modulestore/xml_importer.py | 42 ++++++++--- 2 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 cms/djangoapps/contentstore/management/commands/check_course.py diff --git a/cms/djangoapps/contentstore/management/commands/check_course.py b/cms/djangoapps/contentstore/management/commands/check_course.py new file mode 100644 index 0000000000..c691ac63a3 --- /dev/null +++ b/cms/djangoapps/contentstore/management/commands/check_course.py @@ -0,0 +1,74 @@ +from django.core.management.base import BaseCommand, CommandError +from xmodule.modulestore.django import modulestore +from xmodule.contentstore.django import contentstore +from xmodule.modulestore.xml_importer import check_module_metadata_editability +from xmodule.course_module import CourseDescriptor + +from request_cache.middleware import RequestCache + +from django.core.cache import get_cache, InvalidCacheBackendError + +class Command(BaseCommand): + help = '''Delete a MongoDB backed course''' + + def handle(self, *args, **options): + if len(args) != 1 : + raise CommandError("check_course requires one argument: ") + + loc_str = args[0] + + loc = CourseDescriptor.id_to_location(loc_str) + + ms = modulestore() + + # setup a request cache so we don't throttle the DB with all the metadata inheritance requests + ms.request_cache = RequestCache.get_request_cache() + + course = ms.get_item(loc, depth=3) + + err_cnt = 0 + def _xlint_metadata(module): + err_cnt = check_module_metadata_editability(module) + for child in module.get_children(): + err_cnt = err_cnt + _xlint_metadata(child) + return err_cnt + + _xlint_metadata(course) + + # we've had a bug where the xml_attributes field can we rewritten as a string rather than a dict + def _check_xml_attributes_field(module): + err_cnt = 0 + if hasattr(module, 'xml_attributes') and (isinstance(module, str) or isinstance(module, unicode)): + print 'module = {0} has xml_attributes as a string. It should be a dict'.format(module.location.url()) + err_cnt = err_cnt + 1 + for child in module.get_children(): + err_cnt = err_cnt + _check_xml_attributes_field(child) + return err_cnt + + _check_xml_attributes_field(course) + + # check for dangling discussion items, this can cause errors in the forums + def _get_discussion_items(module): + discussion_items = [] + if module.location.category == 'discussion': + discussion_items = discussion_items + [module.location.url()] + + for child in module.get_children(): + discussion_items = discussion_items + _get_discussion_items(child) + + return discussion_items + + discussion_items =_get_discussion_items(course) + + # now query all discussion items via get_items() and compare with the tree-traversal + queried_discussion_items = ms.get_items(['i4x', course.location.org, course.location.course, + 'discussion', None, None]) + + for item in queried_discussion_items: + if item.location.url() not in discussion_items: + print 'Found dangling discussion module = {0}'.format(item.location.url()) + + + + + diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py index 7c1f1fb4f7..0a7d07afe1 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py @@ -356,22 +356,43 @@ def remap_namespace(module, target_location_namespace): return module -def validate_no_non_editable_metadata(module_store, course_id, category, allowed=None): + +def allowed_metadata_by_category(category): + # should this be in the descriptors?!? + return { + 'vertical': [], + 'chapter': ['start'], + 'sequential': ['due', 'format', 'start', 'graded'] + }.get(category,['*']) + + +def check_module_metadata_editability(module): ''' - Assert that there is no metadata within a particular category that we can't support editing + Assert that there is no metadata within a particular module that we can't support editing However we always allow 'display_name' and 'xml_attribtues' ''' - _allowed = (allowed if allowed is not None else []) + ['xml_attributes', 'display_name'] + allowed = allowed_metadata_by_category(module.location.category) + if '*' in allowed: + # everything is allowed + return 0 + allowed = allowed + ['xml_attributes', 'display_name'] + err_cnt = 0 + my_metadata = dict(own_metadata(module)) + for key in my_metadata.keys(): + if key not in allowed: + err_cnt = err_cnt + 1 + print ': found metadata on {0}. Studio will not support editing this piece of metadata, so it is not allowed. Metadata: {1} = {2}'. format(module.location.url(), key, my_metadata[key]) + + return err_cnt + + +def validate_no_non_editable_metadata(module_store, course_id, category): err_cnt = 0 for module_loc in module_store.modules[course_id]: module = module_store.modules[course_id][module_loc] if module.location.category == category: - my_metadata = dict(own_metadata(module)) - for key in my_metadata.keys(): - if key not in _allowed: - err_cnt = err_cnt + 1 - print ': found metadata on {0}. Studio will not support editing this piece of metadata, so it is not allowed. Metadata: {1} = {2}'. format(module.location.url(), key, my_metadata[key]) + err_cnt = err_cnt + check_module_metadata_editability(module) return err_cnt @@ -463,10 +484,9 @@ def perform_xlint(data_dir, course_dirs, # don't allow metadata on verticals, since we can't edit them in studio err_cnt += validate_no_non_editable_metadata(module_store, course_id, "vertical") # don't allow metadata on chapters, since we can't edit them in studio - err_cnt += validate_no_non_editable_metadata(module_store, course_id, "chapter",['start']) + err_cnt += validate_no_non_editable_metadata(module_store, course_id, "chapter") # don't allow metadata on sequences that we can't edit - err_cnt += validate_no_non_editable_metadata(module_store, course_id, "sequential", - ['due','format','start','graded']) + err_cnt += validate_no_non_editable_metadata(module_store, course_id, "sequential") # check for a presence of a course marketing video location_elements = course_id.split('/') From 22017ac24c4b29958cc791dd47437a53314b221e Mon Sep 17 00:00:00 2001 From: Jay Zoldak Date: Thu, 4 Apr 2013 09:56:21 -0400 Subject: [PATCH 42/66] pep8 fixes for psychoanalyze and capa module --- common/lib/xmodule/xmodule/capa_module.py | 22 ++-- .../xmodule/xmodule/tests/test_capa_module.py | 108 ++++++------------ lms/djangoapps/psychometrics/psychoanalyze.py | 7 +- 3 files changed, 49 insertions(+), 88 deletions(-) diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index e1e023c185..2097e4d4ee 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -108,11 +108,10 @@ class CapaModule(CapaFields, XModule): ''' icon_class = 'problem' - js = {'coffee': [resource_string(__name__, 'js/src/capa/display.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/javascript_loader.coffee'), - ], + ], 'js': [resource_string(__name__, 'js/src/capa/imageinput.js'), resource_string(__name__, 'js/src/capa/schematic.js') ]} @@ -367,11 +366,11 @@ class CapaModule(CapaFields, XModule): self.set_state_from_lcp() # Prepend a scary warning to the student - warning = '
    '\ - '

    Warning: The problem has been reset to its initial state!

    '\ - 'The problem\'s state was corrupted by an invalid submission. ' \ - 'The submission consisted of:'\ - '
      ' + warning = '
      '\ + '

      Warning: The problem has been reset to its initial state!

      '\ + 'The problem\'s state was corrupted by an invalid submission. ' \ + 'The submission consisted of:'\ + '
        ' for student_answer in student_answers.values(): if student_answer != '': warning += '
      • ' + cgi.escape(student_answer) + '
      • ' @@ -388,7 +387,6 @@ class CapaModule(CapaFields, XModule): return html - def get_problem_html(self, encapsulate=True): '''Return html for the problem. Adds check, reset, save buttons as necessary based on the problem config and state.''' @@ -401,7 +399,6 @@ class CapaModule(CapaFields, XModule): except Exception, err: html = self.handle_problem_html_error(err) - # The convention is to pass the name of the check button # if we want to show a check button, and False otherwise # This works because non-empty strings evaluate to True @@ -454,7 +451,7 @@ class CapaModule(CapaFields, XModule): 'score_update': self.update_score, 'input_ajax': self.handle_input_ajax, 'ungraded_response': self.handle_ungraded_response - } + } if dispatch not in handlers: return 'Error' @@ -472,7 +469,7 @@ class CapaModule(CapaFields, XModule): d.update({ 'progress_changed': after != before, 'progress_status': Progress.to_js_status_str(after), - }) + }) return json.dumps(d, cls=ComplexEncoder) def is_past_due(self): @@ -535,7 +532,6 @@ class CapaModule(CapaFields, XModule): return False - def update_score(self, get): """ Delivers grading response (e.g. from asynchronous code checking) to @@ -590,7 +586,6 @@ class CapaModule(CapaFields, XModule): self.set_state_from_lcp() return response - def get_answer(self, get): ''' For the "show answer" button. @@ -700,7 +695,6 @@ class CapaModule(CapaFields, XModule): 'max_value': score['total'], }) - def check_problem(self, get): ''' Checks whether answers to a problem are correct, and returns a map of correct/incorrect answers: diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index 1fefbb64cd..d94345fe1c 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -35,6 +35,7 @@ class CapaFactory(object): """ num = 0 + @staticmethod def next_num(): CapaFactory.num += 1 @@ -49,7 +50,7 @@ class CapaFactory(object): def answer_key(): """ Return the key stored in the capa problem answer dict """ return ("-".join(['i4x', 'edX', 'capa_test', 'problem', - 'SampleProblem%d' % CapaFactory.num]) + + 'SampleProblem%d' % CapaFactory.num]) + "_2_1") @staticmethod @@ -120,7 +121,6 @@ class CapaFactory(object): return module - class CapaModuleTest(unittest.TestCase): def setUp(self): @@ -142,9 +142,6 @@ class CapaModuleTest(unittest.TestCase): self.assertNotEqual(module.url_name, other_module.url_name, "Factory should be creating unique names for each problem") - - - def test_correct(self): """ Check that the factory creates correct and incorrect problems properly. @@ -155,7 +152,6 @@ class CapaModuleTest(unittest.TestCase): other_module = CapaFactory.create(correct=True) self.assertEqual(other_module.get_score()['score'], 1) - def test_showanswer_default(self): """ Make sure the show answer logic does the right thing. @@ -165,14 +161,12 @@ class CapaModuleTest(unittest.TestCase): problem = CapaFactory.create() self.assertFalse(problem.answer_available()) - def test_showanswer_attempted(self): problem = CapaFactory.create(showanswer='attempted') self.assertFalse(problem.answer_available()) problem.attempts = 1 self.assertTrue(problem.answer_available()) - def test_showanswer_closed(self): # can see after attempts used up, even with due date in the future @@ -182,21 +176,19 @@ class CapaModuleTest(unittest.TestCase): due=self.tomorrow_str) self.assertTrue(used_all_attempts.answer_available()) - # can see after due date after_due_date = CapaFactory.create(showanswer='closed', - max_attempts="1", - attempts="0", - due=self.yesterday_str) + max_attempts="1", + attempts="0", + due=self.yesterday_str) self.assertTrue(after_due_date.answer_available()) - # can't see because attempts left attempts_left_open = CapaFactory.create(showanswer='closed', - max_attempts="1", - attempts="0", - due=self.tomorrow_str) + max_attempts="1", + attempts="0", + due=self.tomorrow_str) self.assertFalse(attempts_left_open.answer_available()) # Can't see because grace period hasn't expired @@ -207,8 +199,6 @@ class CapaModuleTest(unittest.TestCase): graceperiod=self.two_day_delta_str) self.assertFalse(still_in_grace.answer_available()) - - def test_showanswer_past_due(self): """ With showanswer="past_due" should only show answer after the problem is closed @@ -222,20 +212,18 @@ class CapaModuleTest(unittest.TestCase): due=self.tomorrow_str) self.assertFalse(used_all_attempts.answer_available()) - # can see after due date past_due_date = CapaFactory.create(showanswer='past_due', - max_attempts="1", - attempts="0", - due=self.yesterday_str) + max_attempts="1", + attempts="0", + due=self.yesterday_str) self.assertTrue(past_due_date.answer_available()) - # can't see because attempts left attempts_left_open = CapaFactory.create(showanswer='past_due', - max_attempts="1", - attempts="0", - due=self.tomorrow_str) + max_attempts="1", + attempts="0", + due=self.tomorrow_str) self.assertFalse(attempts_left_open.answer_available()) # Can't see because grace period hasn't expired, even though have no more @@ -260,31 +248,28 @@ class CapaModuleTest(unittest.TestCase): due=self.tomorrow_str) self.assertTrue(used_all_attempts.answer_available()) - # can see after due date past_due_date = CapaFactory.create(showanswer='finished', - max_attempts="1", - attempts="0", - due=self.yesterday_str) + max_attempts="1", + attempts="0", + due=self.yesterday_str) self.assertTrue(past_due_date.answer_available()) - # can't see because attempts left and wrong attempts_left_open = CapaFactory.create(showanswer='finished', - max_attempts="1", - attempts="0", - due=self.tomorrow_str) + max_attempts="1", + attempts="0", + due=self.tomorrow_str) self.assertFalse(attempts_left_open.answer_available()) # _can_ see because attempts left and right correct_ans = CapaFactory.create(showanswer='finished', - max_attempts="1", - attempts="0", - due=self.tomorrow_str, - correct=True) + max_attempts="1", + attempts="0", + due=self.tomorrow_str, + correct=True) self.assertTrue(correct_ans.answer_available()) - # Can see even though grace period hasn't expired, because have no more # attempts. still_in_grace = CapaFactory.create(showanswer='finished', @@ -294,7 +279,6 @@ class CapaModuleTest(unittest.TestCase): graceperiod=self.two_day_delta_str) self.assertTrue(still_in_grace.answer_available()) - def test_closed(self): # Attempts < Max attempts --> NOT closed @@ -322,7 +306,6 @@ class CapaModuleTest(unittest.TestCase): due=self.yesterday_str) self.assertTrue(module.closed()) - def test_parse_get_params(self): # We have to set up Django settings in order to use QueryDict @@ -348,7 +331,6 @@ class CapaModuleTest(unittest.TestCase): "Output dict should have key %s" % original_key) self.assertEqual(valid_get_dict[original_key], result[key]) - # Valid GET param dict with list keys valid_get_dict = self._querydict_from_dict({'input_2[]': ['test1', 'test2']}) result = CapaModule.make_dict_of_responses(valid_get_dict) @@ -366,12 +348,11 @@ class CapaModuleTest(unittest.TestCase): with self.assertRaises(ValueError): result = CapaModule.make_dict_of_responses(invalid_get_dict) - # Two equivalent names (one list, one non-list) # One of the values would overwrite the other, so detect this # and raise an exception invalid_get_dict = self._querydict_from_dict({'input_1[]': 'test 1', - 'input_1': 'test 2'}) + 'input_1': 'test 2'}) with self.assertRaises(ValueError): result = CapaModule.make_dict_of_responses(invalid_get_dict) @@ -395,7 +376,6 @@ class CapaModuleTest(unittest.TestCase): return copyDict - def test_check_problem_correct(self): module = CapaFactory.create(attempts=1) @@ -403,6 +383,7 @@ class CapaModuleTest(unittest.TestCase): # Simulate that all answers are marked correct, no matter # what the input is, by patching CorrectMap.is_correct() # Also simulate rendering the HTML + # TODO: pep8 thinks the following line has invalid syntax with patch('capa.correctmap.CorrectMap.is_correct') as mock_is_correct,\ patch('xmodule.capa_module.CapaModule.get_problem_html') as mock_html: mock_is_correct.return_value = True @@ -439,7 +420,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the number of attempts is incremented by 1 self.assertEqual(module.attempts, 1) - def test_check_problem_closed(self): module = CapaFactory.create(attempts=3) @@ -503,12 +483,11 @@ class CapaModuleTest(unittest.TestCase): # Expect that the number of attempts is NOT incremented self.assertEqual(module.attempts, 1) - def test_check_problem_error(self): # Try each exception that capa_module should handle - for exception_class in [StudentInputError, - LoncapaProblemError, + for exception_class in [StudentInputError, + LoncapaProblemError, ResponseError]: # Create the module @@ -532,9 +511,9 @@ class CapaModuleTest(unittest.TestCase): self.assertEqual(module.attempts, 1) def test_check_problem_error_with_staff_user(self): - + # Try each exception that capa module should handle - for exception_class in [StudentInputError, + for exception_class in [StudentInputError, LoncapaProblemError, ResponseError]: @@ -560,7 +539,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the number of attempts is NOT incremented self.assertEqual(module.attempts, 1) - def test_reset_problem(self): module = CapaFactory.create(done=True) module.new_lcp = Mock(wraps=module.new_lcp) @@ -583,7 +561,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the problem was reset module.new_lcp.assert_called_once_with({'seed': None}) - def test_reset_problem_closed(self): module = CapaFactory.create() @@ -598,7 +575,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the problem was NOT reset self.assertTrue('success' in result and not result['success']) - def test_reset_problem_not_done(self): # Simulate that the problem is NOT done module = CapaFactory.create(done=False) @@ -610,7 +586,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the problem was NOT reset self.assertTrue('success' in result and not result['success']) - def test_save_problem(self): module = CapaFactory.create(done=False) @@ -625,7 +600,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the result is success self.assertTrue('success' in result and result['success']) - def test_save_problem_closed(self): module = CapaFactory.create(done=False) @@ -640,7 +614,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the result is failure self.assertTrue('success' in result and not result['success']) - def test_save_problem_submitted_with_randomize(self): module = CapaFactory.create(rerandomize='always', done=True) @@ -651,7 +624,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that we cannot save self.assertTrue('success' in result and not result['success']) - def test_save_problem_submitted_no_randomize(self): module = CapaFactory.create(rerandomize='never', done=True) @@ -724,7 +696,6 @@ class CapaModuleTest(unittest.TestCase): module = CapaFactory.create(rerandomize="never", done=True) self.assertTrue(module.should_show_check_button()) - def test_should_show_reset_button(self): attempts = random.randint(1, 10) @@ -755,7 +726,6 @@ class CapaModuleTest(unittest.TestCase): module = CapaFactory.create(max_attempts=0, done=True) self.assertTrue(module.should_show_reset_button()) - def test_should_show_save_button(self): attempts = random.randint(1, 10) @@ -823,7 +793,6 @@ class CapaModuleTest(unittest.TestCase): html = module.get_problem_html() # assert that we got here without exploding - def test_get_problem_html(self): module = CapaFactory.create() @@ -869,7 +838,6 @@ class CapaModuleTest(unittest.TestCase): # Assert that the encapsulated html contains the original html self.assertTrue(html in html_encapsulated) - def test_get_problem_html_error(self): """ In production, when an error occurs with the problem HTML @@ -902,7 +870,6 @@ class CapaModuleTest(unittest.TestCase): # Expect that the module has created a new dummy problem with the error self.assertNotEqual(original_problem, module.lcp) - def test_random_seed_no_change(self): # Run the test for each possible rerandomize value @@ -920,10 +887,10 @@ class CapaModuleTest(unittest.TestCase): self.assertEqual(seed, 1) # Check the problem - get_request_dict = { CapaFactory.input_key(): '3.14'} + get_request_dict = {CapaFactory.input_key(): '3.14'} module.check_problem(get_request_dict) - # Expect that the seed is the same + # Expect that the seed is the same self.assertEqual(seed, module.seed) # Save the problem @@ -933,7 +900,7 @@ class CapaModuleTest(unittest.TestCase): self.assertEqual(seed, module.seed) def test_random_seed_with_reset(self): - + def _reset_and_get_seed(module): ''' Reset the XModule and return the module's seed @@ -956,7 +923,7 @@ class CapaModuleTest(unittest.TestCase): Returns True if *test_func* was successful (returned True) within *num_tries* attempts - *test_func* must be a function + *test_func* must be a function of the form test_func() -> bool ''' success = False @@ -989,9 +956,10 @@ class CapaModuleTest(unittest.TestCase): # Since there's a small chance we might get the # same seed again, give it 5 chances # to generate a different seed - success = _retry_and_check(5, - lambda: _reset_and_get_seed(module) != seed) - + success = _retry_and_check(5, + lambda: _reset_and_get_seed(module) != seed) + + # TODO: change this comparison to module.seed is not None? self.assertTrue(module.seed != None) msg = 'Could not get a new seed from reset after 5 tries' self.assertTrue(success, msg) diff --git a/lms/djangoapps/psychometrics/psychoanalyze.py b/lms/djangoapps/psychometrics/psychoanalyze.py index 093051a3bd..dd60776594 100644 --- a/lms/djangoapps/psychometrics/psychoanalyze.py +++ b/lms/djangoapps/psychometrics/psychoanalyze.py @@ -15,7 +15,6 @@ from scipy.optimize import curve_fit from django.conf import settings from django.db.models import Sum, Max from psychometrics.models import * -from xmodule.modulestore import Location log = logging.getLogger("mitx.psychometrics") @@ -292,7 +291,7 @@ def generate_plots_for_problem(problem): 'info': '', 'data': jsdata, 'cmd': '[%s], %s' % (','.join(jsplots), axisopts), - }) + }) #log.debug('plots = %s' % plots) return msg, plots @@ -333,9 +332,9 @@ def make_psychometrics_data_update_handler(course_id, user, module_state_key): pmd.done = done try: - pmd.attempts = state.get('attempts',0) + pmd.attempts = state.get('attempts', 0) except: - log.exception("no attempts for %s (state=%s)" % (sm,sm.state)) + log.exception("no attempts for %s (state=%s)" % (sm, sm.state)) try: checktimes = eval(pmd.checktimes) # update log of attempt timestamps From c7061a0262392c6e75747fcfed02dde0583c18c7 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Thu, 4 Apr 2013 10:20:31 -0400 Subject: [PATCH 43/66] add a command line utility to walk through the course and find common errors --- .../contentstore/management/commands/check_course.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/check_course.py b/cms/djangoapps/contentstore/management/commands/check_course.py index c691ac63a3..174048f108 100644 --- a/cms/djangoapps/contentstore/management/commands/check_course.py +++ b/cms/djangoapps/contentstore/management/commands/check_course.py @@ -19,12 +19,12 @@ class Command(BaseCommand): loc = CourseDescriptor.id_to_location(loc_str) - ms = modulestore() + modulestore = modulestore() # setup a request cache so we don't throttle the DB with all the metadata inheritance requests - ms.request_cache = RequestCache.get_request_cache() + modulestore.request_cache = RequestCache.get_request_cache() - course = ms.get_item(loc, depth=3) + course = modulestore.get_item(loc, depth=3) err_cnt = 0 def _xlint_metadata(module): From c0fc029b03a2eb8f01c186431366d5a2318cf498 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Thu, 4 Apr 2013 10:33:30 -0400 Subject: [PATCH 44/66] switch over the variable 'ms' to be 'store' --- .../contentstore/management/commands/check_course.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/check_course.py b/cms/djangoapps/contentstore/management/commands/check_course.py index 174048f108..35a11d7041 100644 --- a/cms/djangoapps/contentstore/management/commands/check_course.py +++ b/cms/djangoapps/contentstore/management/commands/check_course.py @@ -19,12 +19,12 @@ class Command(BaseCommand): loc = CourseDescriptor.id_to_location(loc_str) - modulestore = modulestore() + store = modulestore() # setup a request cache so we don't throttle the DB with all the metadata inheritance requests - modulestore.request_cache = RequestCache.get_request_cache() + store.request_cache = RequestCache.get_request_cache() - course = modulestore.get_item(loc, depth=3) + course = store.get_item(loc, depth=3) err_cnt = 0 def _xlint_metadata(module): @@ -61,7 +61,7 @@ class Command(BaseCommand): discussion_items =_get_discussion_items(course) # now query all discussion items via get_items() and compare with the tree-traversal - queried_discussion_items = ms.get_items(['i4x', course.location.org, course.location.course, + queried_discussion_items = store.get_items(['i4x', course.location.org, course.location.course, 'discussion', None, None]) for item in queried_discussion_items: From 039ccb83ccbb55a15d252fb59f1c97bb46e7a529 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Tue, 2 Apr 2013 16:23:32 -0400 Subject: [PATCH 45/66] Migrate to the open source XBlock repo --- common/lib/xmodule/xmodule/abtest_module.py | 2 +- common/lib/xmodule/xmodule/capa_module.py | 12 ++--- .../xmodule/combined_open_ended_module.py | 10 ++-- .../xmodule/xmodule/peer_grading_module.py | 2 +- common/lib/xmodule/xmodule/poll_module.py | 4 +- .../lib/xmodule/xmodule/randomize_module.py | 2 +- common/lib/xmodule/xmodule/seq_module.py | 2 +- .../lib/xmodule/xmodule/timelimit_module.py | 6 +-- common/lib/xmodule/xmodule/video_module.py | 2 +- .../lib/xmodule/xmodule/videoalpha_module.py | 2 +- lms/djangoapps/courseware/grades.py | 4 +- lms/djangoapps/courseware/model_data.py | 46 ++++++++-------- lms/djangoapps/courseware/models.py | 4 +- .../courseware/tests/test_model_data.py | 54 +++++++++---------- local-requirements.txt | 2 +- 15 files changed, 77 insertions(+), 77 deletions(-) diff --git a/common/lib/xmodule/xmodule/abtest_module.py b/common/lib/xmodule/xmodule/abtest_module.py index 0e1c66df8e..e84de270b2 100644 --- a/common/lib/xmodule/xmodule/abtest_module.py +++ b/common/lib/xmodule/xmodule/abtest_module.py @@ -33,7 +33,7 @@ def group_from_value(groups, v): class ABTestFields(object): group_portions = Object(help="What proportions of students should go in each group", default={DEFAULT: 1}, scope=Scope.content) - group_assignments = Object(help="What group this user belongs to", scope=Scope.student_preferences, default={}) + group_assignments = Object(help="What group this user belongs to", scope=Scope.preferences, default={}) group_content = Object(help="What content to display to each group", scope=Scope.content, default={DEFAULT: []}) experiment = String(help="Experiment that this A/B test belongs to", scope=Scope.content) has_children = True diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 2097e4d4ee..025d156e03 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -83,7 +83,7 @@ class ComplexEncoder(json.JSONEncoder): class CapaFields(object): - attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.student_state) + attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state) max_attempts = StringyInteger(help="Maximum number of attempts that a student is allowed", scope=Scope.settings) due = Date(help="Date that this problem is due by", scope=Scope.settings) graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings) @@ -91,12 +91,12 @@ class CapaFields(object): force_save_button = Boolean(help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False) rerandomize = Randomization(help="When to rerandomize the problem", default="always", scope=Scope.settings) data = String(help="XML data for the problem", scope=Scope.content) - correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.student_state, default={}) - input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.student_state) - student_answers = Object(help="Dictionary with the current student responses", scope=Scope.student_state) - done = Boolean(help="Whether the student has answered the problem", scope=Scope.student_state) + correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.user_state, default={}) + input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.user_state) + student_answers = Object(help="Dictionary with the current student responses", scope=Scope.user_state) + done = Boolean(help="Whether the student has answered the problem", scope=Scope.user_state) display_name = String(help="Display name for this module", scope=Scope.settings) - seed = StringyInteger(help="Random seed for this student", scope=Scope.student_state) + seed = StringyInteger(help="Random seed for this student", scope=Scope.user_state) weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings) markdown = String(help="Markdown source of this module", scope=Scope.settings) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index f70cf62d29..71b641fbd2 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -50,14 +50,14 @@ class VersionInteger(Integer): class CombinedOpenEndedFields(object): display_name = String(help="Display name for this module", default="Open Ended Grading", scope=Scope.settings) - current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.student_state) - task_states = List(help="List of state dictionaries of each task within this module.", scope=Scope.student_state) + current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.user_state) + task_states = List(help="List of state dictionaries of each task within this module.", scope=Scope.user_state) state = String(help="Which step within the current task that the student is on.", default="initial", - scope=Scope.student_state) + scope=Scope.user_state) student_attempts = Integer(help="Number of attempts taken by the student on this problem", default=0, - scope=Scope.student_state) + scope=Scope.user_state) ready_to_reset = Boolean(help="If the problem is ready to be reset or not.", default=False, - scope=Scope.student_state) + scope=Scope.user_state) attempts = Integer(help="Maximum number of attempts that a student is allowed.", default=1, scope=Scope.settings) is_graded = Boolean(help="Whether or not the problem is graded.", default=False, scope=Scope.settings) accept_file_upload = Boolean(help="Whether or not the problem accepts file uploads.", default=False, diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 5d064378bf..2226b8f7dd 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -38,7 +38,7 @@ class PeerGradingFields(object): max_grade = Integer(help="The maximum grade that a student can receieve for this problem.", default=MAX_SCORE, scope=Scope.settings) student_data_for_location = Object(help="Student data for a given peer grading problem.", default=json.dumps({}), - scope=Scope.student_state) + scope=Scope.user_state) weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings) diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py index 0fb3bfb496..c8ad44a918 100644 --- a/common/lib/xmodule/xmodule/poll_module.py +++ b/common/lib/xmodule/xmodule/poll_module.py @@ -30,8 +30,8 @@ class PollFields(object): # Name of poll to use in links to this poll display_name = String(help="Display name for this module", scope=Scope.settings) - voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.student_state, default=False) - poll_answer = String(help="Student answer", scope=Scope.student_state, default='') + voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.user_state, default=False) + poll_answer = String(help="Student answer", scope=Scope.user_state, default='') poll_answers = Object(help="All possible answers for the poll fro other students", scope=Scope.content) answers = List(help="Poll answers from xml", scope=Scope.content, default=[]) diff --git a/common/lib/xmodule/xmodule/randomize_module.py b/common/lib/xmodule/xmodule/randomize_module.py index 6620ab3cf7..240f33e33e 100644 --- a/common/lib/xmodule/xmodule/randomize_module.py +++ b/common/lib/xmodule/xmodule/randomize_module.py @@ -10,7 +10,7 @@ log = logging.getLogger('mitx.' + __name__) class RandomizeFields(object): - choice = Integer(help="Which random child was chosen", scope=Scope.student_state) + choice = Integer(help="Which random child was chosen", scope=Scope.user_state) class RandomizeModule(RandomizeFields, XModule): diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index f8e982f1a0..f6c3133ede 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -23,7 +23,7 @@ class SequenceFields(object): # NOTE: Position is 1-indexed. This is silly, but there are now student # positions saved on prod, so it's not easy to fix. - position = Integer(help="Last tab viewed in this sequence", scope=Scope.student_state) + position = Integer(help="Last tab viewed in this sequence", scope=Scope.user_state) class SequenceModule(SequenceFields, XModule): diff --git a/common/lib/xmodule/xmodule/timelimit_module.py b/common/lib/xmodule/xmodule/timelimit_module.py index efa47a5dca..732aa25e2e 100644 --- a/common/lib/xmodule/xmodule/timelimit_module.py +++ b/common/lib/xmodule/xmodule/timelimit_module.py @@ -16,9 +16,9 @@ log = logging.getLogger(__name__) class TimeLimitFields(object): - beginning_at = Float(help="The time this timer was started", scope=Scope.student_state) - ending_at = Float(help="The time this timer will end", scope=Scope.student_state) - accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.student_state) + beginning_at = Float(help="The time this timer was started", scope=Scope.user_state) + ending_at = Float(help="The time this timer will end", scope=Scope.user_state) + accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.user_state) time_expired_redirect_url = String(help="Url to redirect users to after the timelimit has expired", scope=Scope.settings) duration = Float(help="The length of this timer", scope=Scope.settings) suppress_toplevel_navigation = Boolean(help="Whether the toplevel navigation should be suppressed when viewing this module", scope=Scope.settings) diff --git a/common/lib/xmodule/xmodule/video_module.py b/common/lib/xmodule/xmodule/video_module.py index 0203299b40..2343d24a57 100644 --- a/common/lib/xmodule/xmodule/video_module.py +++ b/common/lib/xmodule/xmodule/video_module.py @@ -19,7 +19,7 @@ log = logging.getLogger(__name__) class VideoFields(object): data = String(help="XML data for the problem", scope=Scope.content) - position = Integer(help="Current position in the video", scope=Scope.student_state, default=0) + position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) display_name = String(help="Display name for this module", scope=Scope.settings) diff --git a/common/lib/xmodule/xmodule/videoalpha_module.py b/common/lib/xmodule/xmodule/videoalpha_module.py index a88c906b9c..6754f8f664 100644 --- a/common/lib/xmodule/xmodule/videoalpha_module.py +++ b/common/lib/xmodule/xmodule/videoalpha_module.py @@ -21,7 +21,7 @@ log = logging.getLogger(__name__) class VideoAlphaFields(object): data = String(help="XML data for the problem", scope=Scope.content) - position = Integer(help="Current position in the video", scope=Scope.student_state, default=0) + position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) display_name = String(help="Display name for this module", scope=Scope.settings) diff --git a/lms/djangoapps/courseware/grades.py b/lms/djangoapps/courseware/grades.py index 51c0b21799..ae386f1528 100644 --- a/lms/djangoapps/courseware/grades.py +++ b/lms/djangoapps/courseware/grades.py @@ -165,7 +165,7 @@ def grade(student, request, course, model_data_cache=None, keep_raw_scores=False # Create a fake key to pull out a StudentModule object from the ModelDataCache key = LmsKeyValueStore.Key( - Scope.student_state, + Scope.user_state, student.id, moduledescriptor.location, None @@ -370,7 +370,7 @@ def get_score(course_id, user, problem_descriptor, module_creator, model_data_ca # Create a fake KeyValueStore key to pull out the StudentModule key = LmsKeyValueStore.Key( - Scope.student_state, + Scope.user_state, user.id, problem_descriptor.location, None diff --git a/lms/djangoapps/courseware/model_data.py b/lms/djangoapps/courseware/model_data.py index b725f64308..826e766e5d 100644 --- a/lms/djangoapps/courseware/model_data.py +++ b/lms/djangoapps/courseware/model_data.py @@ -134,7 +134,7 @@ class ModelDataCache(object): """ if scope in (Scope.children, Scope.parent): return [] - elif scope == Scope.student_state: + elif scope == Scope.user_state: return self._chunked_query( StudentModule, 'module_state_key__in', @@ -159,7 +159,7 @@ class ModelDataCache(object): ), field_name__in=set(field.name for field in fields), ) - elif scope == Scope.student_preferences: + elif scope == Scope.preferences: return self._chunked_query( XModuleStudentPrefsField, 'module_type__in', @@ -167,7 +167,7 @@ class ModelDataCache(object): student=self.user.pk, field_name__in=set(field.name for field in fields), ) - elif scope == Scope.student_info: + elif scope == Scope.user_info: return self._query( XModuleStudentInfoField, student=self.user.pk, @@ -190,15 +190,15 @@ class ModelDataCache(object): """ Return the key used in the ModelDataCache for the specified KeyValueStore key """ - if key.scope == Scope.student_state: + if key.scope == Scope.user_state: return (key.scope, key.block_scope_id.url()) elif key.scope == Scope.content: return (key.scope, key.block_scope_id.url(), key.field_name) elif key.scope == Scope.settings: return (key.scope, '%s-%s' % (self.course_id, key.block_scope_id.url()), key.field_name) - elif key.scope == Scope.student_preferences: + elif key.scope == Scope.preferences: return (key.scope, key.block_scope_id, key.field_name) - elif key.scope == Scope.student_info: + elif key.scope == Scope.user_info: return (key.scope, key.field_name) def _cache_key_from_field_object(self, scope, field_object): @@ -206,15 +206,15 @@ class ModelDataCache(object): Return the key used in the ModelDataCache for the specified scope and field """ - if scope == Scope.student_state: + if scope == Scope.user_state: return (scope, field_object.module_state_key) elif scope == Scope.content: return (scope, field_object.definition_id, field_object.field_name) elif scope == Scope.settings: return (scope, field_object.usage_id, field_object.field_name) - elif scope == Scope.student_preferences: + elif scope == Scope.preferences: return (scope, field_object.module_type, field_object.field_name) - elif scope == Scope.student_info: + elif scope == Scope.user_info: return (scope, field_object.field_name) def find(self, key): @@ -237,7 +237,7 @@ class ModelDataCache(object): if field_object is not None: return field_object - if key.scope == Scope.student_state: + if key.scope == Scope.user_state: field_object, _ = StudentModule.objects.get_or_create( course_id=self.course_id, student=self.user, @@ -255,13 +255,13 @@ class ModelDataCache(object): field_name=key.field_name, usage_id='%s-%s' % (self.course_id, key.block_scope_id.url()), ) - elif key.scope == Scope.student_preferences: + elif key.scope == Scope.preferences: field_object, _ = XModuleStudentPrefsField.objects.get_or_create( field_name=key.field_name, module_type=key.block_scope_id, student=self.user, ) - elif key.scope == Scope.student_info: + elif key.scope == Scope.user_info: field_object, _ = XModuleStudentInfoField.objects.get_or_create( field_name=key.field_name, student=self.user, @@ -281,12 +281,12 @@ class LmsKeyValueStore(KeyValueStore): If the scope to write to is not one of the 5 named scopes: Scope.content Scope.settings - Scope.student_state - Scope.student_preferences - Scope.student_info + Scope.user_state + Scope.preferences + Scope.user_info then an InvalidScopeError will be raised. - Data for Scope.student_state is stored as StudentModule objects via the django orm. + Data for Scope.user_state is stored as StudentModule objects via the django orm. Data for the other scopes is stored in individual objects that are named for the scope involved and have the field name as a key @@ -297,9 +297,9 @@ class LmsKeyValueStore(KeyValueStore): _allowed_scopes = ( Scope.content, Scope.settings, - Scope.student_state, - Scope.student_preferences, - Scope.student_info, + Scope.user_state, + Scope.preferences, + Scope.user_info, Scope.children, ) @@ -321,7 +321,7 @@ class LmsKeyValueStore(KeyValueStore): if field_object is None: raise KeyError(key.field_name) - if key.scope == Scope.student_state: + if key.scope == Scope.user_state: return json.loads(field_object.state)[key.field_name] else: return json.loads(field_object.value) @@ -335,7 +335,7 @@ class LmsKeyValueStore(KeyValueStore): if key.scope not in self._allowed_scopes: raise InvalidScopeError(key.scope) - if key.scope == Scope.student_state: + if key.scope == Scope.user_state: state = json.loads(field_object.state) state[key.field_name] = value field_object.state = json.dumps(state) @@ -355,7 +355,7 @@ class LmsKeyValueStore(KeyValueStore): if field_object is None: raise KeyError(key.field_name) - if key.scope == Scope.student_state: + if key.scope == Scope.user_state: state = json.loads(field_object.state) del state[key.field_name] field_object.state = json.dumps(state) @@ -377,7 +377,7 @@ class LmsKeyValueStore(KeyValueStore): if field_object is None: return False - if key.scope == Scope.student_state: + if key.scope == Scope.user_state: return key.field_name in json.loads(field_object.state) else: return True diff --git a/lms/djangoapps/courseware/models.py b/lms/djangoapps/courseware/models.py index 448757a2f8..53493b8e45 100644 --- a/lms/djangoapps/courseware/models.py +++ b/lms/djangoapps/courseware/models.py @@ -165,7 +165,7 @@ class XModuleSettingsField(models.Model): class XModuleStudentPrefsField(models.Model): """ - Stores data set in the Scope.student_preferences scope by an xmodule field + Stores data set in the Scope.preferences scope by an xmodule field """ class Meta: @@ -199,7 +199,7 @@ class XModuleStudentPrefsField(models.Model): class XModuleStudentInfoField(models.Model): """ - Stores data set in the Scope.student_preferences scope by an xmodule field + Stores data set in the Scope.preferences scope by an xmodule field """ class Meta: diff --git a/lms/djangoapps/courseware/tests/test_model_data.py b/lms/djangoapps/courseware/tests/test_model_data.py index 7f4727cf15..65eaa5a4bd 100644 --- a/lms/djangoapps/courseware/tests/test_model_data.py +++ b/lms/djangoapps/courseware/tests/test_model_data.py @@ -32,9 +32,9 @@ course_id = 'edX/test_course/test' content_key = partial(LmsKeyValueStore.Key, Scope.content, None, location('def_id')) settings_key = partial(LmsKeyValueStore.Key, Scope.settings, None, location('def_id')) -student_state_key = partial(LmsKeyValueStore.Key, Scope.student_state, 'user', location('def_id')) -student_prefs_key = partial(LmsKeyValueStore.Key, Scope.student_preferences, 'user', 'problem') -student_info_key = partial(LmsKeyValueStore.Key, Scope.student_info, 'user', None) +user_state_key = partial(LmsKeyValueStore.Key, Scope.user_state, 'user', location('def_id')) +prefs_key = partial(LmsKeyValueStore.Key, Scope.preferences, 'user', 'problem') +user_info_key = partial(LmsKeyValueStore.Key, Scope.user_info, 'user', None) class UserFactory(factory.Factory): @@ -115,13 +115,13 @@ class TestInvalidScopes(TestCase): def setUp(self): self.desc_md = {} self.user = UserFactory.create() - self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.student_state, 'a_field')])], course_id, self.user) + self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user) self.kvs = LmsKeyValueStore(self.desc_md, self.mdc) def test_invalid_scopes(self): - for scope in (Scope(student=True, block=BlockScope.DEFINITION), - Scope(student=False, block=BlockScope.TYPE), - Scope(student=False, block=BlockScope.ALL)): + for scope in (Scope(user=True, block=BlockScope.DEFINITION), + Scope(user=False, block=BlockScope.TYPE), + Scope(user=False, block=BlockScope.ALL)): self.assertRaises(InvalidScopeError, self.kvs.get, LmsKeyValueStore.Key(scope, None, None, 'field')) self.assertRaises(InvalidScopeError, self.kvs.set, LmsKeyValueStore.Key(scope, None, None, 'field'), 'value') self.assertRaises(InvalidScopeError, self.kvs.delete, LmsKeyValueStore.Key(scope, None, None, 'field')) @@ -134,48 +134,48 @@ class TestStudentModuleStorage(TestCase): self.desc_md = {} student_module = StudentModuleFactory(state=json.dumps({'a_field': 'a_value'})) self.user = student_module.student - self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.student_state, 'a_field')])], course_id, self.user) + self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user) self.kvs = LmsKeyValueStore(self.desc_md, self.mdc) def test_get_existing_field(self): "Test that getting an existing field in an existing StudentModule works" - self.assertEquals('a_value', self.kvs.get(student_state_key('a_field'))) + self.assertEquals('a_value', self.kvs.get(user_state_key('a_field'))) def test_get_missing_field(self): "Test that getting a missing field from an existing StudentModule raises a KeyError" - self.assertRaises(KeyError, self.kvs.get, student_state_key('not_a_field')) + self.assertRaises(KeyError, self.kvs.get, user_state_key('not_a_field')) def test_set_existing_field(self): - "Test that setting an existing student_state field changes the value" - self.kvs.set(student_state_key('a_field'), 'new_value') + "Test that setting an existing user_state field changes the value" + self.kvs.set(user_state_key('a_field'), 'new_value') self.assertEquals(1, StudentModule.objects.all().count()) self.assertEquals({'a_field': 'new_value'}, json.loads(StudentModule.objects.all()[0].state)) def test_set_missing_field(self): - "Test that setting a new student_state field changes the value" - self.kvs.set(student_state_key('not_a_field'), 'new_value') + "Test that setting a new user_state field changes the value" + self.kvs.set(user_state_key('not_a_field'), 'new_value') self.assertEquals(1, StudentModule.objects.all().count()) self.assertEquals({'a_field': 'a_value', 'not_a_field': 'new_value'}, json.loads(StudentModule.objects.all()[0].state)) def test_delete_existing_field(self): "Test that deleting an existing field removes it from the StudentModule" - self.kvs.delete(student_state_key('a_field')) + self.kvs.delete(user_state_key('a_field')) self.assertEquals(1, StudentModule.objects.all().count()) - self.assertRaises(KeyError, self.kvs.get, student_state_key('not_a_field')) + self.assertRaises(KeyError, self.kvs.get, user_state_key('not_a_field')) def test_delete_missing_field(self): "Test that deleting a missing field from an existing StudentModule raises a KeyError" - self.assertRaises(KeyError, self.kvs.delete, student_state_key('not_a_field')) + self.assertRaises(KeyError, self.kvs.delete, user_state_key('not_a_field')) self.assertEquals(1, StudentModule.objects.all().count()) self.assertEquals({'a_field': 'a_value'}, json.loads(StudentModule.objects.all()[0].state)) def test_has_existing_field(self): "Test that `has` returns True for existing fields in StudentModules" - self.assertTrue(self.kvs.has(student_state_key('a_field'))) + self.assertTrue(self.kvs.has(user_state_key('a_field'))) def test_has_missing_field(self): "Test that `has` returns False for missing fields in StudentModule" - self.assertFalse(self.kvs.has(student_state_key('not_a_field'))) + self.assertFalse(self.kvs.has(user_state_key('not_a_field'))) class TestMissingStudentModule(TestCase): @@ -187,14 +187,14 @@ class TestMissingStudentModule(TestCase): def test_get_field_from_missing_student_module(self): "Test that getting a field from a missing StudentModule raises a KeyError" - self.assertRaises(KeyError, self.kvs.get, student_state_key('a_field')) + self.assertRaises(KeyError, self.kvs.get, user_state_key('a_field')) def test_set_field_in_missing_student_module(self): "Test that setting a field in a missing StudentModule creates the student module" self.assertEquals(0, len(self.mdc.cache)) self.assertEquals(0, StudentModule.objects.all().count()) - self.kvs.set(student_state_key('a_field'), 'a_value') + self.kvs.set(user_state_key('a_field'), 'a_value') self.assertEquals(1, len(self.mdc.cache)) self.assertEquals(1, StudentModule.objects.all().count()) @@ -207,11 +207,11 @@ class TestMissingStudentModule(TestCase): def test_delete_field_from_missing_student_module(self): "Test that deleting a field from a missing StudentModule raises a KeyError" - self.assertRaises(KeyError, self.kvs.delete, student_state_key('a_field')) + self.assertRaises(KeyError, self.kvs.delete, user_state_key('a_field')) def test_has_field_for_missing_student_module(self): "Test that `has` returns False for missing StudentModules" - self.assertFalse(self.kvs.has(student_state_key('a_field'))) + self.assertFalse(self.kvs.has(user_state_key('a_field'))) class StorageTestBase(object): @@ -286,13 +286,13 @@ class TestContentStorage(StorageTestBase, TestCase): class TestStudentPrefsStorage(StorageTestBase, TestCase): factory = StudentPrefsFactory - scope = Scope.student_preferences - key_factory = student_prefs_key + scope = Scope.preferences + key_factory = prefs_key storage_class = XModuleStudentPrefsField class TestStudentInfoStorage(StorageTestBase, TestCase): factory = StudentInfoFactory - scope = Scope.student_info - key_factory = student_info_key + scope = Scope.user_info + key_factory = user_info_key storage_class = XModuleStudentInfoField diff --git a/local-requirements.txt b/local-requirements.txt index de2d274719..177897f53d 100644 --- a/local-requirements.txt +++ b/local-requirements.txt @@ -6,4 +6,4 @@ # XBlock: # Might change frequently, so put it in local-requirements.txt, # but conceptually is an external package, so it is in a separate repo. --e git+ssh://git@github.com/MITx/xmodule-debugger@9a4f883a#egg=XBlock +-e git+https://github.com/edx/XBlock.git@96d8f5f4#egg=XBlock From 4c511c3c6634af9d57b985ccfe7b222c5fe08220 Mon Sep 17 00:00:00 2001 From: Brian Wilson Date: Thu, 4 Apr 2013 11:14:52 -0400 Subject: [PATCH 46/66] add progress logging --- .../courseware/management/commands/remove_input_state.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lms/djangoapps/courseware/management/commands/remove_input_state.py b/lms/djangoapps/courseware/management/commands/remove_input_state.py index 9adabeafc9..e45d08e351 100644 --- a/lms/djangoapps/courseware/management/commands/remove_input_state.py +++ b/lms/djangoapps/courseware/management/commands/remove_input_state.py @@ -76,6 +76,11 @@ class Command(BaseCommand): for hist_module in hist_modules: self.remove_studentmodulehistory_input_state(hist_module, save_changes) + if self.num_visited % 1000 == 0: + LOG.info(" Progress: updated {0} of {1} student modules".format(self.num_changed, self.num_visited)) + LOG.info(" Progress: updated {0} of {1} student history modules".format(self.num_hist_changed, + self.num_hist_visited)) + @transaction.autocommit def remove_studentmodule_input_state(self, module, save_changes): ''' Fix the grade assigned to a StudentModule''' From ea6174af28edef0b36d46f3e3b311e3fa624b2e8 Mon Sep 17 00:00:00 2001 From: John Jarvis Date: Thu, 4 Apr 2013 11:40:44 -0400 Subject: [PATCH 47/66] fixing image resolution for the stanford-university image --- .../releases/stanford-university_204x114.png | Bin 0 -> 8861 bytes lms/templates/feed.rss | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 lms/static/images/press/releases/stanford-university_204x114.png diff --git a/lms/static/images/press/releases/stanford-university_204x114.png b/lms/static/images/press/releases/stanford-university_204x114.png new file mode 100644 index 0000000000000000000000000000000000000000..79dac0732c6500721d98dc73dee4609a161a692e GIT binary patch literal 8861 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 E2SIT;bN~PV literal 0 HcmV?d00001 diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index 1ac88ffe34..bd97113e33 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -13,7 +13,7 @@ 2012-12-19T14:00:00-07:00 Stanford University to Collaborate with edX on Development of Non-Profit Open Source edX Platform - <img src="${static.url('images/press/releases/stanford-university_102x57.png')}" /> + <img src="${static.url('images/press/releases/stanford-university_204x114.png')}" /> <p></p> From d3e7739b3b4b2f2ea72539148c9c082ac66d0a2b Mon Sep 17 00:00:00 2001 From: Brian Wilson Date: Thu, 4 Apr 2013 12:03:08 -0400 Subject: [PATCH 48/66] add user name and email to progress page --- lms/djangoapps/courseware/views.py | 1 + lms/templates/courseware/progress.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index b2b0874786..ae15b40d26 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -630,6 +630,7 @@ def progress(request, course_id, student_id=None): 'courseware_summary': courseware_summary, 'grade_summary': grade_summary, 'staff_access': staff_access, + 'student': student, } context.update() diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index f94e7651f0..9e2a2e5982 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -31,7 +31,7 @@ ${progress_graph.body(grade_summary, course.grade_cutoffs, "grade-detail-graph",
        -

        Course Progress

        +

        Course Progress for Student '${student.username}' (${student.email})

        %if not course.disable_progress_graph: From db1c0bf081a01748d50c9109d4131502129cc279 Mon Sep 17 00:00:00 2001 From: "Mark L. Chang" Date: Thu, 4 Apr 2013 12:14:34 -0400 Subject: [PATCH 49/66] added dev key so tests run --- cms/envs/test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cms/envs/test.py b/cms/envs/test.py index 59664bfd40..7d898de478 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -118,3 +118,6 @@ PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.SHA1PasswordHasher', 'django.contrib.auth.hashers.MD5PasswordHasher', ) + +# segment-io key for dev +SEGMENT_IO_KEY = 'mty8edrrsg' From 73113eddc725bb05102e8b8f95b874f5b1e56d04 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Thu, 4 Apr 2013 13:38:30 -0400 Subject: [PATCH 50/66] fix xml_attributes inspection --- .../contentstore/management/commands/check_course.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/check_course.py b/cms/djangoapps/contentstore/management/commands/check_course.py index 35a11d7041..aec1a34c04 100644 --- a/cms/djangoapps/contentstore/management/commands/check_course.py +++ b/cms/djangoapps/contentstore/management/commands/check_course.py @@ -38,9 +38,10 @@ class Command(BaseCommand): # we've had a bug where the xml_attributes field can we rewritten as a string rather than a dict def _check_xml_attributes_field(module): err_cnt = 0 - if hasattr(module, 'xml_attributes') and (isinstance(module, str) or isinstance(module, unicode)): - print 'module = {0} has xml_attributes as a string. It should be a dict'.format(module.location.url()) - err_cnt = err_cnt + 1 + if hasattr(module, 'xml_attributes'): + if isinstance(module.xml_attributes, str) or isinstance(module.xml_attributes, unicode): + print 'module = {0} has xml_attributes as a string. It should be a dict'.format(module.location.url()) + err_cnt = err_cnt + 1 for child in module.get_children(): err_cnt = err_cnt + _check_xml_attributes_field(child) return err_cnt From 02b7ab4fa075ca22caa87722b3dd9b2c73c5fbe8 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Fri, 29 Mar 2013 12:49:24 -0400 Subject: [PATCH 51/66] Tests to make sure that input_states have the correct keys and are not cross-pollinating --- .../lib/xmodule/xmodule/tests/test_capa_module.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index d94345fe1c..7f334207e7 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -838,6 +838,19 @@ class CapaModuleTest(unittest.TestCase): # Assert that the encapsulated html contains the original html self.assertTrue(html in html_encapsulated) + def test_input_state_consistency(self): + module1 = CapaFactory.create() + module2 = CapaFactory.create() + + # check to make sure that the input_state and the keys have the same values + module1.set_state_from_lcp() + self.assertEqual(module1.lcp.inputs.keys(),module1.input_state.keys()) + + module2.set_state_from_lcp() + + intersection = set(module2.input_state.keys()).intersection(set(module1.input_state.keys())) + self.assertEqual(len(intersection), 0) + def test_get_problem_html_error(self): """ In production, when an error occurs with the problem HTML From ffc125949662142b4c7472ee3ff9014e6e5aafb8 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Thu, 4 Apr 2013 10:21:40 -0400 Subject: [PATCH 52/66] Apply text and image changes reqeusted by UTAustinX Lighthouse LMS tickets: [#307 state:resolved] [#310 state:resolved] [#319 state:resolved] [#322 state:resolved] --- .../utaustin/utaustin-cover_2025x550.jpg | Bin 91807 -> 68619 bytes .../university_profile/utaustinx.html | 2 +- lms/templates/university_profile/utx.html | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/static/images/university/utaustin/utaustin-cover_2025x550.jpg b/lms/static/images/university/utaustin/utaustin-cover_2025x550.jpg index 7294b53f1b07603575dc6023006d261b4efe33b8..4cf76ba8a120c279fb59397e6665a23d61b1755e 100644 GIT binary patch literal 68619 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 literal 91807 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 <%block name="university_description"> -

        The University of Texas at Austin is the top-ranked public university in a nearly 1,000-mile radius, and is ranked in the top 25 universities in the world. Students have been finding their passion in life at UT Austin for more than 130 years, and it has been a member of the prestigious AAU since 1929. UT Austin combines the academic depth and breadth of a world research institute (regularly ranking within the top three producers of doctoral degrees in the country) with the fun and excitement of a big-time collegiate experience. It is currently the fifth-largest university in America, with more than 50,000 students and 3,000 professors across 17 colleges and schools, and is the first major American university to build a medical school in the past 50 years.

        +

        The University of Texas at Austin is the top-ranked public university in a nearly 1,000-mile radius, and is ranked in the top 25 universities in the world. Students have been finding their passion in life at UT Austin for more than 130 years, and it has been a member of the prestigious AAU since 1929. UT Austin combines the academic depth and breadth of a world research institute (regularly ranking within the top three producers of doctoral degrees in the country) with the fun and excitement of a big-time collegiate experience. It is currently the fifth-largest university in America, with more than 50,000 students and 3,000 professors across 17 colleges and schools. UT Austin will be opening the Dell Medical School in 2016.

        ${parent.body()} diff --git a/lms/templates/university_profile/utx.html b/lms/templates/university_profile/utx.html index ea34ddb85b..d25d8f09b8 100644 --- a/lms/templates/university_profile/utx.html +++ b/lms/templates/university_profile/utx.html @@ -22,7 +22,7 @@ <%block name="university_description">

        Educating students, providing care for patients, conducting groundbreaking research and serving the needs of Texans and the nation for more than 130 years, The University of Texas System is one of the largest public university systems in the United States, with nine academic universities and six health science centers. Student enrollment exceeded 215,000 in the 2011 academic year. The UT System confers more than one-third of the state’s undergraduate degrees and educates nearly three-fourths of the state’s health care professionals annually. The UT System has an annual operating budget of $13.1 billion (FY 2012) including $2.3 billion in sponsored programs funded by federal, state, local and private sources. With roughly 87,000 employees, the UT System is one of the largest employers in the state.

        -

        Find out about the University of Texas Austin.

        +

        Find out about The University of Texas at Austin.

        ${parent.body()} From 32b8c59320af7f9477d08b776ebe1ee078b67ce3 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Thu, 4 Apr 2013 11:08:44 -0400 Subject: [PATCH 53/66] Update jobs page Lighthouse ticket [#304 state:resolved] --- lms/templates/static_templates/jobs.html | 108 ++++++++++++++++++++--- 1 file changed, 97 insertions(+), 11 deletions(-) diff --git a/lms/templates/static_templates/jobs.html b/lms/templates/static_templates/jobs.html index e33ff62e9a..f6a93b6f8a 100644 --- a/lms/templates/static_templates/jobs.html +++ b/lms/templates/static_templates/jobs.html @@ -159,13 +159,50 @@
      • Proactive, optimistic approach to problem solving.
      • Commitment to constant personal and organizational improvement.
      • Willingness to travel to partner sites as needed.
      • -
      • Bachelors required, Master’s in Education, organizational learning, or other related field preferred.
      • +
      • Bachelor's or Master’s in Education, organizational learning, or other related field preferred. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.

      If you are interested in this position, please send an email to jobs@edx.org.

    + +
    +
    +

    TRAINER

    +

    All those Universities on the edX homepage are full of incredible professors and teaching teams, designing on-line courses that will change the face of education. The edX team is constantly training whole new university teams on how to make their visions shine using edX software. We’re looking for some truly talented people to help train people on the tools that are enabling the future of education.

    +

    Responsibilities:

    +
      +
    • Facilitate training programs as required ensuring that best practices are incorporated in all learning environments.
    • +
    • Create and design learning materials for training curriculums, incorporate edX best practices into training curriculum.
    • +
    • Incorporate key performance metrics into training modules; participate in strategic initiatives
    • +
    • Measure, monitor and share training results with business units to identify future training opportunities.
    • +
    • Identify and leverage existing resources to maximize partner efficiency and productivity.
    • +
    • Work with both Universities and edX to provide strategic input based on future training needs.
    • +
    • Communicate effectively in oral and written presentations.
    • +
    • Analyze learners training needs and identify cross training opportunities.
    • +
    • Mentor and train others on training tools to expand training efficiency and uniformity.
    • +
    • Build relationships with universities to be viewed as a trusted training partner.
    • +
    +

    Requirements:

    +
      +
    • Minimum of 1-3 years experience developing and delivering educational training, preferably in an educational technology organization.
    • +
    • Lean and Agile thinking and training. Experienced in Scrum or kanban preferred.
    • +
    • Excellent interpersonal skills including proven presentation and facilitation skills.
    • +
    • Strong oral and written communication skills.
    • +
    • Flexibility to work on a variety of initiatives; prior startup experience preferred.
    • +
    • Outstanding work ethic, results-oriented, and creative/innovative style.
    • +
    • Proactive, optimistic approach to problem solving.
    • +
    • Commitment to constant personal and organizational improvement.
    • +
    • Willingness to travel to partner sites as needed.
    • +
    • Bachelors or Master’s in Education, organizational learning, instructional design or other related field preferred. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
    • +
    + +

    If you are interested in this position, please send an email to jobs@edx.org.

    +
    +
    + +

    INSTRUCTIONAL DESIGNER

    @@ -187,8 +224,10 @@

Qualifications:

    -
  • Master's Degree in Educational Technology, Instructional Design or related field. Experience in higher education with additional experience in a start-up or research environment preferable.
  • -
  • Excellent interpersonal and communication (written and verbal), project management, problem-solving and time management skills. The ability to be flexible with projects and to work on multiple courses essential.
  • Ability to meet deadlines and manage expectations of constituents. +
  • Master's Degree in Educational Technology, Instructional Design or related field. Experience in higher education with additional experience in a start-up or research environment preferable. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
  • +
  • Experience in higher education with additional experience in a start-up or research environment preferable.
  • +
  • Excellent interpersonal and communication (written and verbal), project management, problem-solving and time management skills. The ability to be flexible with projects and to work on multiple courses essential.
  • +
  • Ability to meet deadlines and manage expectations of constituents.
  • Capacity to develop new and relevant technology skills. Experience using game theory design and learning analytics to inform instructional design decisions and strategy.
  • Technical Skills: Video and screencasting experience. LMS Platform experience, xml, HTML, CSS, Adobe Design Suite, Camtasia or Captivate experience. Experience with web 2.0 collaboration tools.
@@ -205,16 +244,16 @@

edX Program Managers (PM) lead the edX's course production process. They are systems thinkers who manage the creation of a course from start to finish. PMs work with University Professors and course staff to help them take advantage of edX services to create world class online learning offerings and encourage the exploration of an emerging form of higher education.

Responsibilities:

    -
  • Create and execute the course production cycle. PMs are able to examine and explain what they do in great detail and able to think abstractly about people, time, and processes. They coordinate the efforts of multiple
  • teams engaged in the production of the courses assigned to them. +
  • Create and execute the course production cycle. PMs are able to examine and explain what they do in great detail and able to think abstractly about people, time, and processes. They coordinate the efforts of multiple teams engaged in the production of the courses assigned to them.
  • Train partners and drive best practices adoption. PMs train course staff from partner institutions and help them adopt best practices for workflow and tools.
  • Build capacity. Mentor staff at partner institutions, train the trainers that help them scale their course production ability.
  • -
  • Create visibility. PMs are responsible for making the state of the course production system accessible and comprehensible to all stakeholders. They are capable of training Course development teams in Scrum and
  • Kanban, and are Lean thinkers and educators. +
  • Create visibility. PMs are responsible for making the state of the course production system accessible and comprehensible to all stakeholders. They are capable of training Course development teams in Scrum and Kanban, and are Lean thinkers and educators.
  • Improve workflows. PMs are responsible for carefully assessing the methods and outputs of each course and adjusting them to take best advantage of available resources.
  • Encourage innovation. Spark creativity in course teams to build new courses that could never be produced in brick and mortar settings.

Qualifications:

    -
  • Bachelor's Degree. Master's Degree preferred.
  • +
  • Bachelor's Degree. Master's Degree preferred. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
  • At least 2 years of experience working with University faculty and administrators.
  • Proven record of successful Scrum or Kanban project management, including use of project management tools.
  • Ability to create processes that systematically provide solutions to open ended challenges.
  • @@ -256,7 +295,7 @@

Skills:

    -
  • Bachelor’s degree or higher
  • +
  • Bachelor’s degree or higher. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
  • Exquisite communication skills, especially listening
  • Inexhaustible attention to detail with the ability to let go of perfection
  • Deep commitment to Lean project management, including a dedication to its best intentions not just its rituals
  • @@ -286,8 +325,7 @@

Qualifications:

    -
  • Bachelor’s degree or higher in a Technical Area
  • -
  • MBA or Masters in Design preferred
  • +
  • Bachelor’s degree or higher in a Technical Area, MBA or Masters in Design preferred. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
  • Proven ability to develop and implement strategy
  • Exquisite organizational skills
  • Deep analytical skills
  • @@ -319,7 +357,7 @@

Qualifications:

    -
  • Bachelor’s degree or higher
  • +
  • Bachelor’s degree or higher. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
  • Thorough knowledge of Python, DJango, XML,HTML, CSS , Javascript and backbone.js
  • Ability to work on multiple projects simultaneously without splintering
  • Tactfully escalate conflicting deadlines or priorities only when needed. Otherwise help the team members negotiate a solution.
  • @@ -358,7 +396,7 @@
  • Test Driven Development
  • Committed to Documentation best practices so your code can be consumed in an open source environment
  • Contributor to or consumer of Open Source Frameworks
  • -
  • BS in Computer Science from top-tier institution
  • +
  • BS in Computer Science from top-tier institution. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.
  • Acknowledged by peers as a technology leader
@@ -367,6 +405,51 @@ +
+
+

DEVOPS ENGINEER – SYESTEMS ADMINISTRATOR

+

The Devop Engineers at edX help develop and maintain the infrastructure in AWS for all services and systems required to run edX. We're seeking a capable systems administrator who is unafraid of scripting languages and development to build out tools in order to improve the functionality of edX. The devops team primarily focuses on the provisioning, configuration, and deployment of services at edX. If you have a passion for automation and constant improvement then we want to hear from you. Our production environment is primarily built on Ubuntu (in AWS) and we use Puppet and Fabric to manage most of the environment.

+

In addition to the primary task of building infrastructure the Devops team supports the developers in a variety of other contexts, including helping with desktop development environments if required. We participate in on-call and emergency support and there will be occasional out of normal hours work required.

+

Responsibilities:

+
    +
  • Work with developers and staff to maintain and improve the infrastructure of edX.
  • +
  • Assist where needed with other technical support tasks to support the fast moving pace of edX.
  • +
  • Rapidly diagnose and resolve faults with organization-wide servers and services, and communicate to users as appropriate.
  • +
+

Requirements:

+
    +
  • Bachelor's degree in engineering or computer science. But we're all about education, so let us know how you gained what you need to succeed in this role: projects after completing 6.00x or CS50x, Xbox cheevos, on-line guilds led, large scale innovations championed.3 or more years of systems administration.
  • +
  • Must have an excellent working knowledge of Linux both as an end-user and as an administrator.
  • +
  • Must be adept in programming/scripting languages such as Python, Ruby, Bash.
  • +
  • Must be familiar with a configuration management system such as Puppet, Chef, Ansible.
  • +
  • Must have experience running web applications in a production environment.
  • +
  • Must have excellent personal interaction skills as the position requires interfacing with a wide range of people up to board level.
  • +
  • Ideally possesses experience with some of the following technologies: nginx, mysql, mongodb, django environments, splunk, git.
  • +
+ +

If you are interested in this position, please send an email to jobs@edx.org.

+
+
+ + +
+
+

LEARNING SCIENCES ENGINEER

+

In 2012, edX reinvented education. In 2013, the edX learning sciences team is charged with reinventing education, again. The goal of the team is to prototype and develop technologies which will radically change the way students learn and instructors teach. We will engage in projects in learning analytics, crowdsourced content development, intelligent tutoring, as well as radical changes to the ways course content is structured. We are looking to opportunistically build a small (3 person), fast-moving team capable of rapidly bringing advanced development projects to prototype and to market. All members of the team must be spectacular software engineers capable of working in or adapting to dynamic, duck typed, functional languages (Python and JavaScript). In addition, we are looking for some combination of:

+
    +
  • Deep expertise in mathematics, and in particular, advanced linear algebra, machine learning, big data, psychometrics, and probability.
  • +
  • UX design. Capable of envisioning user interface for software that does things that have never been done before, and bringing them through to market. Skills should be broad and range the full gamut: graphic design, UX, HTML5, basic JavaScript, and CSS.
  • +
  • Interest and experience in both research and practice of education, cognitive science, and related fields.
  • +
  • Core backend experience (Python, Django, MongoDB, SQL)
  • +
  • Background in social networks and social network analysis (both social science and mathematics) is desirable as well.
  • +
+

More than anything, we’re looking for spectacular people capable of very rapidly building things which have never been built before. We’re capable of providing both traditional employment, and potentially, in partnership with MIT, more academic opportunities.

+ +

If you are interested in this position, please send an email to jobs@edx.org.

+
+
+ +
@@ -374,12 +457,15 @@

How to Apply

E-mail your resume, cover letter and any other materials to jobs@edx.org

From d498694659bc000f301dac9e7afb3ae35551b37b Mon Sep 17 00:00:00 2001 From: Greg Price Date: Thu, 4 Apr 2013 13:46:46 -0400 Subject: [PATCH 54/66] Fix date on Stanford press release Lighthouse ticket [#328 state:resolved] --- .../static_templates/press_releases/stanford_announcement.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/static_templates/press_releases/stanford_announcement.html b/lms/templates/static_templates/press_releases/stanford_announcement.html index be788f319c..2b19b62de3 100644 --- a/lms/templates/static_templates/press_releases/stanford_announcement.html +++ b/lms/templates/static_templates/press_releases/stanford_announcement.html @@ -73,7 +73,7 @@ Stanford University and edX, the not-for-profi