Commit 47aacc70 by Brian Talbot

Merge branch 'master' into feature/btalbot/studio-alerts

parents bc0b1b09 999ed17e
...@@ -21,18 +21,26 @@ class Command(BaseCommand): ...@@ -21,18 +21,26 @@ class Command(BaseCommand):
'''Delete a MongoDB backed course''' '''Delete a MongoDB backed course'''
def handle(self, *args, **options): def handle(self, *args, **options):
if len(args) != 1: if len(args) != 1 and len(args) != 2:
raise CommandError("delete_course requires one argument: <location>") raise CommandError("delete_course requires one or more arguments: <location> |commit|")
loc_str = args[0] loc_str = args[0]
commit = False
if len(args) == 2:
commit = args[1] == 'commit'
if commit:
print 'Actually going to delete the course from DB....'
ms = modulestore('direct') ms = modulestore('direct')
cs = contentstore() cs = contentstore()
if query_yes_no("Deleting course {0}. Confirm?".format(loc_str), default="no"): if query_yes_no("Deleting course {0}. Confirm?".format(loc_str), default="no"):
if query_yes_no("Are you sure. This action cannot be undone!", default="no"): if query_yes_no("Are you sure. This action cannot be undone!", default="no"):
loc = CourseDescriptor.id_to_location(loc_str) loc = CourseDescriptor.id_to_location(loc_str)
if delete_course(ms, cs, loc) == True: if delete_course(ms, cs, loc, commit) == True:
print 'removing User permissions from course....' print 'removing User permissions from course....'
# in the django layer, we need to remove all the user permissions groups associated with this course # in the django layer, we need to remove all the user permissions groups associated with this course
if commit:
_delete_course_group(loc) _delete_course_group(loc)
...@@ -171,7 +171,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): ...@@ -171,7 +171,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012') location = CourseDescriptor.id_to_location('edX/full/6.002_Spring_2012')
delete_course(ms, cs, location) delete_course(ms, cs, location, commit=True)
items = ms.get_items(Location(['i4x', 'edX', 'full', 'vertical', None])) items = ms.get_items(Location(['i4x', 'edX', 'full', 'vertical', None]))
self.assertEqual(len(items), 0) self.assertEqual(len(items), 0)
...@@ -465,7 +465,9 @@ class ContentStoreTest(ModuleStoreTestCase): ...@@ -465,7 +465,9 @@ class ContentStoreTest(ModuleStoreTestCase):
# check for grace period definition which should be defined at the course level # check for grace period definition which should be defined at the course level
self.assertIn('graceperiod', new_module.metadata) self.assertIn('graceperiod', new_module.metadata)
self.assertEqual(course.metadata['graceperiod'], new_module.metadata['graceperiod']) self.assertEqual(parent.metadata['graceperiod'], new_module.metadata['graceperiod'])
self.assertEqual(course.metadata['xqa_key'], new_module.metadata['xqa_key'])
# #
# now let's define an override at the leaf node level # now let's define an override at the leaf node level
......
...@@ -80,10 +80,15 @@ def get_lms_link_for_item(location, preview=False, course_id=None): ...@@ -80,10 +80,15 @@ def get_lms_link_for_item(location, preview=False, course_id=None):
course_id = get_course_id(location) course_id = get_course_id(location)
if settings.LMS_BASE is not None: if settings.LMS_BASE is not None:
lms_link = "//{preview}{lms_base}/courses/{course_id}/jump_to/{location}".format( if preview:
preview='preview.' if preview else '', lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE',
lms_base=settings.LMS_BASE, 'preview.' + settings.LMS_BASE)
course_id= course_id, else:
lms_base = settings.LMS_BASE
lms_link = "//{lms_base}/courses/{course_id}/jump_to/{location}".format(
lms_base=lms_base,
course_id=course_id,
location=Location(location) location=Location(location)
) )
else: else:
......
...@@ -320,8 +320,11 @@ def edit_unit(request, location): ...@@ -320,8 +320,11 @@ def edit_unit(request, location):
break break
index = index + 1 index = index + 1
preview_lms_link = '//{preview}{lms_base}/courses/{org}/{course}/{course_name}/courseware/{section}/{subsection}/{index}'.format( preview_lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE',
preview='preview.', 'preview.' + settings.LMS_BASE)
preview_lms_link = '//{preview_lms_base}/courses/{org}/{course}/{course_name}/courseware/{section}/{subsection}/{index}'.format(
preview_lms_base=preview_lms_base,
lms_base=settings.LMS_BASE, lms_base=settings.LMS_BASE,
org=course.location.org, org=course.location.org,
course=course.location.course, course=course.location.course,
......
...@@ -172,6 +172,9 @@ LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identi ...@@ -172,6 +172,9 @@ LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identi
USE_I18N = True USE_I18N = True
USE_L10N = True USE_L10N = True
# Tracking
TRACK_MAX_EVENT = 10000
# Messages # Messages
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
...@@ -275,6 +278,10 @@ INSTALLED_APPS = ( ...@@ -275,6 +278,10 @@ INSTALLED_APPS = (
'auth', 'auth',
'student', # misleading name due to sharing with lms 'student', # misleading name due to sharing with lms
'course_groups', # not used in cms (yet), but tests run 'course_groups', # not used in cms (yet), but tests run
# tracking
'track',
# For asset pipelining # For asset pipelining
'pipeline', 'pipeline',
'staticfiles', 'staticfiles',
......
...@@ -97,7 +97,7 @@ CMS.Views.Settings.Details = CMS.Views.ValidatingView.extend({ ...@@ -97,7 +97,7 @@ CMS.Views.Settings.Details = CMS.Views.ValidatingView.extend({
} }
var newVal = new Date(date.getTime() + time * 1000); var newVal = new Date(date.getTime() + time * 1000);
if (!cacheModel.has(fieldName) || cacheModel.get(fieldName).getTime() !== newVal.getTime()) { if (!cacheModel.has(fieldName) || cacheModel.get(fieldName).getTime() !== newVal.getTime()) {
cacheModel.save(fieldName, newVal, { error: CMS.ServerError}); cacheModel.save(fieldName, newVal);
} }
} }
}; };
......
...@@ -90,8 +90,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ ...@@ -90,8 +90,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({
setGracePeriod : function(event) { setGracePeriod : function(event) {
event.data.clearValidationErrors(); event.data.clearValidationErrors();
var newVal = event.data.model.dateToGracePeriod($(event.currentTarget).timepicker('getTime')); var newVal = event.data.model.dateToGracePeriod($(event.currentTarget).timepicker('getTime'));
if (event.data.model.get('grace_period') != newVal) event.data.model.save('grace_period', newVal, if (event.data.model.get('grace_period') != newVal) event.data.model.save('grace_period', newVal);
{ error : CMS.ServerError});
}, },
updateModel : function(event) { updateModel : function(event) {
if (!this.selectorToField[event.currentTarget.id]) return; if (!this.selectorToField[event.currentTarget.id]) return;
...@@ -227,8 +226,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({ ...@@ -227,8 +226,7 @@ CMS.Views.Settings.Grading = CMS.Views.ValidatingView.extend({
object[cutoff['designation']] = cutoff['cutoff'] / 100.0; object[cutoff['designation']] = cutoff['cutoff'] / 100.0;
return object; return object;
}, },
{}), {}));
{ error : CMS.ServerError});
}, },
addNewGrade: function(e) { addNewGrade: function(e) {
......
<form class="choicegroup capa_inputtype" id="inputtype_${id}"> <form class="choicegroup capa_inputtype" id="inputtype_${id}">
<div class="indicator_container">
<fieldset>
% for choice_id, choice_description in choices:
<label for="input_${id}_${choice_id}">
% if choice_id in value:
<span class="indicator_container">
% if status == 'unsubmitted': % if status == 'unsubmitted':
<span class="unanswered" style="display:inline-block;" id="status_${id}"></span> <span class="unanswered" style="display:inline-block;" id="status_${id}"></span>
% elif status == 'correct': % elif status == 'correct':
...@@ -9,15 +15,21 @@ ...@@ -9,15 +15,21 @@
% elif status == 'incomplete': % elif status == 'incomplete':
<span class="incorrect" id="status_${id}"></span> <span class="incorrect" id="status_${id}"></span>
% endif % endif
</div> </span>
% else:
<span class="indicator_container">&#160;</span>
% endif
<fieldset> <input type="${input_type}" name="input_${id}${name_array_suffix}" id="input_${id}_${choice_id}" value="${choice_id}"
% for choice_id, choice_description in choices:
<label for="input_${id}_${choice_id}"> <input type="${input_type}" name="input_${id}${name_array_suffix}" id="input_${id}_${choice_id}" value="${choice_id}"
% if choice_id in value: % if choice_id in value:
checked="true" checked="true"
% endif % endif
/> ${choice_description} </label> />
${choice_description}
</label>
% endfor % endfor
<span id="answer_${id}"></span> <span id="answer_${id}"></span>
</fieldset> </fieldset>
......
...@@ -227,7 +227,7 @@ section.problem { ...@@ -227,7 +227,7 @@ section.problem {
background: url('../images/correct-icon.png') center center no-repeat; background: url('../images/correct-icon.png') center center no-repeat;
height: 20px; height: 20px;
position: relative; position: relative;
top: 6px; top: 3px;
width: 25px; width: 25px;
} }
...@@ -237,7 +237,7 @@ section.problem { ...@@ -237,7 +237,7 @@ section.problem {
height: 20px; height: 20px;
width: 20px; width: 20px;
position: relative; position: relative;
top: 6px; top: 3px;
} }
} }
......
...@@ -92,7 +92,7 @@ def clone_course(modulestore, contentstore, source_location, dest_location, dele ...@@ -92,7 +92,7 @@ def clone_course(modulestore, contentstore, source_location, dest_location, dele
return True return True
def delete_course(modulestore, contentstore, source_location): def delete_course(modulestore, contentstore, source_location, commit = False):
# first check to see if the modulestore is Mongo backed # first check to see if the modulestore is Mongo backed
if not isinstance(modulestore, MongoModuleStore): if not isinstance(modulestore, MongoModuleStore):
raise Exception("Expected a MongoModuleStore in the runtime. Aborting....") raise Exception("Expected a MongoModuleStore in the runtime. Aborting....")
...@@ -107,6 +107,7 @@ def delete_course(modulestore, contentstore, source_location): ...@@ -107,6 +107,7 @@ def delete_course(modulestore, contentstore, source_location):
thumb_loc = Location(thumb["_id"]) thumb_loc = Location(thumb["_id"])
id = StaticContent.get_id_from_location(thumb_loc) id = StaticContent.get_id_from_location(thumb_loc)
print "Deleting {0}...".format(id) print "Deleting {0}...".format(id)
if commit:
contentstore.delete(id) contentstore.delete(id)
# then delete all of the assets # then delete all of the assets
...@@ -115,6 +116,7 @@ def delete_course(modulestore, contentstore, source_location): ...@@ -115,6 +116,7 @@ def delete_course(modulestore, contentstore, source_location):
asset_loc = Location(asset["_id"]) asset_loc = Location(asset["_id"])
id = StaticContent.get_id_from_location(asset_loc) id = StaticContent.get_id_from_location(asset_loc)
print "Deleting {0}...".format(id) print "Deleting {0}...".format(id)
if commit:
contentstore.delete(id) contentstore.delete(id)
# then delete all course modules # then delete all course modules
...@@ -123,10 +125,12 @@ def delete_course(modulestore, contentstore, source_location): ...@@ -123,10 +125,12 @@ def delete_course(modulestore, contentstore, source_location):
for module in modules: for module in modules:
if module.category != 'course': # save deleting the course module for last if module.category != 'course': # save deleting the course module for last
print "Deleting {0}...".format(module.location) print "Deleting {0}...".format(module.location)
if commit:
modulestore.delete_item(module.location) modulestore.delete_item(module.location)
# finally delete the top-level course module itself # finally delete the top-level course module itself
print "Deleting {0}...".format(source_location) print "Deleting {0}...".format(source_location)
if commit:
modulestore.delete_item(source_location) modulestore.delete_item(source_location)
return True return True
...@@ -79,7 +79,7 @@ if Backbone? ...@@ -79,7 +79,7 @@ if Backbone?
#determined in the coffeescript based on whether or not there's a #determined in the coffeescript based on whether or not there's a
#group id #group id
if response.is_cohorted if response.is_cohorted and response.is_moderator
source = "script#_inline_discussion_cohorted" source = "script#_inline_discussion_cohorted"
else else
source = "script#_inline_discussion" source = "script#_inline_discussion"
......
...@@ -96,24 +96,25 @@ def create_thread(request, course_id, commentable_id): ...@@ -96,24 +96,25 @@ def create_thread(request, course_id, commentable_id):
#kevinchugh because the new requirement is that all groups will be determined #kevinchugh because the new requirement is that all groups will be determined
#by the group id in the request this all goes away #by the group id in the request this all goes away
#not anymore, only for admins
# Cohort the thread if the commentable is cohorted. # Cohort the thread if the commentable is cohorted.
#if is_commentable_cohorted(course_id, commentable_id): if is_commentable_cohorted(course_id, commentable_id):
# user_group_id = get_cohort_id(user, course_id) user_group_id = get_cohort_id(user, course_id)
# TODO (vshnayder): once we have more than just cohorts, we'll want to # TODO (vshnayder): once we have more than just cohorts, we'll want to
# change this to a single get_group_for_user_and_commentable function # change this to a single get_group_for_user_and_commentable function
# that can do different things depending on the commentable_id # that can do different things depending on the commentable_id
# if cached_has_permission(request.user, "see_all_cohorts", course_id): if cached_has_permission(request.user, "see_all_cohorts", course_id):
# admins can optionally choose what group to post as # admins can optionally choose what group to post as
# group_id = post.get('group_id', user_group_id) group_id = post.get('group_id', user_group_id)
# else: else:
# regular users always post with their own id. # regular users always post with their own id.
# group_id = user_group_id group_id = user_group_id
group_id = post.get('group_id')
if group_id: if group_id:
thread.update_attributes(group_id=group_id) thread.update_attributes(group_id=group_id)
log.debug("Saving thread %r", thread.attributes)
thread.save() thread.save()
if post.get('auto_subscribe', 'false').lower() == 'true': if post.get('auto_subscribe', 'false').lower() == 'true':
......
...@@ -133,6 +133,7 @@ def inline_discussion(request, course_id, discussion_id): ...@@ -133,6 +133,7 @@ def inline_discussion(request, course_id, discussion_id):
#if the commentable is cohorted, otherwise everything is not cohorted #if the commentable is cohorted, otherwise everything is not cohorted
#and no one has the option of choosing a cohort #and no one has the option of choosing a cohort
is_cohorted = is_course_cohorted(course_id) and is_commentable_cohorted(course_id, discussion_id) is_cohorted = is_course_cohorted(course_id) and is_commentable_cohorted(course_id, discussion_id)
is_moderator = cached_has_permission(request.user, "see_all_cohorts", course_id)
cohorts_list = list() cohorts_list = list()
...@@ -140,26 +141,16 @@ def inline_discussion(request, course_id, discussion_id): ...@@ -140,26 +141,16 @@ def inline_discussion(request, course_id, discussion_id):
cohorts_list.append({'name':'All Groups','id':None}) cohorts_list.append({'name':'All Groups','id':None})
#if you're a mod, send all cohorts and let you pick #if you're a mod, send all cohorts and let you pick
if cached_has_permission(request.user, "see_all_cohorts", course_id):
if is_moderator:
cohorts = get_course_cohorts(course_id) cohorts = get_course_cohorts(course_id)
for c in cohorts: for c in cohorts:
cohorts_list.append({'name':c.name, 'id':c.id}) cohorts_list.append({'name':c.name, 'id':c.id})
else: else:
#otherwise, just make a dictionary of two #students don't get to choose
user_cohort = get_cohort(cc_user, course_id)
if user_cohort:
user_cohort_name = user_cohort.name
user_cohort_id = user_cohort.id
else:
user_cohort_name = user_cohort_id = None
if user_cohort:
cohorts_list.append({'name':user_cohort_name, 'id':user_cohort_id})
else:
cohorts_list = None cohorts_list = None
return utils.JsonResponse({ return utils.JsonResponse({
'discussion_data': map(utils.safe_content, threads), 'discussion_data': map(utils.safe_content, threads),
'user_info': user_info, 'user_info': user_info,
...@@ -170,6 +161,7 @@ def inline_discussion(request, course_id, discussion_id): ...@@ -170,6 +161,7 @@ def inline_discussion(request, course_id, discussion_id):
'allow_anonymous_to_peers': allow_anonymous_to_peers, 'allow_anonymous_to_peers': allow_anonymous_to_peers,
'allow_anonymous': allow_anonymous, 'allow_anonymous': allow_anonymous,
'cohorts': cohorts_list, 'cohorts': cohorts_list,
'is_moderator': is_moderator,
'is_cohorted': is_cohorted 'is_cohorted': is_cohorted
}) })
......
...@@ -46,21 +46,18 @@ ...@@ -46,21 +46,18 @@
%elif course.metadata.get("allow_anonymous_to_peers", False): %elif course.metadata.get("allow_anonymous_to_peers", False):
<input type="checkbox" name="anonymous_to_peers" class="discussion-anonymous-to-peers" id="new-post-anonymous-to-peers"><label for="new-post-anonymous-to-peers">post anonymously to classmates</label> <input type="checkbox" name="anonymous_to_peers" class="discussion-anonymous-to-peers" id="new-post-anonymous-to-peers"><label for="new-post-anonymous-to-peers">post anonymously to classmates</label>
%endif %endif
%if is_course_cohorted: %if is_course_cohorted and is_moderator:
<div class="form-group-label choose-cohort"> <div class="form-group-label choose-cohort">
Make visible to: Make visible to:
<select class="group-filter-select new-post-group" name = "group_id"> <select class="group-filter-select new-post-group" name = "group_id">
<option value="">All Groups</option> <option value="">All Groups</option>
%if is_moderator:
%for c in cohorts: %for c in cohorts:
<option value="${c.id}">${c.name}</option> <option value="${c.id}"
%endfor %if user_cohort and str(user_cohort) == str(c.id):
%else: selected
%if user_cohort:
<option value="${user_cohort}">My Cohort</option>
%endif
%endif %endif
>${c.name}</option>
%endfor
</select> </select>
</div> </div>
%endif %endif
......
...@@ -415,7 +415,10 @@ end ...@@ -415,7 +415,10 @@ end
namespace :cms do namespace :cms do
desc "Delete existing MongoDB based course" desc "Delete existing MongoDB based course"
task :delete_course do task :delete_course do
if ENV['LOC']
if ENV['LOC'] and ENV['COMMIT']
sh(django_admin(:cms, :dev, :delete_course, ENV['LOC'], ENV['COMMIT']))
elsif ENV['LOC']
sh(django_admin(:cms, :dev, :delete_course, ENV['LOC'])) sh(django_admin(:cms, :dev, :delete_course, ENV['LOC']))
else else
raise "You must pass in a LOC parameter" raise "You must pass in a LOC parameter"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment