Commit 50141ffe by Gregory Martin

implement dateutils from edx-ui-toolkit

parent f70b111d
......@@ -4,7 +4,7 @@ module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: 'openassessment/xblock/static/js',
basePath: 'openassessment/xblock/static/',
plugins: [
......@@ -25,37 +25,56 @@ module.exports = function(config) {
// list of files / patterns to load in the browser
files: [
'lib/jquery.min.js',
'lib/*.js',
'src/oa_shared.js',
'src/*.js',
'src/lms/*.js',
'src/studio/*.js',
'spec/test_shared.js',
'spec/*.js',
'spec/lms/*.js',
'spec/studio/*.js',
'js/lib/jquery.min.js',
'js/lib/codemirror.js',
'js/lib/jquery.timepicker.min.js',
'js/lib/jquery-ui-1.10.4.min.js',
'js/lib/underscore-min.js',
'../../../node_modules/requirejs/require.js',
'../../../require-config.js',
{
pattern: '../../../node_modules/moment-timezone/builds/moment-timezone-with-data.min.js',
served: true, included: false
},
{
pattern: '../../../node_modules/moment/min/moment-with-locales.min.js',
served: true, included: false
},
{
pattern: '../../../node_modules/edx-ui-toolkit/src/js/utils/date-utils.js',
served: true, included: false
},
{
pattern: '../../../node_modules/edx-ui-toolkit/src/js/utils/string-utils.js',
served: true, included: false
},
//
'js/src/oa_shared.js',
'js/src/*.js',
'js/src/lms/*.js',
'js/src/studio/*.js',
'js/spec/test_shared.js',
'js/spec/*.js',
'js/spec/lms/*.js',
'js/spec/studio/*.js',
// fixtures
{
pattern: 'fixtures/*.html',
pattern: 'js/fixtures/*.html',
served: true, included: false
}
],
// list of files to exclude
exclude: [
'src/design*.js'
'js/src/design*.js'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/*.js': 'coverage',
'src/lms/*.js': 'coverage',
'src/studio/*.js': 'coverage'
'js/src/*.js': 'coverage',
'js/src/lms/*.js': 'coverage',
'js/src/studio/*.js': 'coverage'
},
......
......@@ -20,13 +20,17 @@
<span class="step__label">{% trans "Assess Peers" %}</span>
{% 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|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 %}
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "available August 13th, 2014 00:00 UTC (in 5 days and 45 minutes)" #}
{% blocktrans with start_date=peer_start|date:"Y-m-d H:i" time_until=peer_start|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ start_date }}" data-string="available {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></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|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 %}
{# Translators: This string displays a date to the user, then tells them the time until that date. Example: "due August 13th, 2014 00:00 UTC (in 5 days and 45 minutes)" #}
{% blocktrans with due_date=peer_due|date:"Y-m-d H:i" time_until=peer_due|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ due_date }}" data-string="due {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></span>
{% endblocktrans %}
</span>
{% endif %}
</span>
......
......@@ -17,16 +17,20 @@
{% 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|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 %}
{% blocktrans with start_date=submission_start|date:"Y-m-d H:i" time_until=submission_start|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ start_date }}" data-string="available {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></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|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 %}
{% blocktrans with due_date=submission_due|date:"Y-m-d H:i" time_until=submission_due|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ due_date }}" data-string="due {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></span>
{% endblocktrans %}
</span>
{% endif %}
</span>
</button>
{% block title %}
<span class="step__status">
<span class="step__status__value">
......@@ -44,7 +48,10 @@
<p>
{% trans "Enter your response to the question." %}
{% if submission_due %}
{% trans "You can save your progress and return to complete your response at any time before the due date" %} (<span class="step__deadline"><span class="date">{{ submission_due|timezone:time_zone|date:"l, N j, Y H:i e" }}</span></span>).
{% trans "You can save your progress and return to complete your response at any time before the due date" %}
(<span class="step__deadline">
<span class="date ora-datetime" data-datetime="{{ submission_due|date:'Y-m-d H:i' }}" data-timezone="{{ user_timezone }}" data-format="longDateTime" data-language="{{ user_language }}"></span>
</span>).
{% else %}
{% trans "You can save your progress and return to complete your response at any time." %}
{% endif %}
......
......@@ -32,11 +32,11 @@
{% trans "Your submission was cancelled. " %}
<p>
{% if workflow_cancellation.cancelled_by %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|timezone:time_zone|date:"N j, Y H:i e" removed_by_username=workflow_cancellation.cancelled_by %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|timezone:"UTC"|date:"Y-m-d H:i e" removed_by_username=workflow_cancellation.cancelled_by %}
Your submission has been cancelled by {{ removed_by_username }} on {{ removed_datetime }}
{% endblocktrans %}
{% else %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|timezone:time_zone|date:"N j, Y H:i e" %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|timezone:"UTC"|date:"Y-m-d H:i e" %}
Your submission was cancelled on {{ removed_datetime }}
{% endblocktrans %}
{% endif %}
......
......@@ -18,12 +18,16 @@
{% 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|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 %}
{% blocktrans with start_date=self_start|date:"Y-m-d H:i" time_until=self_start|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ start_date }}" data-string="available {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></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|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 %}
{% blocktrans with due_date=self_due|date:"Y-m-d H:i" time_until=self_due|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ due_date }}" data-string="due {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></span>
{% endblocktrans %}
</span>
{% endif %}
</span>
......
......@@ -26,11 +26,11 @@
{% if workflow_cancellation %}
<p>
{% if workflow_cancellation.cancelled_by %}
{% blocktrans with removed_by_username=workflow_cancellation.cancelled_by removed_datetime=workflow_cancellation.cancelled_at|timezone:time_zone|date:"F j, Y H:i e" %}
{% blocktrans with removed_by_username=workflow_cancellation.cancelled_by removed_datetime=workflow_cancellation.cancelled_at|timezone:"UTC"|date:"Y-m-d H:i e" %}
Learner submission removed by {{ removed_by_username }} on {{ removed_datetime }}
{% endblocktrans %}
{% else %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|timezone:time_zone|date:"F j, Y H:i e" %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|timezone:"UTC"|date:"Y-m-d H:i e" %}
Learner submission removed on {{ removed_datetime }}
{% endblocktrans %}
{% endif %}
......
......@@ -17,12 +17,16 @@
{% 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|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 %}
{% blocktrans with start_date=training_start|date:"Y-m-d H:i" time_until=training_start|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ start_date }}" data-string="available {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></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|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 %}
{% blocktrans with due_date=training_due|date:"Y-m-d H:i" time_until=training_due|timeuntil %}
<span class="date ora-datetime" data-datetime="{{ due_date }}" data-string="due {date} (in {{ time_until }})" data-timezone="{{ user_timezone }}" data-language="{{ user_language }}"></span>
{% endblocktrans %}
</span>
</span>
{% endif %}
......
"""
The Peer Assessment Mixin for all Peer Functionality.
"""
import logging
from webob import Response
......@@ -10,7 +15,8 @@ from openassessment.assessment.errors import (
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, get_current_time_zone
from .resolve_dates import DISTANT_FUTURE
from .user_data import get_user_preferences
from .data_conversion import clean_criterion_feedback, create_submission_dict, verify_assessment_parameters
logger = logging.getLogger(__name__)
......@@ -161,12 +167,13 @@ 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')
user_preferences = get_user_preferences(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),
"user_timezone": user_preferences['user_timezone'],
"user_language": user_preferences['user_language'],
"xblock_id": self.get_xblock_id(),
}
......
......@@ -24,18 +24,6 @@ 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.
......
......@@ -6,7 +6,8 @@ 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, get_current_time_zone
from .resolve_dates import DISTANT_FUTURE
from .user_data import get_user_preferences
from .data_conversion import (clean_criterion_feedback, create_submission_dict,
create_rubric_dict, verify_assessment_parameters)
......@@ -54,12 +55,13 @@ class SelfAssessmentMixin(object):
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')
user_preferences = get_user_preferences(self.runtime.service(self, 'user'))
context = {
'allow_latex': self.allow_latex,
"xblock_id": self.get_xblock_id(),
'time_zone': get_current_time_zone(user_service)
'user_timezone': user_preferences['user_timezone'],
'user_language': user_preferences['user_language']
}
# We display the due date whether the problem is open or closed.
......
......@@ -24,7 +24,7 @@ from openassessment.assessment.api import self as self_api
from openassessment.assessment.api import ai as ai_api
from openassessment.workflow import api as workflow_api
from openassessment.assessment.api import staff as staff_api
from .resolve_dates import get_current_time_zone
from .user_data import get_user_preferences
logger = logging.getLogger(__name__)
......@@ -319,11 +319,14 @@ class StaffAreaMixin(object):
Returns:
A context dict for rendering a student submission and associated rubric (for staff grading).
"""
user_preferences = get_user_preferences(self.runtime.service(self, 'user')) # localize for staff user
context = {
'submission': create_submission_dict(submission, self.prompts) if submission else None,
'rubric_criteria': copy.deepcopy(self.rubric_criteria_with_labels),
'student_username': student_username,
'time_zone': get_current_time_zone(self.runtime.service(self, 'user')), # localize for staff user
'user_timezone': user_preferences['user_timezone'],
'user_language': user_preferences['user_language']
}
if submission:
......
......@@ -893,7 +893,8 @@
"cancelled_at": "2015-10-01T04:53",
"comments": "Cancelled!"
},
"time_zone": "utc"
"user_timezone": "utc",
"user_language": "en"
},
"output": "oa_staff_cancelled_submission.html"
},
......@@ -1195,5 +1196,22 @@
"student_username": "mock_user_2"
},
"output": "oa_staff_grade_learners_assessment_2.html"
},
{
"template": "openassessmentblock/response/oa_response.html",
"context": {
"saved_response": {
"answer": {
"parts": [
{ "text": "", "prompt": { "description": "Prompt 1" }},
{ "text": "", "prompt": { "description": "Prompt 2" }}
]
}
},
"save_status": "This response has not been saved.",
"submit_enabled": true,
"submission_due": "2020-01-01T00:00"
},
"output": "oa_response_date.html"
}
]
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
Tests for OA dateutil factory.
**/
describe('OpenAssessment.DateTimeFactory', function() {
beforeEach(function() {
// Load the DOM fixture
loadFixtures('oa_response_date.html');
});
describe('apply', function() {
it('has the correct HTML elements', function() {
var timeElement = $('.step__title').get(0);
var datetimeFactory = new OpenAssessment.DateTimeFactory(timeElement);
datetimeFactory.apply();
$('.ora-datetime', timeElement).each(function() {
var self = this;
expect($(self).data('datetime')).toBe('2019-12-31 19:00');
expect($(self).data('string')).toContain('due {date}');
});
});
});
describe('determineContext', function() {
it('generates a context dict', function() {
var timeElement = $('.step__title').get(0);
var datetimeFactory = new OpenAssessment.DateTimeFactory(timeElement);
$('.ora-datetime', timeElement).each(function() {
var self = this;
$(self).attr('data-language', 'en');
$(self).attr('data-timezone', 'America/Los_Angeles');
});
$('.ora-datetime', timeElement).each(function() {
var el = this;
var testContext = datetimeFactory.determineContext($(el));
expect(testContext['datetime']).toBe('2019-12-31 19:00');
expect(testContext['timezone']).toBe('America/Los_Angeles');
expect(testContext['language']).toBe('en');
expect(testContext['format']).toBe('');
})
})
});
describe('determineDateToken', function() {
it('defaults', function() {
var timeElement = $('.step__title').get(0);
var datetimeFactory = new OpenAssessment.DateTimeFactory(timeElement);
$('.ora-datetime', timeElement).each(function() {
var el = this;
var testDateToken = datetimeFactory.determineDateToken($(el));
expect(testDateToken).toBe('date');
});
$('.ora-datetime', timeElement).each(function() {
var self = this;
$(self).attr('data-datetoken', 'TEST');
});
$('.ora-datetime', timeElement).each(function() {
var el = this;
var testDateToken = datetimeFactory.determineDateToken($(el));
expect(testDateToken).toBe('TEST');
})
})
});
describe('isValid', function() {
it('checks a valid variable', function() {
var timeElement = $('.step__title').get(0);
var datetimeFactory = new OpenAssessment.DateTimeFactory(timeElement);
var testDict = {
'Invalid date': false,
'invalid date': true,
'': false,
1: true
};
Object.keys(testDict).forEach(function(key) {
expect(datetimeFactory.isValid(key)).toEqual(testDict[key]);
});
})
});
});
......@@ -466,7 +466,7 @@ describe('OpenAssessment.StaffAreaView', function() {
// Verify that the student view reflects the cancellation
expect($($('.staff-info__student__response p', staffArea.element)[0]).text().trim()).toBe(
'Learner submission removed by staff on October 1, 2015 04:53 UTC'
'Learner submission removed by staff on 2015-10-01 04:53 UTC'
);
expect($($('.staff-info__student__response p', staffArea.element)[1]).text().trim()).toBe(
'Comments: Cancelled!'
......
......@@ -3,5 +3,5 @@ Common test configuration, loaded before any of the spec files.
**/
// Set the fixture path
jasmine.getFixtures().fixturesPath = 'base/fixtures';
jasmine.getFixtures().fixturesPath = 'base/js/fixtures';
......@@ -223,6 +223,7 @@ OpenAssessment.BaseView.prototype = {
this.selfView.load(usageID);
this.gradeView.load(usageID);
this.leaderboardView.load(usageID);
/**
this.messageView.load() is intentionally omitted.
Because of the asynchronous loading, there is no way to tell (from the perspective of the
......@@ -383,4 +384,5 @@ function OpenAssessmentBlock(runtime, element, data) {
var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.BaseView(runtime, element, server, data);
view.load();
}
/**
*
* A helper function to utilize DateUtils.
**/
OpenAssessment.DateTimeFactory = function(element) {
this.element = element;
};
OpenAssessment.DateTimeFactory.prototype = {
apply: function() {
var dtFactory = this;
$('.ora-datetime', this.element).each(function() {
dtFactory.elementApply($(this));
});
},
determineContext: function(el) {
var context;
context = {
datetime: el.data('datetime'),
timezone: el.data('timezone'),
language: el.data('language'),
format: ''
};
return context;
},
determineDateToken: function(el) {
var dtFactory = this;
var dateToken = 'date';
if (dtFactory.isValid(el.data('datetoken'))) {
dateToken = el.data('datetoken');
}
return dateToken;
},
elementApply: function(el) {
var dtFactory = this;
(function(require) {
require([
'jquery',
'edx-ui-toolkit/js/utils/date-utils',
'edx-ui-toolkit/js/utils/string-utils'
], function($, DateUtils, StringUtils) {
var context;
var localTimeString;
var displayDatetime;
var interpolateDict = {};
if (dtFactory.isValid(el.data('datetime'))) {
context = dtFactory.determineContext(el);
if (dtFactory.isValid(el.data('format'))) {
context.format = DateUtils.dateFormatEnum[el.data('format')];
}
localTimeString = DateUtils.localize(context);
interpolateDict[dtFactory.determineDateToken(el)] = localTimeString;
if (dtFactory.isValid(el.data('string'))) {
displayDatetime = StringUtils.interpolate(
el.data('string'),
interpolateDict
);
} else {
displayDatetime = localTimeString;
}
} else {
displayDatetime = StringUtils.interpolate(
el.data('string'),
interpolateDict
);
}
el.text(displayDatetime);
}
);
}).call(this, require || RequireJS.require);
},
isValid: function(candidateVariable) {
return candidateVariable !== undefined &&
candidateVariable !== '' &&
candidateVariable !== 'Invalid date' &&
candidateVariable !== 'None';
}
};
......@@ -12,6 +12,7 @@ OpenAssessment.GradeView = function(element, server, baseView) {
this.baseView = baseView;
this.announceStatus = false;
this.isRendering = false;
this.dateFactory = new OpenAssessment.DateTimeFactory(this.element);
};
OpenAssessment.GradeView.prototype = {
......@@ -33,6 +34,7 @@ OpenAssessment.GradeView.prototype = {
view.installHandlers();
view.baseView.announceStatusChangeToSRandFocus(stepID, usageID, true, view, focusID);
view.dateFactory.apply();
}
).fail(function(errMsg) {
baseView.showLoadError('grade', errMsg);
......
......@@ -16,6 +16,8 @@ OpenAssessment.PeerView = function(element, server, baseView) {
this.rubric = null;
this.isRendering = false;
this.announceStatus = false;
this.dateFactory = new OpenAssessment.DateTimeFactory(this.element);
};
OpenAssessment.PeerView.prototype = {
......@@ -42,6 +44,7 @@ OpenAssessment.PeerView.prototype = {
view.baseView.announceStatusChangeToSRandFocus(stepID, usageID, false, view, focusID);
view.announceStatus = false;
view.dateFactory.apply();
}
).fail(function() {
view.baseView.showLoadError('peer-assessment');
......
......@@ -26,6 +26,7 @@ OpenAssessment.ResponseView = function(element, server, fileUploader, baseView,
this.fileUploaded = false;
this.announceStatus = false;
this.isRendering = false;
this.dateFactory = new OpenAssessment.DateTimeFactory(this.element);
};
OpenAssessment.ResponseView.prototype = {
......@@ -58,11 +59,10 @@ OpenAssessment.ResponseView.prototype = {
view.server.renderLatex($(stepID, view.element));
view.installHandlers();
view.setAutoSaveEnabled(true);
view.isRendering = false;
view.baseView.announceStatusChangeToSRandFocus(stepID, usageID, false, view, focusID);
view.announceStatus = false;
view.dateFactory.apply();
}
).fail(function() {
view.baseView.showLoadError('response');
......
......@@ -16,6 +16,7 @@ OpenAssessment.SelfView = function(element, server, baseView) {
this.rubric = null;
this.isRendering = false;
this.announceStatus = false;
this.dateFactory = new OpenAssessment.DateTimeFactory(this.element);
};
OpenAssessment.SelfView.prototype = {
......@@ -38,8 +39,9 @@ OpenAssessment.SelfView.prototype = {
view.server.renderLatex($(stepID, view.element));
view.installHandlers();
view.baseView.announceStatusChangeToSRandFocus(stepID, usageID, false, view, focusID);
view.dateFactory.apply();
}
).fail(function() {
view.showLoadError('self-assessment');
......
......@@ -11,6 +11,7 @@ OpenAssessment.StaffView = function(element, server, baseView) {
this.baseView = baseView;
this.isRendering = false;
this.announceStatus = false;
};
OpenAssessment.StaffView.prototype = {
......
......@@ -16,6 +16,7 @@ OpenAssessment.StudentTrainingView = function(element, server, baseView) {
this.rubric = null;
this.isRendering = false;
this.announceStatus = false;
this.dateFactory = new OpenAssessment.DateTimeFactory(this.element);
};
OpenAssessment.StudentTrainingView.prototype = {
......@@ -38,7 +39,7 @@ OpenAssessment.StudentTrainingView.prototype = {
view.baseView.announceStatusChangeToSRandFocus(stepID, usageID, false, view, focusID);
view.announceStatus = false;
view.dateFactory.apply();
}
).fail(function() {
view.baseView.showLoadError('student-training');
......
......@@ -8,7 +8,8 @@ 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, get_current_time_zone
from .resolve_dates import DISTANT_FUTURE
from .user_data import get_user_preferences
logger = logging.getLogger(__name__)
......@@ -69,14 +70,15 @@ 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')
user_preferences = get_user_preferences(self.runtime.service(self, 'user'))
context = {"xblock_id": self.get_xblock_id()}
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)
context['user_timezone'] = user_preferences['user_timezone']
context['user_language'] = user_preferences['user_language']
if not workflow_status:
return template, context
......
......@@ -8,7 +8,8 @@ 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, get_current_time_zone
from .resolve_dates import DISTANT_FUTURE
from .user_data import get_user_preferences
from data_conversion import create_submission_dict, prepare_submission_for_serialization
from validation import validate_submission
......@@ -376,11 +377,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')
user_preferences = get_user_preferences(self.runtime.service(self, 'user'))
path = 'openassessmentblock/response/oa_response.html'
context = {
'time_zone': get_current_time_zone(user_service),
'user_timezone': user_preferences['user_timezone'],
'user_language': user_preferences['user_language'],
"xblock_id": self.get_xblock_id()}
# Due dates can default to the distant future, in which case
......
......@@ -19,7 +19,7 @@ from .base import XBlockHandlerTestCase, scenario
class TestOpenAssessment(XBlockHandlerTestCase):
"""Test Open Asessessment Xblock functionality"""
TIME_ZONE_FN_PATH = 'openassessment.xblock.peer_assessment_mixin.get_current_time_zone'
TIME_ZONE_FN_PATH = 'openassessment.xblock.user_data.get_user_preferences'
@scenario('data/basic_scenario.xml')
def test_load_student_view(self, xblock):
......@@ -100,8 +100,8 @@ class TestOpenAssessment(XBlockHandlerTestCase):
# Expect that the page renders even if the update fails
self.assertIn("OpenAssessmentBlock", xblock_fragment.body_html())
@ddt.data(('utc', 'April 1, 2014 00:00 UTC'),
('America/Los_Angeles', 'March 31, 2014 17:00 PDT'))
@ddt.data(('utc', '2014-03-31 20:00'),
('America/Los_Angeles', '2014-03-31 20:00'))
@ddt.unpack
def test_load_student_view_with_dates(self, time_zone, expected_date):
"""OA XBlock returns some HTML to the user.
......@@ -110,8 +110,8 @@ class TestOpenAssessment(XBlockHandlerTestCase):
Open Assessment XBlock. We don't want to match too heavily against the
contents.
"""
with patch('openassessment.xblock.submission_mixin.get_current_time_zone') as time_zone_fn:
time_zone_fn.return_value = pytz.timezone(time_zone)
with patch('openassessment.xblock.user_data.get_user_preferences') as time_zone_fn:
time_zone_fn.return_value['user_timezone'] = pytz.timezone(time_zone)
xblock = self.load_scenario('data/dates_scenario.xml')
xblock_fragment = self.runtime.render(xblock, "student_view")
......@@ -159,67 +159,40 @@ class TestOpenAssessment(XBlockHandlerTestCase):
request.params = {}
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.data(('utc', '2014-03-31 21:01'),
('America/Los_Angeles', '2014-03-31 21:01'))
@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)
time_zone_fn.return_value['user_timezone'] = 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.data(('utc', '2014-04-30 20:00'),
('America/Los_Angeles', '2014-04-30 20:00'))
@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)
time_zone_fn.return_value['user_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.data(('utc', '2014-03-31 21:01'),
('America/Los_Angeles', '2014-03-31 21:01'))
@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)
time_zone_fn.return_value['user_timezone'] = pytz.timezone(time_zone)
# Set start dates
xblock = self._set_up_start_date(dt.datetime(2014, 4, 6, 1, 1, 1))
......@@ -229,25 +202,24 @@ class TestOpenAssessment(XBlockHandlerTestCase):
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.data(('utc', '2014-04-30 20:00'),
('America/Los_Angeles', '2014-04-30 20:00'))
@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)
time_zone_fn.return_value['user_timezone'] = 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.data(('utc', '2014-04-05 21:01'),
('America/Los_Angeles', '2014-04-05 21:01'))
@ddt.unpack
@freeze_time("2014-01-01")
@patch.object(openassessmentblock.OpenAssessmentBlock, 'is_beta_tester', new_callable=PropertyMock)
......@@ -259,7 +231,7 @@ class TestOpenAssessment(XBlockHandlerTestCase):
):
"""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)
time_zone_fn.return_value['user_timezone'] = pytz.timezone(time_zone)
mock_is_beta_tester.return_value = True
# Set start dates
......@@ -267,8 +239,8 @@ class TestOpenAssessment(XBlockHandlerTestCase):
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.data(('utc', '2014-04-30 20:00'),
('America/Los_Angeles', '2014-04-30 20:00'))
@ddt.unpack
@patch.object(openassessmentblock.OpenAssessmentBlock, 'is_beta_tester', new_callable=PropertyMock)
def test_formatted_end_dates_for_beta_tester_without_days_early(
......@@ -279,7 +251,7 @@ class TestOpenAssessment(XBlockHandlerTestCase):
):
"""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)
time_zone_fn.return_value['user_timezone'] = pytz.timezone(time_zone)
mock_is_beta_tester.return_value = True
# Set due dates
......@@ -287,8 +259,8 @@ class TestOpenAssessment(XBlockHandlerTestCase):
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.data(('utc', '2014-04-05 21:01'),
('America/Los_Angeles', '2014-04-05 21:01'))
@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):
......@@ -304,8 +276,8 @@ class TestOpenAssessment(XBlockHandlerTestCase):
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.data(('utc', '2014-04-30 20:00'),
('America/Los_Angeles', '2014-04-30 20:00'))
@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"""
......
......@@ -309,7 +309,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', expected_context
......@@ -325,7 +326,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_closed.html', expected_context
......@@ -341,7 +343,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_unavailable.html', expected_context
......@@ -360,7 +363,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_waiting.html',
......@@ -400,7 +404,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'peer_file_url': '',
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_assessment.html',
......@@ -420,7 +425,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
......@@ -444,7 +450,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_closed.html',
......@@ -480,7 +487,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'review_num': 1,
'submit_button_text': 'submit your assessment & move to response #2',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_closed.html',
......@@ -508,7 +516,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'must_grade': 5,
'review_num': 1,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
......@@ -541,7 +550,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'rubric_criteria': xblock.rubric_criteria,
'submit_button_text': 'Submit your assessment & review another response',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_turbo_mode_waiting.html',
......@@ -572,7 +582,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'rubric_criteria': xblock.rubric_criteria,
'submit_button_text': 'Submit your assessment & review another response',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_turbo_mode.html',
......@@ -594,7 +605,8 @@ class TestPeerAssessmentRender(XBlockHandlerTestCase):
'rubric_criteria': xblock.rubric_criteria,
'submit_button_text': 'Submit your assessment & review another response',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
self._assert_path_and_context(
xblock, 'openassessmentblock/peer/oa_peer_unavailable.html',
......
......@@ -6,7 +6,9 @@ import datetime
from django.test import TestCase
import ddt
from mock import MagicMock
from openassessment.xblock.resolve_dates import resolve_dates, DISTANT_PAST, DISTANT_FUTURE, get_current_time_zone
from openassessment.xblock.resolve_dates import resolve_dates, DISTANT_PAST, DISTANT_FUTURE
from openassessment.xblock.user_data import get_user_preferences
import pytz
from workbench.runtime import WorkBenchUserService
......@@ -131,13 +133,14 @@ class ResolveDatesTest(TestCase):
STUB_I18N
)
@ddt.data(({}, pytz.utc),
({'pref-lang': 'en', 'time_zone': 'America/Los_Angeles'}, pytz.timezone('America/Los_Angeles')))
@ddt.data(({}, None, None),
({'pref-lang': 'en', 'time_zone': 'America/Los_Angeles'}, 'America/Los_Angeles', 'en'))
@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"""
def test_get_user_preferences(self, user_preferences, expected_timezone, expected_language):
"""Verify get_user_preferences returns correct time zone and language"""
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)
user_preferences = get_user_preferences(user_service)
self.assertEqual(expected_timezone, user_preferences['user_timezone'])
self.assertEqual(expected_language, user_preferences['user_language'])
......@@ -172,7 +172,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
{
'self_start': datetime.datetime(5999, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
)
......@@ -185,7 +186,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
{
'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
)
......@@ -196,7 +198,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_unavailable.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
)
......@@ -212,7 +215,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_unavailable.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
}
)
......@@ -228,7 +232,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
},
workflow_status='waiting',
status_details={
......@@ -249,7 +254,9 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
},
workflow_status="peer",
status_details={
......@@ -268,7 +275,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
},
workflow_status='done'
)
......@@ -283,7 +291,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_cancelled.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
},
workflow_status='cancelled'
)
......@@ -302,7 +311,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
'file_upload_type': None,
'self_file_url': '',
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
},
workflow_status='self',
submission_uuid=submission['uuid']
......@@ -326,7 +336,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
xblock, 'openassessmentblock/self/oa_self_complete.html',
{
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
},
workflow_status='self',
submission_uuid=submission['uuid']
......@@ -345,7 +356,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
{
'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
},
workflow_status='self',
submission_uuid=submission['uuid']
......@@ -376,7 +388,8 @@ class TestSelfAssessmentRender(XBlockHandlerTestCase):
{
'self_due': datetime.datetime(2000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': pytz.utc,
'user_language': 'en'
},
workflow_status='self',
submission_uuid=submission['uuid']
......
......@@ -66,7 +66,8 @@ 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
data["expected_context"]['user_timezone'] = None
data["expected_context"]['user_language'] = None
self.assert_path_and_context(xblock, data["expected_template"], data["expected_context"])
# Agree with the course author's assessment
......@@ -87,7 +88,8 @@ 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
data["expected_context"]['user_timezone'] = None
data["expected_context"]['user_language'] = None
self.assert_path_and_context(xblock, data["expected_template"], data["expected_context"])
# Agree with the course author's assessment
......@@ -111,7 +113,8 @@ 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
data["expected_context"]['user_timezone'] = None
data["expected_context"]['user_language'] = None
self.assert_path_and_context(xblock, data["expected_template"], data["expected_context"])
# Disagree with the course author's assessment
......@@ -134,7 +137,8 @@ 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
expected_context['user_timezone'] = None
expected_context['user_language'] = None
self.assert_path_and_context(xblock, expected_template, expected_context)
# Agree with the course author's assessment
......@@ -182,7 +186,8 @@ class StudentTrainingAssessTest(StudentTrainingTest):
self.assertFalse(resp['corrections'])
expected_context = {
"allow_latex": False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
expected_template = "openassessmentblock/student_training/student_training_complete.html"
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -213,7 +218,9 @@ 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
expected_context['user_timezone'] = None
expected_context['user_language'] = None
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'))
......@@ -230,7 +237,8 @@ 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
expected_context['user_timezone'] = None
expected_context['user_language'] = None
self.assert_path_and_context(xblock, expected_template, expected_context)
selected_data = {
......@@ -317,7 +325,8 @@ class StudentTrainingRenderTest(StudentTrainingTest):
expected_context = {
'training_due': "2000-01-01T00:00:00+00:00",
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -331,7 +340,8 @@ class StudentTrainingRenderTest(StudentTrainingTest):
expected_template = "openassessmentblock/student_training/student_training_cancelled.html"
expected_context = {
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -350,6 +360,7 @@ class StudentTrainingRenderTest(StudentTrainingTest):
expected_context = {
'training_start': datetime.datetime(3000, 1, 1).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
self.assert_path_and_context(xblock, expected_template, expected_context)
......@@ -182,7 +182,8 @@ 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,
'user_timezone': None,
'user_language': None
}
)
......@@ -205,7 +206,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': True,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -224,7 +226,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'submit_enabled': False,
'submission_due': dt.datetime(2999, 5, 6).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -242,7 +245,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'save_status': 'This response has not been saved.',
'submit_enabled': False,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -266,7 +270,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'submit_enabled': True,
'submission_due': dt.datetime(2999, 5, 6).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -290,7 +295,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'submit_enabled': True,
'submission_due': dt.datetime(2999, 5, 6).replace(tzinfo=pytz.utc),
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -309,7 +315,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': True,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -341,7 +348,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'cancelled_by_id': 'Bob',
'cancelled_by': mock_staff
},
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -367,7 +375,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': True,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -379,7 +388,8 @@ 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,
'user_timezone': None,
'user_language': None
}
)
......@@ -398,7 +408,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'peer_incomplete': False,
'self_incomplete': True,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -423,7 +434,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'student_submission': create_submission_dict(submission, xblock.prompts),
'file_upload_type': None,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -448,7 +460,8 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
'student_submission': create_submission_dict(submission, xblock.prompts),
'file_upload_type': None,
'allow_latex': False,
'time_zone': pytz.utc,
'user_timezone': None,
'user_language': None
}
)
......@@ -457,7 +470,7 @@ class SubmissionRenderTest(XBlockHandlerTestCase):
# Expect that the response step is open and displays the deadline
resp = self.request(xblock, 'render_submission', json.dumps(dict()))
self.assertIn('Enter your response to the question', resp)
self.assertIn('Monday, May 6, 2999 00:00 UTC', resp)
self.assertIn('2999-05-05 19:00', resp)
# Create a submission for the user
xblock.create_submission(
......
"""
Retrieve user-specific data
"""
def get_user_preferences(user_service):
"""
Returns the preferred language and timezone for the current user, if specified, or None if not.
:param user_service: XblockUserService
"""
user_preferences = {
'user_language': None,
'user_timezone': None
}
retrieved_preferences = user_service.get_current_user().opt_attrs.get('edx-platform.user_preferences')
if retrieved_preferences is not None:
user_preferences['user_timezone'] = retrieved_preferences.get('time_zone')
user_preferences['user_language'] = retrieved_preferences.get('pref-lang')
return user_preferences
......@@ -2,23 +2,29 @@
"name": "edx-ora2",
"version": "0.2.0",
"repository": "https://github.com/edx/edx-ora2.git",
"dependencies": {
"edx-ui-toolkit": "1.5.1",
"moment": "^2.15.1",
"moment-timezone": "~0.5.5",
"requirejs": "~2.3.2",
"underscore": "^1.8.2"
},
"devDependencies": {
"underscore": "^1.8.2",
"jasmine": "^2.3.0",
"jscs": "2.6.0",
"jshint": "2.8.0",
"karma": "^0.12.16",
"karma-chrome-launcher": "^0.1.4",
"karma-coverage": "^0.2.6",
"karma-jasmine": "^0.3.6",
"karma-jasmine-html-reporter": "~0.1",
"karma-jasmine-jquery": "^0.1.1",
"karma-chrome-launcher": "^0.1.4",
"karma-phantomjs-launcher": "^0.1.4",
"karma-sinon": "^1.0.3",
"karma-jasmine-html-reporter": "~0.1",
"karma-spec-reporter": "^0.0.20",
"jasmine": "^2.3.0",
"phantomjs": "^1.9.11",
"sinon": "^1.10.3",
"uglify-js": "^2.6.3",
"jshint": "2.8.0",
"jscs": "2.6.0"
"uglify-js": "^2.6.3"
},
"scripts": {
"test": "./node_modules/karma/bin/karma start --reporters spec,coverage"
......
(function(require, define) {
'use strict';
var defineDependency;
// We do not wish to bundle common libraries (that may also be used by non-RequireJS code on the page
// into the optimized files. Therefore load these libraries through script tags and explicitly define them.
// Note that when the optimizer executes this code, window will not be defined.
if (window) {
defineDependency = function (globalName, name, noShim) {
var getGlobalValue = function () {
var globalNamePath = globalName.split('.'),
result = window,
i;
for (i = 0; i < globalNamePath.length; i++) {
result = result[globalNamePath[i]];
}
return result;
},
globalValue = getGlobalValue();
if (globalValue) {
if (noShim) {
define(name, {});
} else {
define(name, [], function () {
return globalValue;
});
}
} else {
console.error('Expected library to be included on page, but not found on window object: ' + name);
}
};
defineDependency('jQuery', 'jquery');
}
function getBaseUrlPath() {
// require-config doesn't play nice with relative paths, but
// the Travis server, devstack, and staging/production servers all place the
// node_module files differently in absolute paths - this is a way to retrieve the
// path to the Jasmine req's as nicely as possible
var scripts = document.getElementsByTagName("script");
var fullTag = $(scripts[scripts.length-1]);
var baseUrl = fullTag.attr('src').split(['require-config'])[0];
return baseUrl
}
require.config({
baseUrl: getBaseUrlPath(),
paths: {
'jquery': './openassessment/xblock/static/js/lib/jquery.min',
'moment': './node_modules/moment/min/moment-with-locales.min',
'moment-timezone': './node_modules/moment-timezone/builds/moment-timezone-with-data.min',
'edx-ui-toolkit/js/utils/date-utils': './node_modules/edx-ui-toolkit/src/js/utils/date-utils',
'edx-ui-toolkit/js/utils/string-utils': './node_modules/edx-ui-toolkit/src/js/utils/string-utils'
},
shim: {
'jquery': {
exports: 'jQuery'
}
}
})
}).call(this, require || RequireJS.require, define || RequireJS.define);
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