Commit 16bd2372 by Kevin Kim

Convert ORA dates to user's preferred time zone.

parent 9a1f72f0
......@@ -17,12 +17,12 @@
{% if peer_start %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with start_date=peer_start|utc|date:"N j, Y H:i e" time_until=peer_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with start_date=peer_start|timezone:time_zone|date:"N j, Y H:i e" time_until=peer_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% elif peer_due %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with due_date=peer_due|utc|date:"N j, Y H:i e" time_until=peer_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with due_date=peer_due|timezone:time_zone|date:"N j, Y H:i e" time_until=peer_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% endif %}
</span>
......
......@@ -13,12 +13,12 @@
{% if submission_start %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with start_date=submission_start|utc|date:"N j, Y H:i e" time_until=submission_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with start_date=submission_start|timezone:time_zone|date:"N j, Y H:i e" time_until=submission_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% elif submission_due %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with due_date=submission_due|utc|date:"N j, Y H:i e" time_until=submission_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with due_date=submission_due|timezone:time_zone|date:"N j, Y H:i e" time_until=submission_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% endif %}
</span>
......
......@@ -13,12 +13,12 @@
{% if self_start %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with start_date=self_start|utc|date:"N j, Y H:i e" time_until=self_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with start_date=self_start|timezone:time_zone|date:"N j, Y H:i e" time_until=self_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% elif self_due %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with due_date=self_due|utc|date:"N j, Y H:i e" time_until=self_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with due_date=self_due|timezone:time_zone|date:"N j, Y H:i e" time_until=self_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% endif %}
</span>
......
......@@ -13,12 +13,12 @@
{% if training_start %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with start_date=training_start|utc|date:"N j, Y H:i e" time_until=training_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with start_date=training_start|timezone:time_zone|date:"N j, Y H:i e" time_until=training_start|timeuntil %}available <span class="date">{{ start_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
{% elif training_due %}
<span class="step__deadline">
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 (in 5 days and 45 minutes)" #}
{% blocktrans with due_date=training_due|utc|date:"N j, Y H:i e" time_until=training_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
{% blocktrans with due_date=training_due|timezone:time_zone|date:"N j, Y H:i e" time_until=training_due|timeuntil %}due <span class="date">{{ due_date }} (in {{ time_until }})</span>{% endblocktrans %}
</span>
</span>
{% endif %}
......
......@@ -7,11 +7,10 @@ from openassessment.assessment.api import peer as peer_api
from openassessment.assessment.errors import (
PeerAssessmentRequestError, PeerAssessmentInternalError, PeerAssessmentWorkflowError
)
from openassessment.workflow import api as workflow_api
from openassessment.workflow.errors import AssessmentWorkflowError
from openassessment.xblock.defaults import DEFAULT_RUBRIC_FEEDBACK_TEXT
from .data_conversion import create_rubric_dict
from .resolve_dates import DISTANT_FUTURE
from .resolve_dates import DISTANT_FUTURE, get_current_time_zone
from .data_conversion import clean_criterion_feedback, create_submission_dict, verify_assessment_parameters
logger = logging.getLogger(__name__)
......@@ -162,10 +161,12 @@ class PeerAssessmentMixin(object):
path = 'openassessmentblock/peer/oa_peer_unavailable.html'
finished = False
problem_closed, reason, start_date, due_date = self.is_closed(step="peer-assessment")
user_service = self.runtime.service(self, 'user')
context_dict = {
"rubric_criteria": self.rubric_criteria_with_labels,
"allow_latex": self.allow_latex,
"time_zone": get_current_time_zone(user_service),
}
if self.rubric_feedback_prompt is not None:
......
......@@ -24,6 +24,18 @@ DISTANT_PAST = dt.datetime(dt.MINYEAR, 1, 1, tzinfo=pytz.utc)
DISTANT_FUTURE = dt.datetime(dt.MAXYEAR, 1, 1, tzinfo=pytz.utc)
def get_current_time_zone(user_service):
"""
Returns the preferred time zone for the current user, if specified, or UTC if not
:param user_service: XblockUserService
"""
user_preferences = user_service.get_current_user().opt_attrs.get('edx-platform.user_preferences')
if user_preferences is None:
return pytz.utc
return pytz.timezone(user_preferences.get('time_zone', 'utc'))
def _parse_date(value, _):
"""
Parse an ISO formatted datestring into a datetime object with timezone set to UTC.
......@@ -46,7 +58,11 @@ def _parse_date(value, _):
try:
return parse_date(value).replace(tzinfo=pytz.utc)
except ValueError:
raise InvalidDateFormat(_("'{date}' is an invalid date format. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.").format(date=value))
raise InvalidDateFormat(
_("'{date}' is an invalid date format. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.").format(
date=value
)
)
else:
raise InvalidDateFormat(_("'{date}' must be a date string or datetime").format(date=value))
......@@ -201,8 +217,11 @@ def resolve_dates(start, end, date_ranges, _):
step_end = _parse_date(step_end, _) if step_end is not None else prev_end
if step_start < prev_start:
msg = _(u"This step's start date '{start}' cannot be earlier than the previous step's start date '{prev}'.").format(
start=step_start, prev=prev_start
msg = _(
u"This step's start date '{start}' cannot be earlier than the previous step's start date '{prev}'."
).format(
start=step_start,
prev=prev_start,
)
raise DateValidationError(msg)
......
......@@ -6,7 +6,7 @@ from webob import Response
from openassessment.assessment.api import self as self_api
from openassessment.workflow import api as workflow_api
from submissions import api as submission_api
from .resolve_dates import DISTANT_FUTURE
from .resolve_dates import DISTANT_FUTURE, get_current_time_zone
from .data_conversion import (clean_criterion_feedback, create_submission_dict,
create_rubric_dict, verify_assessment_parameters)
......@@ -51,9 +51,14 @@ class SelfAssessmentMixin(object):
SubmissionError: Error occurred while retrieving the current submission.
SelfAssessmentRequestError: Error occurred while checking if we had a self-assessment.
"""
context = {'allow_latex': self.allow_latex}
path = 'openassessmentblock/self/oa_self_unavailable.html'
problem_closed, reason, start_date, due_date = self.is_closed(step="self-assessment")
user_service = self.runtime.service(self, 'user')
context = {
'allow_latex': self.allow_latex,
'time_zone': get_current_time_zone(user_service)
}
# We display the due date whether the problem is open or closed.
# If no date is set, it defaults to the distant future, in which
......@@ -121,7 +126,10 @@ class SelfAssessmentMixin(object):
"""
if self.submission_uuid is None:
return {'success': False, 'msg': self._(u"You must submit a response before you can perform a self-assessment.")}
return {
'success': False,
'msg': self._(u"You must submit a response before you can perform a self-assessment.")
}
try:
assessment = self_api.create_assessment(
......
if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}if(typeof window.ngetgext==="undefined"){window.ngettext=function(singularText,pluralText,n){if(n>1){return pluralText}else{return singularText}}}if(typeof window.Logger==="undefined"){window.Logger={log:function(){}}}if(typeof window.MathJax==="undefined"){window.MathJax={Hub:{Typeset:function(){},Queue:function(){}}}}if(typeof OpenAssessment.Server==="undefined"||!OpenAssessment.Server){OpenAssessment.Server=function(runtime,element){this.runtime=runtime;this.element=element};var jsonContentType="application/json; charset=utf-8";OpenAssessment.Server.prototype={url:function(handler){return this.runtime.handlerUrl(this.element,handler)},render:function(component){var view=this;var url=this.url("render_"+component);return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(view,[data])}).fail(function(){defer.rejectWith(view,[gettext("This section could not be loaded.")])})}).promise()},renderLatex:function(element){element.filter(".allow--latex").each(function(){MathJax.Hub.Queue(["Typeset",MathJax.Hub,this])})},renderContinuedPeer:function(){var view=this;var url=this.url("render_peer_assessment");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:{continue_grading:true}}).done(function(data){defer.resolveWith(view,[data])}).fail(function(){defer.rejectWith(view,[gettext("This section could not be loaded.")])})}).promise()},studentInfo:function(studentUsername,options){var url=this.url("render_student_info");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:_.extend({student_username:studentUsername},options)}).done(function(data){defer.resolveWith(this,[data])}).fail(function(){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},staffGradeForm:function(){var url=this.url("render_staff_grade_form");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(this,[data])}).fail(function(){defer.rejectWith(this,[gettext("The staff assessment form could not be loaded.")])})}).promise()},staffGradeCounts:function(){var url=this.url("render_staff_grade_counts");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(this,[data])}).fail(function(){defer.rejectWith(this,[gettext("The display of ungraded and checked out responses could not be loaded.")])})}).promise()},submit:function(submission){var url=this.url("submit");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({submission:submission}),contentType:jsonContentType}).done(function(data){var success=data[0];if(success){var studentId=data[1];var attemptNum=data[2];defer.resolveWith(this,[studentId,attemptNum])}else{var errorNum=data[1];var errorMsg=data[2];defer.rejectWith(this,[errorNum,errorMsg])}}).fail(function(){defer.rejectWith(this,["AJAX",gettext("This response could not be submitted.")])})}).promise()},save:function(submission){var url=this.url("save_submission");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({submission:submission}),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This response could not be saved.")])})}).promise()},submitFeedbackOnAssessment:function(text,options){var url=this.url("submit_feedback");var payload=JSON.stringify({feedback_text:text,feedback_options:options});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This feedback could not be submitted.")])})}).promise()},submitAssessment:function(assessmentType,payload){var url=this.url(assessmentType);return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify(payload),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})}).promise()},peerAssess:function(optionsSelected,criterionFeedback,overallFeedback,submissionID){return this.submitAssessment("peer_assess",{options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback,submission_uuid:submissionID})},selfAssess:function(optionsSelected,criterionFeedback,overallFeedback){return this.submitAssessment("self_assess",{options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback})},staffAssess:function(optionsSelected,criterionFeedback,overallFeedback,submissionID,assessType){return this.submitAssessment("staff_assess",{options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback,submission_uuid:submissionID,assess_type:assessType})},trainingAssess:function(optionsSelected){var url=this.url("training_assess");var payload=JSON.stringify({options_selected:optionsSelected});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.corrections])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},scheduleTraining:function(){var url=this.url("schedule_training");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""',contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},rescheduleUnfinishedTasks:function(){var url=this.url("reschedule_unfinished_tasks");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""',contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("One or more rescheduling tasks failed.")])})})},updateEditorContext:function(options){var url=this.url("update_editor_context");var payload=JSON.stringify({prompts:options.prompts,feedback_prompt:options.feedbackPrompt,feedback_default_text:options.feedback_default_text,title:options.title,submission_start:options.submissionStart,submission_due:options.submissionDue,criteria:options.criteria,assessments:options.assessments,editor_assessments_order:options.editorAssessmentsOrder,file_upload_type:options.fileUploadType,white_listed_file_types:options.fileTypeWhiteList,allow_latex:options.latexEnabled,leaderboard_show:options.leaderboardNum});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This problem could not be saved.")])})}).promise()},checkReleased:function(){var url=this.url("check_released");var payload='""';return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.is_released])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("The server could not be contacted.")])})}).promise()},getUploadUrl:function(contentType,filename){var url=this.url("upload_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({contentType:contentType,filename:filename}),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("Could not retrieve upload url.")])})}).promise()},getDownloadUrl:function(){var url=this.url("download_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({}),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("Could not retrieve download url.")])})}).promise()},cancelSubmission:function(submissionID,comments){var url=this.url("cancel_submission");var payload=JSON.stringify({submission_uuid:submissionID,comments:comments});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("The submission could not be removed from the grading pool.")])})}).promise()},publishEvent:function(eventName,eventData){eventData.event_name=eventName;var url=this.url("publish_event");var payload=JSON.stringify(eventData);$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType})}}}if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}if(typeof window.ngetgext==="undefined"){window.ngettext=function(singularText,pluralText,n){if(n>1){return pluralText}else{return singularText}}}if(typeof window.Logger==="undefined"){window.Logger={log:function(){}}}if(typeof window.MathJax==="undefined"){window.MathJax={Hub:{Typeset:function(){},Queue:function(){}}}}OpenAssessment.BaseView=function(runtime,element,server,data){this.runtime=runtime;this.element=element;this.server=server;this.fileUploader=new OpenAssessment.FileUploader;this.responseView=new OpenAssessment.ResponseView(this.element,this.server,this.fileUploader,this,data);this.trainingView=new OpenAssessment.StudentTrainingView(this.element,this.server,this);this.selfView=new OpenAssessment.SelfView(this.element,this.server,this);this.peerView=new OpenAssessment.PeerView(this.element,this.server,this);this.staffView=new OpenAssessment.StaffView(this.element,this.server,this);this.gradeView=new OpenAssessment.GradeView(this.element,this.server,this);this.leaderboardView=new OpenAssessment.LeaderboardView(this.element,this.server,this);this.messageView=new OpenAssessment.MessageView(this.element,this.server,this);this.staffAreaView=new OpenAssessment.StaffAreaView(this.element,this.server,this);this.usageID=""};if(typeof OpenAssessment.unsavedChanges==="undefined"||!OpenAssessment.unsavedChanges){OpenAssessment.unsavedChanges={}}OpenAssessment.clearUnsavedChanges=function(){OpenAssessment.unsavedChanges={};window.onbeforeunload=null};OpenAssessment.BaseView.prototype={scrollToTop:function(selector){if(!selector){selector="#openassessment__steps"}if($.scrollTo instanceof Function){$(window).scrollTo($(selector,this.element),800,{offset:-50})}},setUpCollapseExpand:function(parentElement){parentElement.on("click",".ui-toggle-visibility__control",function(eventData){var sel=$(eventData.target).closest(".ui-toggle-visibility");sel.toggleClass("is--collapsed")})},getUsageID:function(){if(!this.usageID){this.usageID=$(this.element).data("usage-id")}return this.usageID},load:function(){this.responseView.load();this.loadAssessmentModules();this.staffAreaView.load()},loadAssessmentModules:function(){this.trainingView.load();this.peerView.load();this.staffView.load();this.selfView.load();this.gradeView.load();this.leaderboardView.load()},loadMessageView:function(){this.messageView.load()},toggleActionError:function(type,message){var element=this.element;var container=null;if(type==="save"){container=".response__submission__actions"}else if(type==="submit"||type==="peer"||type==="self"||type==="student-training"){container=".step__actions"}else if(type==="feedback_assess"){container=".submission__feedback__actions"}else if(type==="upload"){container="#upload__error"}if(container===null){if(message!==null){console.log(message)}}else{$(container+" .message__content",element).html("<p>"+(message?_.escape(message):"")+"</p>");$(container,element).toggleClass("has--error",message!==null)}},showLoadError:function(stepName,errorMessage){if(!errorMessage){errorMessage=gettext("Unable to load")}var $container=$("#openassessment__"+stepName);$container.toggleClass("has--error",true);$container.find(".step__status__value i").removeClass().addClass("icon fa fa-exclamation-triangle");$container.find(".step__status__value .copy").html(_.escape(errorMessage))},unsavedWarningEnabled:function(enabled,key,message){if(typeof enabled==="undefined"){return window.onbeforeunload!==null}else{var usageID=$(this.element).data("usage-id");if(enabled){if(typeof OpenAssessment.unsavedChanges[usageID]==="undefined"||!OpenAssessment.unsavedChanges[usageID]){OpenAssessment.unsavedChanges[usageID]={}}OpenAssessment.unsavedChanges[usageID][key]=message;window.onbeforeunload=function(){for(var xblockUsageID in OpenAssessment.unsavedChanges){if(OpenAssessment.unsavedChanges.hasOwnProperty(xblockUsageID)){for(var key in OpenAssessment.unsavedChanges[xblockUsageID]){if(OpenAssessment.unsavedChanges[xblockUsageID].hasOwnProperty(key)){return OpenAssessment.unsavedChanges[xblockUsageID][key]}}}}}}else{if(typeof OpenAssessment.unsavedChanges[usageID]!=="undefined"){delete OpenAssessment.unsavedChanges[usageID][key];if($.isEmptyObject(OpenAssessment.unsavedChanges[usageID])){delete OpenAssessment.unsavedChanges[usageID]}if($.isEmptyObject(OpenAssessment.unsavedChanges)){window.onbeforeunload=null}}}}}};function OpenAssessmentBlock(runtime,element,data){var server=new OpenAssessment.Server(runtime,element);var view=new OpenAssessment.BaseView(runtime,element,server,data);view.load()}OpenAssessment.FileUploader=function(){this.upload=function(url,file){return $.Deferred(function(defer){$.ajax({url:url,type:"PUT",data:file,async:false,processData:false,contentType:file.type}).done(function(){Logger.log("openassessment.upload_file",{fileName:file.name,fileSize:file.size,fileType:file.type});defer.resolve()}).fail(function(data,textStatus){defer.rejectWith(this,[textStatus])})}).promise()}};OpenAssessment.GradeView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.GradeView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("grade").done(function(html){$("#openassessment__grade",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__grade",view.element));view.installHandlers()}).fail(function(errMsg){baseView.showLoadError("grade",errMsg)})},installHandlers:function(){var sel=$("#openassessment__grade",this.element);this.baseView.setUpCollapseExpand(sel);var view=this;sel.find(".feedback__submit").click(function(eventObject){eventObject.preventDefault();view.submitFeedbackOnAssessment()})},feedbackText:function(text){if(typeof text==="undefined"){return $("#feedback__remarks__value",this.element).val()}else{$("#feedback__remarks__value",this.element).val(text)}},feedbackOptions:function(options){var view=this;if(typeof options==="undefined"){return $.map($(".feedback__overall__value:checked",view.element),function(element){return $(element).val()})}else{$(".feedback__overall__value",this.element).prop("checked",false);$.each(options,function(index,opt){$("#feedback__overall__value--"+opt,view.element).prop("checked",true)})}},setHidden:function(selector,hidden){selector.toggleClass("is--hidden",hidden);selector.attr("aria-hidden",hidden?"true":"false")},isHidden:function(selector){return selector.hasClass("is--hidden")&&selector.attr("aria-hidden")==="true"},feedbackState:function(newState){var containerSel=$(".submission__feedback__content",this.element);var instructionsSel=containerSel.find(".submission__feedback__instructions");var fieldsSel=containerSel.find(".submission__feedback__fields");var actionsSel=containerSel.find(".submission__feedback__actions");var transitionSel=containerSel.find(".transition__status");var messageSel=containerSel.find(".message--complete");if(typeof newState==="undefined"){var isSubmitting=containerSel.hasClass("is--transitioning")&&containerSel.hasClass("is--submitting")&&!this.isHidden(transitionSel)&&this.isHidden(messageSel)&&this.isHidden(instructionsSel)&&this.isHidden(fieldsSel)&&this.isHidden(actionsSel);var hasSubmitted=containerSel.hasClass("is--submitted")&&this.isHidden(transitionSel)&&!this.isHidden(messageSel)&&this.isHidden(instructionsSel)&&this.isHidden(fieldsSel)&&this.isHidden(actionsSel);var isOpen=!containerSel.hasClass("is--submitted")&&!containerSel.hasClass("is--transitioning")&&!containerSel.hasClass("is--submitting")&&this.isHidden(transitionSel)&&this.isHidden(messageSel)&&!this.isHidden(instructionsSel)&&!this.isHidden(fieldsSel)&&!this.isHidden(actionsSel);if(isOpen){return"open"}else if(isSubmitting){return"submitting"}else if(hasSubmitted){return"submitted"}else{throw"Invalid feedback state"}}else{if(newState==="open"){containerSel.toggleClass("is--transitioning",false);containerSel.toggleClass("is--submitting",false);containerSel.toggleClass("is--submitted",false);this.setHidden(instructionsSel,false);this.setHidden(fieldsSel,false);this.setHidden(actionsSel,false);this.setHidden(transitionSel,true);this.setHidden(messageSel,true)}else if(newState==="submitting"){containerSel.toggleClass("is--transitioning",true);containerSel.toggleClass("is--submitting",true);containerSel.toggleClass("is--submitted",false);this.setHidden(instructionsSel,true);this.setHidden(fieldsSel,true);this.setHidden(actionsSel,true);this.setHidden(transitionSel,false);this.setHidden(messageSel,true)}else if(newState==="submitted"){containerSel.toggleClass("is--transitioning",false);containerSel.toggleClass("is--submitting",false);containerSel.toggleClass("is--submitted",true);this.setHidden(instructionsSel,true);this.setHidden(fieldsSel,true);this.setHidden(actionsSel,true);this.setHidden(transitionSel,true);this.setHidden(messageSel,false)}}},submitFeedbackOnAssessment:function(){var view=this;var baseView=this.baseView;$(".feedback__submit",this.element).toggleClass("is--disabled",true);view.feedbackState("submitting");this.server.submitFeedbackOnAssessment(this.feedbackText(),this.feedbackOptions()).done(function(){view.feedbackState("submitted")}).fail(function(errMsg){baseView.toggleActionError("feedback_assess",errMsg)})}};OpenAssessment.LeaderboardView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.LeaderboardView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("leaderboard").done(function(html){$("#openassessment__leaderboard",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__leaderboard",view.element))}).fail(function(errMsg){baseView.showLoadError("leaderboard",errMsg)})}};OpenAssessment.MessageView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.MessageView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("message").done(function(html){$("#openassessment__message",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__message",view.element))}).fail(function(errMsg){baseView.showLoadError("message",errMsg)})}};OpenAssessment.PeerView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.PeerView.prototype={UNSAVED_WARNING_KEY:"peer-assessment",load:function(){var view=this;this.server.render("peer_assessment").done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__peer-assessment",view.element));view.installHandlers(false)}).fail(function(){view.baseView.showLoadError("peer-assessment")});view.baseView.loadMessageView()},loadContinuedAssessment:function(){var view=this;view.continueAssessmentEnabled(false);this.server.renderContinuedPeer().done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__peer-assessment",view.element));view.installHandlers(true)}).fail(function(){view.baseView.showLoadError("peer-assessment");view.continueAssessmentEnabled(true)})},continueAssessmentEnabled:function(enabled){var button=$(".action--continue--grading",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},installHandlers:function(isContinuedAssessment){var sel=$("#openassessment__peer-assessment",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#peer-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}else{this.rubric=null}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(view.peerSubmitEnabled,view));this.rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view))}sel.find("#peer-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();if(!isContinuedAssessment){view.peerAssess()}else{view.continuedPeerAssess()}});sel.find(".action--continue--grading").click(function(eventObject){eventObject.preventDefault();view.loadContinuedAssessment()})},peerSubmitEnabled:function(enabled){var button=$("#peer-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without submitting your peer assessment, you will lose any work you have done."))}},peerAssess:function(){var view=this;var baseView=view.baseView;this.peerAssessRequest(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);baseView.loadAssessmentModules();baseView.scrollToTop()})},continuedPeerAssess:function(){var view=this;var gradeView=this.baseView.gradeView;var baseView=view.baseView;view.peerAssessRequest(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);view.loadContinuedAssessment();gradeView.load();baseView.scrollToTop()})},peerAssessRequest:function(successFunction){var view=this;var uuid=this.getUUID();view.baseView.toggleActionError("peer",null);view.peerSubmitEnabled(false);this.server.peerAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.rubric.overallFeedback(),uuid).done(successFunction).fail(function(errMsg){view.baseView.toggleActionError("peer",errMsg);view.peerSubmitEnabled(true)})},getUUID:function(){var xBlockElement=$("div[data-usage-id='"+this.baseView.getUsageID()+"']");return xBlockElement.find("#openassessment__peer-assessment").data("submission-uuid")}};OpenAssessment.ResponseView=function(element,server,fileUploader,baseView,data){this.element=element;this.server=server;this.fileUploader=fileUploader;this.baseView=baseView;this.savedResponse=[];this.files=null;this.fileType=null;this.lastChangeTime=Date.now();this.errorOnLastSave=false;this.autoSaveTimerId=null;this.data=data;this.fileUploaded=false};OpenAssessment.ResponseView.prototype={AUTO_SAVE_POLL_INTERVAL:2e3,AUTO_SAVE_WAIT:3e4,MAX_FILE_SIZE:5242880,UNSAVED_WARNING_KEY:"learner-response",load:function(){var view=this;this.server.render("submission").done(function(html){$("#openassessment__response",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__response",view.element));view.installHandlers();view.setAutoSaveEnabled(true)}).fail(function(){view.baseView.showLoadError("response")})},installHandlers:function(){var sel=$("#openassessment__response",this.element);var view=this;var uploadType="";if(sel.find(".submission__answer__display__file").length){uploadType=sel.find(".submission__answer__display__file").data("upload-type")}this.baseView.setUpCollapseExpand(sel);this.savedResponse=this.response();var handleChange=function(){view.handleResponseChanged()};sel.find(".submission__answer__part__text__value").on("change keyup drop paste",handleChange);var handlePrepareUpload=function(eventData){view.prepareUpload(eventData.target.files,uploadType)};sel.find("input[type=file]").on("change",handlePrepareUpload);sel.find("#submission__preview__item").hide();sel.find("#step--response__submit").click(function(eventObject){eventObject.preventDefault();view.submit()});sel.find("#submission__save").click(function(eventObject){eventObject.preventDefault();view.save()});sel.find("#submission__preview").click(function(eventObject){eventObject.preventDefault();var previewText=sel.find(".submission__answer__part__text__value").val();var previewContainer=sel.find("#preview_content");previewContainer.html(previewText.replace(/\r\n|\r|\n/g,"<br />"));sel.find("#submission__preview__item").show();MathJax.Hub.Queue(["Typeset",MathJax.Hub,previewContainer[0]])});sel.find("#file__upload").click(function(eventObject){eventObject.preventDefault();$(".submission__answer__display__file",view.element).removeClass("is--hidden");view.fileUpload()})},setAutoSaveEnabled:function(enabled){if(enabled){if(this.autoSaveTimerId===null){this.autoSaveTimerId=setInterval($.proxy(this.autoSave,this),this.AUTO_SAVE_POLL_INTERVAL)}}else{if(this.autoSaveTimerId!==null){clearInterval(this.autoSaveTimerId)}}},submitEnabled:function(enabled){var sel=$("#step--response__submit",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled);return enabled}},saveEnabled:function(enabled){var sel=$("#submission__save",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},previewEnabled:function(enabled){var sel=$("#submission__preview",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},saveStatus:function(msg){var sel=$("#response__save_status",this.element);if(typeof msg==="undefined"){return sel.text()}else{var label=gettext("Status of Your Response");sel.html('<span class="sr">'+_.escape(label)+":"+"</span>\n"+msg)}},response:function(texts){var sel=$(".response__submission .submission__answer__part__text__value",this.element);if(typeof texts==="undefined"){return sel.map(function(){return $.trim($(this).val())}).get()}else{sel.map(function(index){$(this).val(texts[index])})}},responseChanged:function(){var savedResponse=this.savedResponse;return this.response().some(function(element,index){return element!==savedResponse[index]})},autoSave:function(){var timeSinceLastChange=Date.now()-this.lastChangeTime;if(this.responseChanged()&&timeSinceLastChange>this.AUTO_SAVE_WAIT&&!this.errorOnLastSave){this.save()}},handleResponseChanged:function(){var isNotBlank=!this.response().every(function(element){return $.trim(element)===""});this.submitEnabled(isNotBlank);if(this.responseChanged()){this.saveEnabled(isNotBlank);this.previewEnabled(isNotBlank);this.saveStatus(gettext("This response has not been saved."));this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without saving or submitting your response, you will lose any work you have done on the response."))}this.lastChangeTime=Date.now()},save:function(){this.errorOnLastSave=false;this.saveStatus(gettext("Saving..."));this.baseView.toggleActionError("save",null);this.baseView.unsavedWarningEnabled(false,this.UNSAVED_WARNING_KEY);var view=this;var savedResponse=this.response();this.server.save(savedResponse).done(function(){view.savedResponse=savedResponse;var currentResponse=view.response();var currentResponseIsEmpty=currentResponse.every(function(element){return element===""});view.submitEnabled(!currentResponseIsEmpty);var currentResponseEqualsSaved=currentResponse.every(function(element,index){return element===savedResponse[index]});if(currentResponseEqualsSaved){view.saveEnabled(false);view.saveStatus(gettext("This response has been saved but not submitted."))}}).fail(function(errMsg){view.saveStatus(gettext("Error"));view.baseView.toggleActionError("save",errMsg);view.errorOnLastSave=true})},submit:function(){this.submitEnabled(false);var view=this;var baseView=this.baseView;var fileDefer=$.Deferred();if(view.files!==null&&!view.fileUploaded){var msg=gettext("Do you want to upload your file before submitting?");if(confirm(msg)){fileDefer=view.fileUpload()}else{view.submitEnabled(true);return}}else{fileDefer.resolve()}fileDefer.pipe(function(){return view.confirmSubmission().pipe(function(){var submission=view.response();baseView.toggleActionError("response",null);return view.server.submit(submission)})}).done($.proxy(view.moveToNextStep,view)).fail(function(errCode,errMsg){if(errCode==="ENOMULTI"){view.moveToNextStep()}else{if(errMsg){baseView.toggleActionError("submit",errMsg)}view.submitEnabled(true)}})},moveToNextStep:function(){this.load();this.baseView.loadAssessmentModules();this.baseView.unsavedWarningEnabled(false,this.UNSAVED_WARNING_KEY)},confirmSubmission:function(){var msg=gettext("You're about to submit your response for this assignment. After you submit this response, you can't change it or submit a new response.");return $.Deferred(function(defer){if(confirm(msg)){defer.resolve()}else{defer.reject()}})},prepareUpload:function(files,uploadType){this.files=null;this.fileType=files[0].type;var ext=files[0].name.split(".").pop().toLowerCase();if(files[0].size>this.MAX_FILE_SIZE){this.baseView.toggleActionError("upload",gettext("File size must be 5MB or less."))}else if(uploadType==="image"&&this.data.ALLOWED_IMAGE_MIME_TYPES.indexOf(this.fileType)===-1){this.baseView.toggleActionError("upload",gettext("You can upload files with these file types: ")+"JPG, PNG or GIF")}else if(uploadType==="pdf-and-image"&&this.data.ALLOWED_FILE_MIME_TYPES.indexOf(this.fileType)===-1){this.baseView.toggleActionError("upload",gettext("You can upload files with these file types: ")+"JPG, PNG, GIF or PDF")}else if(uploadType==="custom"&&this.data.FILE_TYPE_WHITE_LIST.indexOf(ext)===-1){this.baseView.toggleActionError("upload",gettext("You can upload files with these file types: ")+this.data.FILE_TYPE_WHITE_LIST.join(", "))}else if(this.data.FILE_EXT_BLACK_LIST.indexOf(ext)!==-1){this.baseView.toggleActionError("upload",gettext("File type is not allowed."))}else{this.baseView.toggleActionError("upload",null);this.files=files}$("#file__upload").toggleClass("is--disabled",this.files===null)},fileUpload:function(){var view=this;var fileUpload=$("#file__upload");fileUpload.addClass("is--disabled");var handleError=function(errMsg){view.baseView.toggleActionError("upload",errMsg);fileUpload.removeClass("is--disabled")};return this.server.getUploadUrl(view.fileType,view.files[0].name).done(function(url){var file=view.files[0];view.fileUploader.upload(url,file).done(function(){view.fileUrl();view.baseView.toggleActionError("upload",null);view.fileUploaded=true}).fail(handleError)}).fail(handleError)},fileUrl:function(){var view=this;var file=$("#submission__answer__file",view.element);view.server.getDownloadUrl().done(function(url){if(file.prop("tagName")==="IMG"){file.attr("src",url)}else{file.attr("href",url)}return url})}};OpenAssessment.Rubric=function(element){this.element=element};OpenAssessment.Rubric.prototype={criterionFeedback:function(criterionFeedback){var selector="textarea.answer__value";var feedback={};var rubric=this;$(selector,this.element).each(function(index,sel){var criterionName=rubric.getCriterionName(sel);
if(typeof criterionFeedback!=="undefined"){$(sel).val(criterionFeedback[criterionName]);feedback[criterionName]=criterionFeedback[criterionName]}else{feedback[criterionName]=$(sel).val()}});return feedback},overallFeedback:function(overallFeedback){var selector=".assessment__rubric__question--feedback__value";if(typeof overallFeedback==="undefined"){return $(selector,this.element).val()}else{$(selector,this.element).val(overallFeedback)}},optionsSelected:function(optionsSelected){var selector="input[type=radio]";var rubric=this;if(typeof optionsSelected==="undefined"){var options={};$(selector+":checked",this.element).each(function(index,sel){options[rubric.getCriterionName(sel)]=sel.value});return options}else{$(selector,this.element).prop("checked",false);$(selector,this.element).each(function(index,sel){var criterionName=rubric.getCriterionName(sel);if(optionsSelected.hasOwnProperty(criterionName)){if(sel.value===optionsSelected[criterionName]){$(sel).prop("checked",true)}}})}},canSubmitCallback:function(callback){var rubric=this;callback(rubric.canSubmit());$(this.element).on("change keyup drop paste",function(){callback(rubric.canSubmit())})},canSubmit:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var numAvailable=$(".field--radio.assessment__rubric__question.has--options",this.element).length;var completedRequiredComments=true;$("textarea[required]",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText===""){completedRequiredComments=false}});return numChecked===numAvailable&&completedRequiredComments},changesExistCallback:function(callback){var rubric=this;callback(rubric.changesExist());$(this.element).on("change keyup drop paste",function(){callback(rubric.changesExist())})},changesExist:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var textExists=false;$("textarea",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText!==""){textExists=true}});return numChecked>0||textExists},showCorrections:function(corrections){var selector="input[type=radio]";var hasErrors=false;var rubric=this;$(selector,this.element).each(function(index,sel){var listItem=$(sel).parents(".assessment__rubric__question");if(corrections.hasOwnProperty(rubric.getCriterionName(sel))){hasErrors=true;listItem.find(".message--incorrect").removeClass("is--hidden");listItem.find(".message--correct").addClass("is--hidden")}else{listItem.find(".message--correct").removeClass("is--hidden");listItem.find(".message--incorrect").addClass("is--hidden")}});return hasErrors},getCriterionName:function(element){return $(element).data("criterion-name")}};OpenAssessment.SelfView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.SelfView.prototype={UNSAVED_WARNING_KEY:"self-assessment",load:function(){var view=this;this.server.render("self_assessment").done(function(html){$("#openassessment__self-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__self-assessment",view.element));view.installHandlers()}).fail(function(){view.showLoadError("self-assessment")})},installHandlers:function(){var view=this;var sel=$("#openassessment__self-assessment",view.element);this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#self-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}else{this.rubric=null}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled,this));this.rubric.changesExistCallback($.proxy(this.assessmentRubricChanges,this))}sel.find("#self-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.selfAssess()})},selfSubmitEnabled:function(enabled){var button=$("#self-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without submitting your self assessment, you will lose any work you have done."))}},selfAssess:function(){var view=this;var baseView=this.baseView;baseView.toggleActionError("self",null);view.selfSubmitEnabled(false);this.server.selfAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.rubric.overallFeedback()).done(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);baseView.loadAssessmentModules();baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("self",errMsg);view.selfSubmitEnabled(true)})}};OpenAssessment.StaffView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffView.prototype={load:function(){var view=this;this.server.render("staff_assessment").done(function(html){$("#openassessment__staff-assessment",view.element).replaceWith(html)}).fail(function(){view.baseView.showLoadError("staff-assessment")})}};!function(OpenAssessment){"use strict";OpenAssessment.StaffAreaView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffAreaView.prototype={FULL_GRADE_UNSAVED_WARNING_KEY:"staff-grade",OVERRIDE_UNSAVED_WARNING_KEY:"staff-override",IS_SHOWING_CLASS:"is--showing",SLIDABLE_CLASS:"ui-slidable",SLIDABLE_CONTENT_CLASS:"ui-slidable__content",load:function(){var view=this;if($(".openassessment__staff-area",view.element).length>0){this.server.render("staff_area").done(function(html){$(".openassessment__staff-area",view.element).replaceWith(html);view.server.renderLatex($(".openassessment__staff-area",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("staff_area")})}},loadStudentInfo:function(classToExpand){var view=this;var $manageLearnersTab=$(".openassessment__staff-tools",this.element);var $form=$manageLearnersTab.find(".openassessment_student_info_form");var studentUsername=$manageLearnersTab.find(".openassessment__student_username").val();var showFormError=function(errorMessage){$form.find(".form--error").text(errorMessage).focus()};var deferred=$.Deferred();$(".openassessment__student-info",view.element).text("");if(studentUsername.trim()){this.server.studentInfo(studentUsername).done(function(html){showFormError("");$(".openassessment__student-info",view.element).replaceWith(html);$manageLearnersTab.on("click",".action--submit-cancel-submission",function(eventObject){eventObject.preventDefault();view.cancelSubmission($(this).data("submission-uuid"))});var handleChange=function(eventData){view.handleCommentChanged(eventData)};$manageLearnersTab.find(".cancel_submission_comments").on("change keyup drop paste",handleChange);var $rubric=$manageLearnersTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$manageLearnersTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.OVERRIDE_UNSAVED_WARNING_KEY));$manageLearnersTab.find(".wrapper--staff-assessment .action--submit",view.element).click(function(eventObject){var target=$(eventObject.currentTarget),rootElement=target.closest(".openassessment__student-info"),submissionID=rootElement.data("submission-uuid");eventObject.preventDefault();view.submitStaffOverride(submissionID,rubric,$manageLearnersTab)})}$manageLearnersTab.find("."+view.SLIDABLE_CLASS).click(function(event){var $toggle=$(event.currentTarget),$content=$toggle.next("."+view.SLIDABLE_CONTENT_CLASS);if($toggle.hasClass(view.IS_SHOWING_CLASS)){$toggle.removeClass(view.IS_SHOWING_CLASS).attr("aria-expanded","false");$content.slideUp()}else{$toggle.addClass(view.IS_SHOWING_CLASS).attr("aria-expanded","true");$content.slideDown()}});$manageLearnersTab.find(".staff-info__student__report__summary").focus();if(classToExpand){$manageLearnersTab.find("."+classToExpand+" ."+view.SLIDABLE_CONTENT_CLASS).slideDown();$manageLearnersTab.find("."+classToExpand+" ."+view.SLIDABLE_CLASS).addClass(view.IS_SHOWING_CLASS).attr("aria-expanded","true").focus()}deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));deferred.reject()})}else{showFormError(gettext("You must provide a learner name."));deferred.reject()}return deferred.promise()},loadStaffGradeForm:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);var $staffGradeControl=$staffGradeTab.find("."+view.SLIDABLE_CLASS);var $staffGradeContent=$staffGradeTab.find("."+view.SLIDABLE_CONTENT_CLASS);var deferred=$.Deferred();var showFormError=function(errorMessage){$staffGradeTab.find(".staff__grade__form--error").text(errorMessage).focus()};$staffGradeControl.toggleClass(view.IS_SHOWING_CLASS,true).attr("aria-expanded","true");if(this.staffGradeFormLoaded){$staffGradeContent.slideDown();deferred.resolve()}else{this.staffGradeFormLoaded=true;this.server.staffGradeForm().done(function(html){showFormError("");$staffGradeTab.find(".staff__grade__form").replaceWith(html);view.updateStaffGradeCounts();var $rubric=$staffGradeTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$staffGradeTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.FULL_GRADE_UNSAVED_WARNING_KEY));$staffGradeTab.find(".wrapper--staff-assessment .action--submit").click(function(eventObject){var submissionID=$staffGradeTab.find(".staff__grade__form").data("submission-uuid");eventObject.preventDefault();view.submitStaffGrade(submissionID,rubric,$staffGradeTab,$(eventObject.currentTarget).hasClass("continue_grading--action"))})}$staffGradeContent.slideDown(function(){$staffGradeControl.focus()});deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));view.staffGradeFormLoaded=false;deferred.reject()})}return deferred.promise()},closeStaffGradeForm:function(clear){var $staffGradeTab=$(".openassessment__staff-grading",this.element);var $staffGradeControl=$staffGradeTab.find("."+this.SLIDABLE_CLASS);var $staffGradeContent=$staffGradeTab.find("."+this.SLIDABLE_CONTENT_CLASS);$staffGradeControl.toggleClass(this.IS_SHOWING_CLASS,false).attr("aria-expanded","false");if(clear){$staffGradeTab.find(".staff__grade__form").replaceWith('<div class="staff__grade__form"></div>');this.updateStaffGradeCounts()}else{$staffGradeContent.slideUp()}$staffGradeControl.focus()},updateStaffGradeCounts:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);view.server.staffGradeCounts().done(function(html){$staffGradeTab.find(".staff__grade__status").replaceWith(html)}).fail(function(){$staffGradeTab.find(".staff__grade__status").replaceWith('<span class="staff__grade__status"><span class="staff__grade__value"><span class="copy">'+gettext("Error getting the number of ungraded responses")+"</span></span></span>")})},installHandlers:function(){var view=this;var $staffArea=$(".openassessment__staff-area",this.element);var $manageLearnersTab=$(".openassessment__staff-tools",$staffArea);var $staffGradeTool=$(".openassessment__staff-grading",$staffArea);if($staffArea.length<=0){return}$staffArea.find(".ui-staff__button").click(function(eventObject){$staffArea.find(".ui-staff__button").each(function(index,button){if(button!==eventObject.currentTarget){var $panel=$staffArea.find("."+$(button).data("panel")).first();$panel.slideUp(0)}});var $button=$(eventObject.currentTarget),$panel=$staffArea.find("."+$button.data("panel")).first();if($button.hasClass("is--active")){$button.removeClass("is--active").attr("aria-expanded","false");$panel.slideUp()}else{$staffArea.find(".ui-staff__button").removeClass("is--active").attr("aria-expanded","false");$button.addClass("is--active").attr("aria-expanded","true");$panel.slideDown()}$panel.find(".ui-staff_close_button").focus()});$staffArea.find(".ui-staff_close_button").click(function(eventObject){var $button=$(eventObject.currentTarget),$panel=$button.closest(".wrapper--ui-staff");$staffArea.find(".ui-staff__button").removeClass("is--active").attr("aria-expanded","false");$panel.slideUp();$staffArea.find(".ui-staff__button").each(function(index,button){var $staffPanel=$staffArea.find("."+$(button).data("panel")).first();if($staffPanel[0]===$panel[0]){$(button).focus()}})});$manageLearnersTab.find(".openassessment_student_info_form").submit(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$manageLearnersTab.find(".action--submit-username").click(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$manageLearnersTab.find(".action--submit-training").click(function(eventObject){eventObject.preventDefault();view.scheduleTraining()});$manageLearnersTab.find(".action--submit-unfinished-tasks").click(function(eventObject){eventObject.preventDefault();view.rescheduleUnfinishedTasks()});$staffGradeTool.find(".staff__grade__show-form").click(function(event){var wasShowing=$(event.currentTarget).hasClass(view.IS_SHOWING_CLASS);if(wasShowing){view.closeStaffGradeForm(false)}else{view.loadStaffGradeForm()}})},scheduleTraining:function(){var view=this;this.server.scheduleTraining().done(function(msg){$(".schedule_training_message",view.element).text(msg)}).fail(function(errMsg){$(".schedule_training_message",view.element).text(errMsg)})},rescheduleUnfinishedTasks:function(){var view=this;this.server.rescheduleUnfinishedTasks().done(function(msg){$(".reschedule_unfinished_tasks_message",view.element).text(msg)}).fail(function(errMsg){$(".reschedule_unfinished_tasks_message",view.element).text(errMsg)})},cancelSubmission:function(submissionUUID){this.cancelSubmissionEnabled(false);var view=this;var comments=$(".cancel_submission_comments",this.element).val();this.server.cancelSubmission(submissionUUID,comments).done(function(){view.loadStudentInfo("staff-info__student__grade")}).fail(function(errorMessage){$(".cancel-submission-error").html(_.escape(errorMessage))})},cancelSubmissionEnabled:function(enabled){var $cancelButton=$(".action--submit-cancel-submission",this.element);if(typeof enabled==="undefined"){return!$cancelButton.hasClass("is--disabled")}else{$cancelButton.toggleClass("is--disabled",!enabled)}},comment:function(text){var $submissionComments=$(".cancel_submission_comments",this.element);if(typeof text==="undefined"){return $submissionComments.val()}else{$submissionComments.val(text)}},handleCommentChanged:function(){var isBlank=$.trim(this.comment())!=="";this.cancelSubmissionEnabled(isBlank)},staffSubmitEnabled:function(scope,enabled){var button=scope.find(".wrapper--staff-assessment .action--submit");if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(key,changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,key,gettext("If you leave this page without submitting your staff assessment, you will lose any work you have done."))}},submitStaffOverride:function(submissionID,rubric,scope){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.OVERRIDE_UNSAVED_WARNING_KEY);view.loadStudentInfo("staff-info__student__grade")};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-override-error","regrade")},submitStaffGrade:function(submissionID,rubric,scope,continueGrading){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.FULL_GRADE_UNSAVED_WARNING_KEY);view.staffGradeFormLoaded=false;if(continueGrading){view.loadStaffGradeForm();view.baseView.scrollToTop(".openassessment__staff-area")}else{view.closeStaffGradeForm(true)}};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-grade-error","full-grade")},callStaffAssess:function(submissionID,rubric,scope,successCallback,errorSelector,assessType){var view=this;view.staffSubmitEnabled(scope,false);this.server.staffAssess(rubric.optionsSelected(),rubric.criterionFeedback(),rubric.overallFeedback(),submissionID,assessType).done(successCallback).fail(function(errorMessage){scope.find(errorSelector).html(_.escape(errorMessage));view.staffSubmitEnabled(scope,true)})}}}(OpenAssessment);OpenAssessment.StudentTrainingView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.StudentTrainingView.prototype={load:function(){var view=this;this.server.render("student_training").done(function(html){$("#openassessment__student-training",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__student-training",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("student-training")})},installHandlers:function(){var sel=$("#openassessment__student-training",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#student-training--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.assessButtonEnabled,this))}sel.find("#student-training--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.assess()})},assess:function(){this.assessButtonEnabled(false);var options={};if(this.rubric!==null){options=this.rubric.optionsSelected()}var view=this;var baseView=this.baseView;this.server.trainingAssess(options).done(function(corrections){var incorrect=$("#openassessment__student-training--incorrect",view.element);var instructions=$("#openassessment__student-training--instructions",view.element);if(!view.rubric.showCorrections(corrections)){view.load();baseView.loadAssessmentModules();incorrect.addClass("is--hidden");instructions.removeClass("is--hidden")}else{instructions.addClass("is--hidden");incorrect.removeClass("is--hidden")}baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("student-training",errMsg);view.assessButtonEnabled(true)})},assessButtonEnabled:function(isEnabled){var button=$("#student-training--001__assessment__submit",this.element);if(typeof isEnabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!isEnabled)}}};
\ No newline at end of file
if(typeof criterionFeedback!=="undefined"){$(sel).val(criterionFeedback[criterionName]);feedback[criterionName]=criterionFeedback[criterionName]}else{feedback[criterionName]=$(sel).val()}});return feedback},overallFeedback:function(overallFeedback){var selector=".assessment__rubric__question--feedback__value";if(typeof overallFeedback==="undefined"){return $(selector,this.element).val()}else{$(selector,this.element).val(overallFeedback)}},optionsSelected:function(optionsSelected){var selector="input[type=radio]";var rubric=this;if(typeof optionsSelected==="undefined"){var options={};$(selector+":checked",this.element).each(function(index,sel){options[rubric.getCriterionName(sel)]=sel.value});return options}else{$(selector,this.element).prop("checked",false);$(selector,this.element).each(function(index,sel){var criterionName=rubric.getCriterionName(sel);if(optionsSelected.hasOwnProperty(criterionName)){if(sel.value===optionsSelected[criterionName]){$(sel).prop("checked",true)}}})}},canSubmitCallback:function(callback){var rubric=this;callback(rubric.canSubmit());$(this.element).on("change keyup drop paste",function(){callback(rubric.canSubmit())})},canSubmit:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var numAvailable=$(".field--radio.assessment__rubric__question.has--options",this.element).length;var completedRequiredComments=true;$("textarea[required]",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText===""){completedRequiredComments=false}});return numChecked===numAvailable&&completedRequiredComments},changesExistCallback:function(callback){var rubric=this;callback(rubric.changesExist());$(this.element).on("change keyup drop paste",function(){callback(rubric.changesExist())})},changesExist:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var textExists=false;$("textarea",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText!==""){textExists=true}});return numChecked>0||textExists},showCorrections:function(corrections){var selector="input[type=radio]";var hasErrors=false;var rubric=this;$(selector,this.element).each(function(index,sel){var listItem=$(sel).parents(".assessment__rubric__question");if(corrections.hasOwnProperty(rubric.getCriterionName(sel))){hasErrors=true;listItem.find(".message--incorrect").removeClass("is--hidden");listItem.find(".message--correct").addClass("is--hidden")}else{listItem.find(".message--correct").removeClass("is--hidden");listItem.find(".message--incorrect").addClass("is--hidden")}});return hasErrors},getCriterionName:function(element){return $(element).data("criterion-name")}};OpenAssessment.SelfView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.SelfView.prototype={UNSAVED_WARNING_KEY:"self-assessment",load:function(){var view=this;this.server.render("self_assessment").done(function(html){$("#openassessment__self-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__self-assessment",view.element));view.installHandlers()}).fail(function(){view.showLoadError("self-assessment")})},installHandlers:function(){var view=this;var sel=$("#openassessment__self-assessment",view.element);this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#self-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}else{this.rubric=null}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled,this));this.rubric.changesExistCallback($.proxy(this.assessmentRubricChanges,this))}sel.find("#self-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.selfAssess()})},selfSubmitEnabled:function(enabled){var button=$("#self-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without submitting your self assessment, you will lose any work you have done."))}},selfAssess:function(){var view=this;var baseView=this.baseView;baseView.toggleActionError("self",null);view.selfSubmitEnabled(false);this.server.selfAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.rubric.overallFeedback()).done(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);baseView.loadAssessmentModules();baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("self",errMsg);view.selfSubmitEnabled(true)})}};OpenAssessment.StaffView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffView.prototype={load:function(){var view=this;this.server.render("staff_assessment").done(function(html){$("#openassessment__staff-assessment",view.element).replaceWith(html)}).fail(function(){view.baseView.showLoadError("staff-assessment")})}};(function(OpenAssessment){"use strict";OpenAssessment.StaffAreaView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffAreaView.prototype={FULL_GRADE_UNSAVED_WARNING_KEY:"staff-grade",OVERRIDE_UNSAVED_WARNING_KEY:"staff-override",IS_SHOWING_CLASS:"is--showing",SLIDABLE_CLASS:"ui-slidable",SLIDABLE_CONTENT_CLASS:"ui-slidable__content",load:function(){var view=this;if($(".openassessment__staff-area",view.element).length>0){this.server.render("staff_area").done(function(html){$(".openassessment__staff-area",view.element).replaceWith(html);view.server.renderLatex($(".openassessment__staff-area",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("staff_area")})}},loadStudentInfo:function(classToExpand){var view=this;var $manageLearnersTab=$(".openassessment__staff-tools",this.element);var $form=$manageLearnersTab.find(".openassessment_student_info_form");var studentUsername=$manageLearnersTab.find(".openassessment__student_username").val();var showFormError=function(errorMessage){$form.find(".form--error").text(errorMessage).focus()};var deferred=$.Deferred();$(".openassessment__student-info",view.element).text("");if(studentUsername.trim()){this.server.studentInfo(studentUsername).done(function(html){showFormError("");$(".openassessment__student-info",view.element).replaceWith(html);$manageLearnersTab.on("click",".action--submit-cancel-submission",function(eventObject){eventObject.preventDefault();view.cancelSubmission($(this).data("submission-uuid"))});var handleChange=function(eventData){view.handleCommentChanged(eventData)};$manageLearnersTab.find(".cancel_submission_comments").on("change keyup drop paste",handleChange);var $rubric=$manageLearnersTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$manageLearnersTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.OVERRIDE_UNSAVED_WARNING_KEY));$manageLearnersTab.find(".wrapper--staff-assessment .action--submit",view.element).click(function(eventObject){var target=$(eventObject.currentTarget),rootElement=target.closest(".openassessment__student-info"),submissionID=rootElement.data("submission-uuid");eventObject.preventDefault();view.submitStaffOverride(submissionID,rubric,$manageLearnersTab)})}$manageLearnersTab.find("."+view.SLIDABLE_CLASS).click(function(event){var $toggle=$(event.currentTarget),$content=$toggle.next("."+view.SLIDABLE_CONTENT_CLASS);if($toggle.hasClass(view.IS_SHOWING_CLASS)){$toggle.removeClass(view.IS_SHOWING_CLASS).attr("aria-expanded","false");$content.slideUp()}else{$toggle.addClass(view.IS_SHOWING_CLASS).attr("aria-expanded","true");$content.slideDown()}});$manageLearnersTab.find(".staff-info__student__report__summary").focus();if(classToExpand){$manageLearnersTab.find("."+classToExpand+" ."+view.SLIDABLE_CONTENT_CLASS).slideDown();$manageLearnersTab.find("."+classToExpand+" ."+view.SLIDABLE_CLASS).addClass(view.IS_SHOWING_CLASS).attr("aria-expanded","true").focus()}deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));deferred.reject()})}else{showFormError(gettext("You must provide a learner name."));deferred.reject()}return deferred.promise()},loadStaffGradeForm:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);var $staffGradeControl=$staffGradeTab.find("."+view.SLIDABLE_CLASS);var $staffGradeContent=$staffGradeTab.find("."+view.SLIDABLE_CONTENT_CLASS);var deferred=$.Deferred();var showFormError=function(errorMessage){$staffGradeTab.find(".staff__grade__form--error").text(errorMessage).focus()};$staffGradeControl.toggleClass(view.IS_SHOWING_CLASS,true).attr("aria-expanded","true");if(this.staffGradeFormLoaded){$staffGradeContent.slideDown();deferred.resolve()}else{this.staffGradeFormLoaded=true;this.server.staffGradeForm().done(function(html){showFormError("");$staffGradeTab.find(".staff__grade__form").replaceWith(html);view.updateStaffGradeCounts();var $rubric=$staffGradeTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$staffGradeTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.FULL_GRADE_UNSAVED_WARNING_KEY));$staffGradeTab.find(".wrapper--staff-assessment .action--submit").click(function(eventObject){var submissionID=$staffGradeTab.find(".staff__grade__form").data("submission-uuid");eventObject.preventDefault();view.submitStaffGrade(submissionID,rubric,$staffGradeTab,$(eventObject.currentTarget).hasClass("continue_grading--action"))})}$staffGradeContent.slideDown(function(){$staffGradeControl.focus()});deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));view.staffGradeFormLoaded=false;deferred.reject()})}return deferred.promise()},closeStaffGradeForm:function(clear){var $staffGradeTab=$(".openassessment__staff-grading",this.element);var $staffGradeControl=$staffGradeTab.find("."+this.SLIDABLE_CLASS);var $staffGradeContent=$staffGradeTab.find("."+this.SLIDABLE_CONTENT_CLASS);$staffGradeControl.toggleClass(this.IS_SHOWING_CLASS,false).attr("aria-expanded","false");if(clear){$staffGradeTab.find(".staff__grade__form").replaceWith('<div class="staff__grade__form"></div>');this.updateStaffGradeCounts()}else{$staffGradeContent.slideUp()}$staffGradeControl.focus()},updateStaffGradeCounts:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);view.server.staffGradeCounts().done(function(html){$staffGradeTab.find(".staff__grade__status").replaceWith(html)}).fail(function(){$staffGradeTab.find(".staff__grade__status").replaceWith('<span class="staff__grade__status"><span class="staff__grade__value"><span class="copy">'+gettext("Error getting the number of ungraded responses")+"</span></span></span>")})},installHandlers:function(){var view=this;var $staffArea=$(".openassessment__staff-area",this.element);var $manageLearnersTab=$(".openassessment__staff-tools",$staffArea);var $staffGradeTool=$(".openassessment__staff-grading",$staffArea);if($staffArea.length<=0){return}$staffArea.find(".ui-staff__button").click(function(eventObject){$staffArea.find(".ui-staff__button").each(function(index,button){if(button!==eventObject.currentTarget){var $panel=$staffArea.find("."+$(button).data("panel")).first();$panel.slideUp(0)}});var $button=$(eventObject.currentTarget),$panel=$staffArea.find("."+$button.data("panel")).first();if($button.hasClass("is--active")){$button.removeClass("is--active").attr("aria-expanded","false");$panel.slideUp()}else{$staffArea.find(".ui-staff__button").removeClass("is--active").attr("aria-expanded","false");$button.addClass("is--active").attr("aria-expanded","true");$panel.slideDown()}$panel.find(".ui-staff_close_button").focus()});$staffArea.find(".ui-staff_close_button").click(function(eventObject){var $button=$(eventObject.currentTarget),$panel=$button.closest(".wrapper--ui-staff");$staffArea.find(".ui-staff__button").removeClass("is--active").attr("aria-expanded","false");$panel.slideUp();$staffArea.find(".ui-staff__button").each(function(index,button){var $staffPanel=$staffArea.find("."+$(button).data("panel")).first();if($staffPanel[0]===$panel[0]){$(button).focus()}})});$manageLearnersTab.find(".openassessment_student_info_form").submit(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$manageLearnersTab.find(".action--submit-username").click(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$manageLearnersTab.find(".action--submit-training").click(function(eventObject){eventObject.preventDefault();view.scheduleTraining()});$manageLearnersTab.find(".action--submit-unfinished-tasks").click(function(eventObject){eventObject.preventDefault();view.rescheduleUnfinishedTasks()});$staffGradeTool.find(".staff__grade__show-form").click(function(event){var wasShowing=$(event.currentTarget).hasClass(view.IS_SHOWING_CLASS);if(wasShowing){view.closeStaffGradeForm(false)}else{view.loadStaffGradeForm()}})},scheduleTraining:function(){var view=this;this.server.scheduleTraining().done(function(msg){$(".schedule_training_message",view.element).text(msg)}).fail(function(errMsg){$(".schedule_training_message",view.element).text(errMsg)})},rescheduleUnfinishedTasks:function(){var view=this;this.server.rescheduleUnfinishedTasks().done(function(msg){$(".reschedule_unfinished_tasks_message",view.element).text(msg)}).fail(function(errMsg){$(".reschedule_unfinished_tasks_message",view.element).text(errMsg)})},cancelSubmission:function(submissionUUID){this.cancelSubmissionEnabled(false);var view=this;var comments=$(".cancel_submission_comments",this.element).val();this.server.cancelSubmission(submissionUUID,comments).done(function(){view.loadStudentInfo("staff-info__student__grade")}).fail(function(errorMessage){$(".cancel-submission-error").html(_.escape(errorMessage))})},cancelSubmissionEnabled:function(enabled){var $cancelButton=$(".action--submit-cancel-submission",this.element);if(typeof enabled==="undefined"){return!$cancelButton.hasClass("is--disabled")}else{$cancelButton.toggleClass("is--disabled",!enabled)}},comment:function(text){var $submissionComments=$(".cancel_submission_comments",this.element);if(typeof text==="undefined"){return $submissionComments.val()}else{$submissionComments.val(text)}},handleCommentChanged:function(){var isBlank=$.trim(this.comment())!=="";this.cancelSubmissionEnabled(isBlank)},staffSubmitEnabled:function(scope,enabled){var button=scope.find(".wrapper--staff-assessment .action--submit");if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(key,changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,key,gettext("If you leave this page without submitting your staff assessment, you will lose any work you have done."))}},submitStaffOverride:function(submissionID,rubric,scope){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.OVERRIDE_UNSAVED_WARNING_KEY);view.loadStudentInfo("staff-info__student__grade")};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-override-error","regrade")},submitStaffGrade:function(submissionID,rubric,scope,continueGrading){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.FULL_GRADE_UNSAVED_WARNING_KEY);view.staffGradeFormLoaded=false;if(continueGrading){view.loadStaffGradeForm();view.baseView.scrollToTop(".openassessment__staff-area")}else{view.closeStaffGradeForm(true)}};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-grade-error","full-grade")},callStaffAssess:function(submissionID,rubric,scope,successCallback,errorSelector,assessType){var view=this;view.staffSubmitEnabled(scope,false);this.server.staffAssess(rubric.optionsSelected(),rubric.criterionFeedback(),rubric.overallFeedback(),submissionID,assessType).done(successCallback).fail(function(errorMessage){scope.find(errorSelector).html(_.escape(errorMessage));view.staffSubmitEnabled(scope,true)})}}})(OpenAssessment);OpenAssessment.StudentTrainingView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.StudentTrainingView.prototype={load:function(){var view=this;this.server.render("student_training").done(function(html){$("#openassessment__student-training",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__student-training",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("student-training")})},installHandlers:function(){var sel=$("#openassessment__student-training",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#student-training--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.assessButtonEnabled,this))}sel.find("#student-training--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.assess()})},assess:function(){this.assessButtonEnabled(false);var options={};if(this.rubric!==null){options=this.rubric.optionsSelected()}var view=this;var baseView=this.baseView;this.server.trainingAssess(options).done(function(corrections){var incorrect=$("#openassessment__student-training--incorrect",view.element);var instructions=$("#openassessment__student-training--instructions",view.element);if(!view.rubric.showCorrections(corrections)){view.load();baseView.loadAssessmentModules();incorrect.addClass("is--hidden");instructions.removeClass("is--hidden")}else{instructions.addClass("is--hidden");incorrect.removeClass("is--hidden")}baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("student-training",errMsg);view.assessButtonEnabled(true)})},assessButtonEnabled:function(isEnabled){var button=$("#student-training--001__assessment__submit",this.element);if(typeof isEnabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!isEnabled)}}};
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,7 +8,7 @@ from openassessment.assessment.api import student_training
from openassessment.workflow import api as workflow_api
from openassessment.workflow.errors import AssessmentWorkflowError
from openassessment.xblock.data_conversion import convert_training_examples_list_to_dict, create_submission_dict
from .resolve_dates import DISTANT_FUTURE
from .resolve_dates import DISTANT_FUTURE, get_current_time_zone
logger = logging.getLogger(__name__)
......@@ -69,12 +69,14 @@ class StudentTrainingMixin(object):
# If no submissions have been created yet, the status will be None.
workflow_status = self.get_workflow_info().get('status')
problem_closed, reason, start_date, due_date = self.is_closed(step="student-training")
user_service = self.runtime.service(self, 'user')
context = {}
template = 'openassessmentblock/student_training/student_training_unavailable.html'
# add allow_latex field to the context
context['allow_latex'] = self.allow_latex
context['time_zone'] = get_current_time_zone(user_service)
if not workflow_status:
return template, context
......
......@@ -8,7 +8,7 @@ from openassessment.fileupload import api as file_upload_api
from openassessment.fileupload.exceptions import FileUploadError
from openassessment.workflow.errors import AssessmentWorkflowError
from .resolve_dates import DISTANT_FUTURE
from .resolve_dates import DISTANT_FUTURE, get_current_time_zone
from data_conversion import create_submission_dict, prepare_submission_for_serialization
from validation import validate_submission
......@@ -376,9 +376,12 @@ class SubmissionMixin(object):
"""
workflow = self.get_workflow_info()
problem_closed, reason, start_date, due_date = self.is_closed('submission')
user_service = self.runtime.service(self, 'user')
path = 'openassessmentblock/response/oa_response.html'
context = {}
context = {
'time_zone': get_current_time_zone(user_service)
}
# Due dates can default to the distant future, in which case
# there's effectively no due date.
......
"""
Tests the Open Assessment XBlock functionality.
"""
import ddt
from collections import namedtuple
import datetime as dt
from freezegun import freeze_time
import pytz
from mock import Mock, patch, MagicMock, PropertyMock
......@@ -12,7 +15,11 @@ from openassessment.workflow.errors import AssessmentWorkflowError
from .base import XBlockHandlerTestCase, scenario
@ddt.ddt
class TestOpenAssessment(XBlockHandlerTestCase):
"""Test Open Asessessment Xblock functionality"""
TIME_ZONE_FN_PATH = 'openassessment.xblock.peer_assessment_mixin.get_current_time_zone'
@scenario('data/basic_scenario.xml')
def test_load_student_view(self, xblock):
......@@ -23,34 +30,34 @@ class TestOpenAssessment(XBlockHandlerTestCase):
contents.
"""
xblock_fragment = self.runtime.render(xblock, "student_view")
self.assertTrue(xblock_fragment.body_html().find("Openassessmentblock"))
self.assertIn("OpenAssessmentBlock", xblock_fragment.body_html())
# Validate Submission Rendering.
submission_response = xblock.render_submission({})
self.assertIsNotNone(submission_response)
self.assertTrue(submission_response.body.find("openassessment__response"))
self.assertIn("openassessment__response", submission_response.body)
# Validate Peer Rendering.
request = namedtuple('Request', 'params')
request.params = {}
peer_response = xblock.render_peer_assessment(request)
self.assertIsNotNone(peer_response)
self.assertTrue(peer_response.body.find("openassessment__peer-assessment"))
self.assertIn("openassessment__peer-assessment", peer_response.body)
# Validate Self Rendering.
self_response = xblock.render_self_assessment(request)
self.assertIsNotNone(self_response)
self.assertTrue(self_response.body.find("openassessment__peer-assessment"))
self.assertIn("openassessment__self-assessment", self_response.body)
# Validate Staff Grade.
staff_response = xblock.render_staff_assessment(request)
self.assertIsNotNone(self_response)
self.assertTrue(staff_response.body.find("openassessment__staff-assessment"))
self.assertIn("openassessment__staff-assessment", staff_response.body)
# Validate Grading.
grade_response = xblock.render_grade({})
self.assertIsNotNone(grade_response)
self.assertTrue(grade_response.body.find("openassessment__grade"))
self.assertIn("openassessment__grade", grade_response.body)
@scenario('data/empty_prompt.xml')
def test_prompt_intentionally_empty(self, xblock):
......@@ -91,95 +98,227 @@ class TestOpenAssessment(XBlockHandlerTestCase):
xblock_fragment = self.runtime.render(xblock, "student_view")
# Expect that the page renders even if the update fails
self.assertTrue(xblock_fragment.body_html().find("Openassessmentblock"))
self.assertIn("OpenAssessmentBlock", xblock_fragment.body_html())
@scenario('data/dates_scenario.xml')
def test_load_student_view_with_dates(self, xblock):
@ddt.data(('utc', 'April 1, 2014 00:00 UTC'),
('America/Los_Angeles', 'March 31, 2014 17:00 PDT'))
@ddt.unpack
def test_load_student_view_with_dates(self, time_zone, expected_date):
"""OA XBlock returns some HTML to the user.
View basic test for verifying we're returned some HTML about the
Open Assessment XBlock. We don't want to match too heavily against the
contents.
"""
xblock_fragment = self.runtime.render(xblock, "student_view")
self.assertTrue(xblock_fragment.body_html().find("Openassessmentblock"))
with patch('openassessment.xblock.submission_mixin.get_current_time_zone') as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
# Validate Submission Rendering.
submission_response = xblock.render_submission({})
self.assertIsNotNone(submission_response)
self.assertTrue(submission_response.body.find("openassessment__response"))
self.assertTrue(submission_response.body.find("April"))
@scenario('data/basic_scenario.xml')
def test_formatted_dates(self, xblock):
xblock = self.load_scenario('data/dates_scenario.xml')
xblock_fragment = self.runtime.render(xblock, "student_view")
self.assertIn("OpenAssessmentBlock", xblock_fragment.body_html())
# Set start/due dates
xblock.start = dt.datetime(2014, 4, 1, 1, 1, 1)
xblock.due = dt.datetime(2014, 5, 1)
# Validate Submission Rendering.
submission_response = xblock.render_submission({})
self.assertIsNotNone(submission_response)
self.assertIn("openassessment__response", submission_response.body)
self.assertIn(expected_date, submission_response.body)
request = namedtuple('Request', 'params')
request.params = {}
resp = xblock.render_peer_assessment(request)
self.assertTrue(resp.body.find('Tuesday, April 01, 2014'))
self.assertTrue(resp.body.find('Thursday, May 01, 2014'))
@scenario('data/basic_scenario.xml')
def test_formatted_dates_for_beta_tester_with_days_early(self, xblock):
"""Test dates for beta tester with days early"""
def _set_up_start_date(self, start_date):
"""
Helper function to set up start date for xblocks
"""
xblock = self.load_scenario('data/basic_scenario.xml')
xblock.start = start_date
return xblock
# Set start/due dates
xblock.start = dt.datetime(2014, 4, 6, 1, 1, 1)
xblock.due = dt.datetime(2014, 5, 1)
def _set_up_days_early_for_beta(self, xblock, days_early):
"""
Helper function to set up start date early for beta testers
"""
xblock.xmodule_runtime = Mock(
course_id='test_course',
anonymous_student_id='test_student',
days_early_for_beta=5,
days_early_for_beta=days_early,
user_is_staff=False,
user_is_beta_tester=True
)
self.assertEqual(xblock.xmodule_runtime.days_early_for_beta, 5)
request = namedtuple('Request', 'params')
request.params = {}
resp = xblock.render_peer_assessment(request)
self.assertTrue(resp.body.find('Tuesday, April 01, 2014'))
self.assertTrue(resp.body.find('Thursday, May 01, 2014'))
@patch.object(openassessmentblock.OpenAssessmentBlock, 'is_beta_tester', new_callable=PropertyMock)
@scenario('data/basic_scenario.xml')
def test_formatted_dates_for_beta_tester_without_days_early(self, xblock, mock_is_beta_tester):
"""Test dates for beta tester without days early"""
mock_is_beta_tester.return_value = True
# Set start/due dates
xblock.start = dt.datetime(2014, 4, 6, 1, 1, 1)
xblock.due = dt.datetime(2014, 5, 1)
request = namedtuple('Request', 'params')
request.params = {}
resp = xblock.render_peer_assessment(request)
self.assertTrue(resp.body.find('Tuesday, April 06, 2014'))
self.assertTrue(resp.body.find('Thursday, May 01, 2014'))
@scenario('data/basic_scenario.xml')
def test_formatted_dates_for_beta_tester_with_nonetype_days_early(self, xblock):
"""Test dates for beta tester with NoneType days early"""
def _set_up_end_date(self, end_date):
"""
Helper function to set up end date for xblocks
"""
xblock = self.load_scenario('data/basic_scenario.xml')
xblock.due = end_date
return xblock
# Set start/due dates
xblock.start = dt.datetime(2014, 4, 6, 1, 1, 1)
xblock.due = dt.datetime(2014, 5, 1)
xblock.xmodule_runtime = Mock(
course_id='test_course',
anonymous_student_id='test_student',
days_early_for_beta=None,
user_is_staff=False,
user_is_beta_tester=True
)
self.assertEqual(xblock.xmodule_runtime.days_early_for_beta, None)
def _render_xblock(self, xblock):
"""
Helper function to render xblock
"""
request = namedtuple('Request', 'params')
request.params = {}
resp = xblock.render_peer_assessment(request)
self.assertTrue(resp.body.find('Tuesday, April 06, 2014'))
self.assertTrue(resp.body.find('Thursday, May 01, 2014'))
return xblock.render_peer_assessment(request)
@ddt.data(('utc', 'April 1, 2014 01:01 UTC'),
('America/Los_Angeles', 'March 31, 2014 18:01 PDT'))
@ddt.unpack
@freeze_time("2014-01-01")
def test_formatted_start_dates(self, time_zone, expected_start_date):
"""Test start dates correctly formatted"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
xblock = self._set_up_start_date(dt.datetime(2014, 4, 1, 1, 1, 1))
resp = self._render_xblock(xblock)
self.assertIn(expected_start_date, resp.body)
@ddt.data((dt.datetime(2015, 3, 8, 9, 59, 00, tzinfo=pytz.utc), 'March 8, 2015 01:59 PST'),
(dt.datetime(2015, 3, 8, 10, 00, 00, tzinfo=pytz.utc), 'March 8, 2015 03:00 PDT'))
@ddt.unpack
@freeze_time("2014-01-01")
def test_formatted_start_dates_daylight_savings(self, date, expected_start_date):
"""Test start dates correctly formatted for daylight savings time"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone('America/Los_Angeles')
# Set start dates'
xblock = self._set_up_start_date(date)
resp = self._render_xblock(xblock)
self.assertIn(expected_start_date, resp.body)
@ddt.data(('utc', 'May 1, 2014 00:00 UTC'),
('America/Los_Angeles', 'April 30, 2014 17:00 PDT'))
@ddt.unpack
def test_formatted_end_dates(self, time_zone, expected_end_date):
"""Test end dates correctly formatted"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
# Set due dates'
xblock = self._set_up_end_date(dt.datetime(2014, 5, 1))
resp = self._render_xblock(xblock)
self.assertIn(expected_end_date, resp.body)
@ddt.data((dt.datetime(2015, 3, 8, 9, 59, 00, tzinfo=pytz.utc), 'March 8, 2015 01:59 PST'),
(dt.datetime(2015, 3, 8, 10, 00, 00, tzinfo=pytz.utc), 'March 8, 2015 03:00 PDT'))
@ddt.unpack
def test_formatted_end_dates_daylight_savings(self, date, expected_end_date):
"""Test end dates correctly formatted for daylight savings time"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone('America/Los_Angeles')
# Set due dates'
xblock = self._set_up_end_date(date)
resp = self._render_xblock(xblock)
self.assertIn(expected_end_date, resp.body)
@ddt.data(('utc', 'April 1, 2014 01:01 UTC'),
('America/Los_Angeles', 'March 31, 2014 18:01 PDT'))
@ddt.unpack
@freeze_time("2014-01-01")
def test_formatted_start_dates_for_beta_tester_with_days_early(self, time_zone, expected_start_date):
"""Test start dates for beta tester with days early"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
# Set start dates
xblock = self._set_up_start_date(dt.datetime(2014, 4, 6, 1, 1, 1))
self._set_up_days_early_for_beta(xblock, 5)
self.assertEqual(xblock.xmodule_runtime.days_early_for_beta, 5)
resp = self._render_xblock(xblock)
self.assertIn(expected_start_date, resp.body)
@ddt.data(('utc', 'May 1, 2014 00:00 UTC'),
('America/Los_Angeles', 'April 30, 2014 17:00 PDT'))
@ddt.unpack
def test_formatted_end_dates_for_beta_tester_with_days_early(self, time_zone, expected_end_date):
"""Test end dates for beta tester with days early"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
# Set due dates
xblock = self._set_up_start_date(dt.datetime(2014, 4, 6, 1, 1, 1))
xblock.due = dt.datetime(2014, 5, 1)
self._set_up_days_early_for_beta(xblock, 5)
self.assertEqual(xblock.xmodule_runtime.days_early_for_beta, 5)
resp = self._render_xblock(xblock)
self.assertIn(expected_end_date, resp.body)
@ddt.data(('utc', 'April 6, 2014 01:01 UTC'),
('America/Los_Angeles', 'April 5, 2014 18:01 PDT'))
@ddt.unpack
@freeze_time("2014-01-01")
@patch.object(openassessmentblock.OpenAssessmentBlock, 'is_beta_tester', new_callable=PropertyMock)
def test_formatted_start_dates_for_beta_tester_without_days_early(
self,
time_zone,
expected_start_date,
mock_is_beta_tester
):
"""Test start dates for beta tester without days early"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
mock_is_beta_tester.return_value = True
# Set start dates
xblock = self._set_up_start_date(dt.datetime(2014, 4, 6, 1, 1, 1))
resp = self._render_xblock(xblock)
self.assertIn(expected_start_date, resp.body)
@ddt.data(('utc', 'May 1, 2014 00:00 UTC'),
('America/Los_Angeles', 'April 30, 2014 17:00 PDT'))
@ddt.unpack
@patch.object(openassessmentblock.OpenAssessmentBlock, 'is_beta_tester', new_callable=PropertyMock)
def test_formatted_end_dates_for_beta_tester_without_days_early(
self,
time_zone,
expected_end_date,
mock_is_beta_tester
):
"""Test end dates for beta tester without days early"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
mock_is_beta_tester.return_value = True
# Set due dates
xblock = self._set_up_end_date(dt.datetime(2014, 5, 1))
resp = self._render_xblock(xblock)
self.assertIn(expected_end_date, resp.body)
@ddt.data(('utc', 'April 6, 2014 01:01 UTC'),
('America/Los_Angeles', 'April 5, 2014 18:01 PDT'))
@ddt.unpack
@freeze_time("2014-01-01")
def test_formatted_start_dates_for_beta_tester_with_nonetype_days_early(self, time_zone, expected_start_date):
"""Test start dates for beta tester with NoneType days early"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
# Set start dates
xblock = self._set_up_start_date(dt.datetime(2014, 4, 6, 1, 1, 1))
self._set_up_days_early_for_beta(xblock, None)
self.assertEqual(xblock.xmodule_runtime.days_early_for_beta, None)
resp = self._render_xblock(xblock)
self.assertIn(expected_start_date, resp.body)
@ddt.data(('utc', 'May 1, 2014 00:00 UTC'),
('America/Los_Angeles', 'April 30, 2014 17:00 PDT'))
@ddt.unpack
def test_formatted_end_dates_for_beta_tester_with_nonetype_days_early(self, time_zone, expected_end_date):
"""Test end dates for beta tester with NoneType days early"""
with patch(self.TIME_ZONE_FN_PATH) as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
# Set due dates
xblock = self._set_up_end_date(dt.datetime(2014, 5, 1))
self._set_up_days_early_for_beta(xblock, None)
self.assertEqual(xblock.xmodule_runtime.days_early_for_beta, None)
resp = self._render_xblock(xblock)
self.assertIn(expected_end_date, resp.body)
@scenario('data/basic_scenario.xml', user_id='Bob')
def test_default_fields(self, xblock):
......
......@@ -309,6 +309,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', expected_context
......@@ -324,6 +325,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_closed.html', expected_context
......@@ -339,6 +341,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', expected_context
......@@ -357,6 +360,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_waiting.html',
......@@ -396,6 +400,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'peer_file_url': '',
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_assessment.html',
......@@ -415,6 +420,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
......@@ -438,6 +444,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_closed.html',
......@@ -473,6 +480,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_closed.html',
......@@ -500,6 +508,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
......@@ -532,6 +541,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'rubric_criteria': xblock.rubric_criteria,
'submit_button_text': 'Submit your assessment & review another response',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_turbo_mode_waiting.html',
......@@ -562,6 +572,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'rubric_criteria': xblock.rubric_criteria,
'submit_button_text': 'Submit your assessment & review another response',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_turbo_mode.html',
......@@ -583,6 +594,7 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'rubric_criteria': xblock.rubric_criteria,
'submit_button_text': 'Submit your assessment & review another response',
'allow_latex': False,
'time_zone': pytz.utc,
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_unavailable.html',
......
......@@ -3,10 +3,12 @@ Test resolving unspecified dates and date strings to datetimes.
"""
import datetime
import pytz
from django.test import TestCase
import ddt
from openassessment.xblock.resolve_dates import resolve_dates, DISTANT_PAST, DISTANT_FUTURE
from mock import MagicMock
from openassessment.xblock.resolve_dates import resolve_dates, DISTANT_PAST, DISTANT_FUTURE, get_current_time_zone
import pytz
from workbench.runtime import WorkBenchUserService
STUB_I18N = lambda x: x
......@@ -128,3 +130,14 @@ class ResolveDatesTest(TestCase):
],
STUB_I18N
)
@ddt.data(({}, pytz.utc),
({'pref-lang': 'en', 'time_zone': 'America/Los_Angeles'}, pytz.timezone('America/Los_Angeles')))
@ddt.unpack
def test_get_current_time_zone(self, user_preferences, expected_time_zone):
"""Verify get_current_time_zone returns correct time zone or UTC"""
user_service = WorkBenchUserService(3)
user_service.get_current_user().opt_attrs['edx-platform.user_preferences'] = user_preferences
time_zone = get_current_time_zone(user_service)
self.assertEqual(expected_time_zone, time_zone)
......@@ -169,7 +169,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
self._assert_path_and_context(
xblock,
'openassessmentblock/self/oa_self_unavailable.html',
{'self_start': datetime.datetime(5999, 1, 1).replace(tzinfo=pytz.utc), 'allow_latex': False}
{
'self_start': datetime.datetime(5999, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
@scenario('data/self_assessment_closed.xml', user_id='Bob')
......@@ -178,14 +182,22 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
self._assert_path_and_context(
xblock,
'openassessmentblock/self/oa_self_closed.html',
{'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc), 'allow_latex': False}
{
'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
@scenario('data/self_assessment_open.xml', user_id='Bob')
def test_open_no_submission(self, xblock):
# Without making a submission, this step should be unavailable
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_unavailable.html', {'allow_latex': False}
xblock, 'openassessmentblock/self/oa_self_unavailable.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
}
)
@scenario('data/self_assessment_open.xml', user_id='James Brown')
......@@ -197,7 +209,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
# Should still not be able to access self-assessment
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_unavailable.html', {'allow_latex': False}
xblock, 'openassessmentblock/self/oa_self_unavailable.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
}
)
@scenario('data/self_assessment_open.xml', user_id='James Brown')
......@@ -209,7 +225,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock.get_student_item_dict(), u"𝓟𝓪𝓼𝓼 𝓽𝓱𝓮 𝓹𝓮𝓪𝓼"
)
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_complete.html', {'allow_latex': False},
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='waiting',
status_details={
'self': {'complete': True},
......@@ -226,7 +246,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
# In the self --> peer configuration, self can be complete
# if our status is "peer"
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_complete.html', {'allow_latex': False},
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status="peer",
status_details={
'self': {'complete': True},
......@@ -241,7 +265,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock.get_student_item_dict(), (u"Ⱥɨn'ŧ ɨŧ fᵾnꝁɏ 1", u"Ⱥɨn'ŧ ɨŧ fᵾnꝁɏ 2")
)
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_complete.html', {'allow_latex': False},
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='done'
)
......@@ -252,7 +280,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock.get_student_item_dict(), u"Ⱥɨn'ŧ ɨŧ fᵾnꝁɏ"
)
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_cancelled.html', {'allow_latex': False},
xblock, 'openassessmentblock/self/oa_self_cancelled.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='cancelled'
)
......@@ -270,6 +302,7 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
'file_upload_type': None,
'self_file_url': '',
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='self',
submission_uuid=submission['uuid']
......@@ -290,7 +323,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
create_rubric_dict(xblock.prompts, xblock.rubric_criteria)
)
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_complete.html', {'allow_latex': False},
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='self',
submission_uuid=submission['uuid']
)
......@@ -305,7 +342,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
self._assert_path_and_context(
xblock,
'openassessmentblock/self/oa_self_closed.html',
{'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc), 'allow_latex': False},
{
'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='self',
submission_uuid=submission['uuid']
)
......@@ -332,7 +373,11 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
# we ALWAYS show complete, even if the workflow tells us we're still have status 'self'.
self._assert_path_and_context(
xblock, 'openassessmentblock/self/oa_self_complete.html',
{'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc), 'allow_latex': False},
{
'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
},
workflow_status='self',
submission_uuid=submission['uuid']
)
......
......@@ -63,6 +63,7 @@ class StudentTrainingAssessTest(StudentTrainingTest):
@ddt.file_data('data/student_training_mixin.json')
def test_correct(self, xblock, data):
xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION)
data["expected_context"]['time_zone'] = pytz.utc
self.assert_path_and_context(xblock, data["expected_template"], data["expected_context"])
# Agree with the course author's assessment
......@@ -83,6 +84,7 @@ class StudentTrainingAssessTest(StudentTrainingTest):
@ddt.file_data('data/student_training_mixin.json')
def test_correct_with_error(self, xblock, data):
xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION)
data["expected_context"]['time_zone'] = pytz.utc
self.assert_path_and_context(xblock, data["expected_template"], data["expected_context"])
# Agree with the course author's assessment
......@@ -106,6 +108,7 @@ class StudentTrainingAssessTest(StudentTrainingTest):
@ddt.file_data('data/student_training_mixin.json')
def test_incorrect(self, xblock, data):
xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION)
data["expected_context"]['time_zone'] = pytz.utc
self.assert_path_and_context(xblock, data["expected_template"], data["expected_context"])
# Disagree with the course author's assessment
......@@ -128,6 +131,7 @@ class StudentTrainingAssessTest(StudentTrainingTest):
expected_context = data["expected_context"].copy()
expected_template = data["expected_template"]
xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION)
expected_context['time_zone'] = pytz.utc
self.assert_path_and_context(xblock, expected_template, expected_context)
# Agree with the course author's assessment
......@@ -173,7 +177,10 @@ class StudentTrainingAssessTest(StudentTrainingTest):
# Expect that we were correct
self.assertTrue(resp['success'], msg=resp.get('msg'))
self.assertFalse(resp['corrections'])
expected_context = {"allow_latex": False}
expected_context = {
"allow_latex": False,
'time_zone': pytz.utc,
}
expected_template = "openassessmentblock/student_training/student_training_complete.html"
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -203,6 +210,7 @@ class StudentTrainingAssessTest(StudentTrainingTest):
xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION)
expected_context = data["expected_context"].copy()
expected_template = data["expected_template"]
expected_context['time_zone'] = pytz.utc
self.assert_path_and_context(xblock, expected_template, expected_context)
resp = self.request(xblock, 'training_assess', json.dumps({}), response_format='json')
self.assertFalse(resp['success'], msg=resp.get('msg'))
......@@ -219,6 +227,7 @@ class StudentTrainingAssessTest(StudentTrainingTest):
xblock.create_submission(xblock.get_student_item_dict(), self.SUBMISSION)
expected_context = data["expected_context"].copy()
expected_template = data["expected_template"]
expected_context['time_zone'] = pytz.utc
self.assert_path_and_context(xblock, expected_template, expected_context)
selected_data = {
......@@ -302,6 +311,7 @@ class StudentTrainingRenderTest(StudentTrainingTest):
expected_context = {
'training_due': "2000-01-01T00:00:00+00:00",
'allow_latex': False,
'time_zone': pytz.utc,
}
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -315,6 +325,7 @@ class StudentTrainingRenderTest(StudentTrainingTest):
expected_template = "openassessmentblock/student_training/student_training_cancelled.html"
expected_context = {
'allow_latex': False,
'time_zone': pytz.utc,
}
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -333,5 +344,6 @@ class StudentTrainingRenderTest(StudentTrainingTest):
expected_context = {
'training_start': datetime.datetime(3000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -182,6 +182,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'file_upload_type': None,
'submission_start': dt.datetime(4999, 4, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -204,6 +205,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': True,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -222,6 +224,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'submit_enabled': False,
'submission_due': dt.datetime(2999, 5, 6).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -239,6 +242,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'save_status': 'This response has not been saved.',
'submit_enabled': False,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -262,6 +266,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'submit_enabled': True,
'submission_due': dt.datetime(2999, 5, 6).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -285,6 +290,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'submit_enabled': True,
'submission_due': dt.datetime(2999, 5, 6).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -303,6 +309,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': True,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -333,7 +340,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'cancelled_at': xblock.get_workflow_cancellation_info(submission['uuid']).get('cancelled_at'),
'cancelled_by_id': 'Bob',
'cancelled_by': mock_staff
}
},
'time_zone': pytz.utc,
}
)
......@@ -359,6 +367,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': True,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -370,6 +379,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'file_upload_type': None,
'submission_due': dt.datetime(2014, 4, 5).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -388,6 +398,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': False,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -412,6 +423,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'student_submission': create_submission_dict(submission, xblock.prompts),
'file_upload_type': None,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......@@ -436,6 +448,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'student_submission': create_submission_dict(submission, xblock.prompts),
'file_upload_type': None,
'allow_latex': False,
'time_zone': pytz.utc,
}
)
......
......@@ -3,6 +3,7 @@
coverage==4.0.2
django-nose==1.4.1
freezegun==0.1.11
mock==1.0.1
moto==0.3.1
pep8==1.7.0
......
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