Commit 7f1c89b4 by cahrens

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

parents c0bb3c96 4b925520
......@@ -21,8 +21,7 @@ Feature: Advanced (manual) course policy
Scenario: Test editing key value
Given I am on the Advanced Course Settings page in Studio
When I edit the value of a policy key
And I press the "Save" notification button
When I edit the value of a policy key and save
Then the policy key value is changed
And I reload the page
Then the policy key value is changed
......
......@@ -51,6 +51,11 @@ def edit_the_value_of_a_policy_key(step):
e._element.send_keys(Keys.TAB, Keys.END, Keys.ARROW_LEFT, ' ', 'X')
@step(u'I edit the value of a policy key and save$')
def edit_the_value_of_a_policy_key(step):
change_display_name_value(step, '"foo"')
@step('I create a JSON object as a value$')
def create_JSON_object(step):
change_display_name_value(step, '{"key": "value", "key_2": "value_2"}')
......@@ -96,7 +101,7 @@ def the_policy_key_value_is_unchanged(step):
@step(u'the policy key value is changed$')
def the_policy_key_value_is_changed(step):
assert_equal(get_display_name_value(), '"Robot Super Course X"')
assert_equal(get_display_name_value(), '"foo"')
############# HELPERS ###############
......
......@@ -18,8 +18,8 @@ COURSE_END_TIME_CSS = "#course-end-time"
ENROLLMENT_START_TIME_CSS = "#course-enrollment-start-time"
ENROLLMENT_END_TIME_CSS = "#course-enrollment-end-time"
DUMMY_TIME = "3:30pm"
DEFAULT_TIME = "12:00am"
DUMMY_TIME = "15:30"
DEFAULT_TIME = "00:00"
############### ACTIONS ####################
......
......@@ -38,7 +38,7 @@ def i_click_the_edit_link_for_the_release_date(step):
@step('I save a new section release date$')
def i_save_a_new_section_release_date(step):
set_date_and_time('input.start-date.date.hasDatepicker', '12/25/2013',
'input.start-time.time.ui-timepicker-input', '12:00am')
'input.start-time.time.ui-timepicker-input', '00:00')
world.browser.click_link_by_text('Save')
......@@ -105,7 +105,7 @@ def the_section_release_date_picker_not_visible(step):
def the_section_release_date_is_updated(step):
css = 'span.published-status'
status_text = world.css_text(css)
assert_equal(status_text, 'Will Release: 12/25/2013 at 12:00am')
assert_equal(status_text, 'Will Release: 12/25/2013 at 00:00 UTC')
############ HELPER METHODS ###################
......
......@@ -57,18 +57,18 @@ def i_see_complete_subsection_name_with_quote_in_editor(step):
@step('I have set a release date and due date in different years$')
def test_have_set_dates_in_different_years(step):
set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '3:00am')
set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '03:00')
world.css_click('.set-date')
# Use a year in the past so that current year will always be different.
set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '4:00am')
set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '04:00')
@step('I see the correct dates$')
def i_see_the_correct_dates(step):
assert_equal('12/25/2011', world.css_find('input#start_date').first.value)
assert_equal('3:00am', world.css_find('input#start_time').first.value)
assert_equal('03:00', world.css_find('input#start_time').first.value)
assert_equal('01/02/2012', world.css_find('input#due_date').first.value)
assert_equal('4:00am', world.css_find('input#due_time').first.value)
assert_equal('04:00', world.css_find('input#due_time').first.value)
@step('I mark it as Homework$')
......
......@@ -92,6 +92,69 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
return cnt
def test_draft_metadata(self):
'''
This verifies a bug we had where inherited metadata was getting written to the
module as 'own-metadata' when publishing. Also verifies the metadata inheritance is
properly computed
'''
store = modulestore()
draft_store = modulestore('draft')
import_from_xml(store, 'common/test/data/', ['simple'])
course = draft_store.get_item(Location(['i4x', 'edX', 'simple',
'course', '2012_Fall', None]), depth=None)
html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod)
self.assertNotIn('graceperiod', own_metadata(html_module))
draft_store.clone_item(html_module.location, html_module.location)
# refetch to check metadata
html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod)
self.assertNotIn('graceperiod', own_metadata(html_module))
# publish module
draft_store.publish(html_module.location, 0)
# refetch to check metadata
html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod)
self.assertNotIn('graceperiod', own_metadata(html_module))
# put back in draft and change metadata and see if it's now marked as 'own_metadata'
draft_store.clone_item(html_module.location, html_module.location)
html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
new_graceperiod = timedelta(**{'hours': 1})
self.assertNotIn('graceperiod', own_metadata(html_module))
html_module.lms.graceperiod = new_graceperiod
self.assertIn('graceperiod', own_metadata(html_module))
self.assertEqual(html_module.lms.graceperiod, new_graceperiod)
draft_store.update_metadata(html_module.location, own_metadata(html_module))
# read back to make sure it reads as 'own-metadata'
html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
self.assertIn('graceperiod', own_metadata(html_module))
self.assertEqual(html_module.lms.graceperiod, new_graceperiod)
# republish
draft_store.publish(html_module.location, 0)
# and re-read and verify 'own-metadata'
draft_store.clone_item(html_module.location, html_module.location)
html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
self.assertIn('graceperiod', own_metadata(html_module))
self.assertEqual(html_module.lms.graceperiod, new_graceperiod)
def test_get_depth_with_drafts(self):
import_from_xml(modulestore(), 'common/test/data/', ['simple'])
......
......@@ -826,7 +826,7 @@ function saveSetSectionScheduleDate(e) {
data: JSON.stringify({ 'id': id, 'metadata': {'start': start}})
}).success(function () {
var $thisSection = $('.courseware-section[data-id="' + id + '"]');
$thisSection.find('.section-published-date').html('<span class="published-status"><strong>Will Release:</strong> ' + input_date + ' at ' + input_time + '</span><a href="#" class="edit-button" data-date="' + input_date + '" data-time="' + input_time + '" data-id="' + id + '">Edit</a>');
$thisSection.find('.section-published-date').html('<span class="published-status"><strong>Will Release:</strong> ' + input_date + ' at ' + input_time + ' UTC</span><a href="#" class="edit-button" data-date="' + input_date + '" data-time="' + input_time + '" data-id="' + id + '">Edit</a>');
$thisSection.find('.section-published-date').animate({
'background-color': 'rgb(182,37,104)'
}, 300).animate({
......
......@@ -110,7 +110,7 @@ CMS.Views.Settings.Details = CMS.Views.ValidatingView.extend({
};
// instrument as date and time pickers
timefield.timepicker();
timefield.timepicker({'timeFormat' : 'H:i'});
datefield.datepicker();
// Using the change event causes savefield to be triggered twice, but it is necessary
......
......@@ -62,6 +62,12 @@ table {
border-spacing: 0;
}
abbr[title] {
border-bottom: none;
text-decoration: none;
cursor: help;
}
// ====================
// grandfathered styles
......
......@@ -604,13 +604,39 @@ body.course.outline {
}
.picker {
@include clearfix();
margin: 30px 0 65px;
.field {
float: left;
margin-right: ($baseline/2);
&:first-child {
margin-left: ($baseline*5);
}
&:last-child {
margin-right: 0;
}
label, input {
display: block;
text-align: left;
}
label {
@include font-size(14);
margin-bottom: ($baseline/4);
}
}
}
.description {
float: left;
margin-top: 30px;
font-size: 14px;
line-height: 20px;
width: 100%;
}
strong {
......
......@@ -3,11 +3,41 @@
body.course.subsection {
.main-wrapper {
margin-top: ($baseline*2);
}
.unit-settings {
.window-contents {
padding: 10px 20px;
}
.datepair {
.field {
display: inline-block;
margin-right: ($baseline/4);
width: 45%;
&:last-child {
margin-right: 0;
}
label, input {
display: block;
text-align: left;
}
input {
width: 100%;
}
label {
margin-bottom: ($baseline/4);
}
}
}
.unit-actions {
border-bottom: none;
padding-bottom: 0;
......@@ -74,7 +104,7 @@ body.course.subsection {
}
.window-contents {
display: none;
display: none;
}
}
......@@ -232,6 +262,7 @@ body.course.subsection {
.remove-date {
display: block;
margin-top: ($baseline/4);
}
}
......@@ -259,7 +290,7 @@ body.course.subsection {
background-position: 0 -50px;
.hidden {
background-position: 0 -5px;
background-position: 0 -5px;
}
}
}
......@@ -369,4 +400,4 @@ body.course.subsection {
}
}
}
}
\ No newline at end of file
}
......@@ -3,9 +3,8 @@
body.course.unit {
.unit .main-wrapper {
@include clearfix();
margin: 40px;
.main-wrapper {
margin-top: ($baseline*2);
}
//Problem Selector tab menu requirements
......@@ -31,7 +30,7 @@ body.course.unit {
}
.unit-body {
.unit-name-input {
padding: 20px 40px;
......@@ -44,7 +43,7 @@ body.course.unit {
font-size: 20px;
}
}
.breadcrumbs {
border-radius: 3px 3px 0 0;
border-bottom: 1px solid #cbd1db;
......@@ -189,10 +188,10 @@ body.course.unit {
@include clearfix;
a {
position: relative;
position: relative;
border: 1px solid $darkGreen;
background: tint($green,20%);
color: #fff;
color: #fff;
&:hover {
background: $brightGreen;
......@@ -254,8 +253,8 @@ body.course.unit {
@include transition (none);
&:hover {
background: tint($green,30%);
color: #fff;
background: tint($green,30%);
color: #fff;
@include transition(background-color .15s);
}
}
......@@ -263,7 +262,7 @@ body.course.unit {
li {
border:none;
border-bottom: 1px dashed $lightGrey;
color: #fff;
color: #fff;
}
li:first-child {
......@@ -326,7 +325,7 @@ body.course.unit {
}
}
// specific editor types
// specific editor types
.empty {
a {
......@@ -337,20 +336,20 @@ body.course.unit {
&:hover {
background: tint($green,30%);
background: tint($green,30%);
color: #fff;
}
}
}
}
.new-component {
.new-component {
text-align: center;
h5 {
color: $darkGreen;
}
}
}
}
......@@ -374,7 +373,7 @@ body.course.unit {
&.editing {
border: 1px solid $lightBluishGrey2;
z-index: auto;
.drag-handle,
.component-actions {
display: none;
......@@ -434,7 +433,7 @@ body.course.unit {
label {
display: inline-block;
margin-right: 10px;
margin-right: 10px;
}
}
......@@ -528,7 +527,7 @@ body.course.unit {
}
.window-contents {
display: none;
display: none;
}
}
......@@ -678,4 +677,4 @@ body.unit {
padding-top: 0;
}
}
}
\ No newline at end of file
}
......@@ -33,17 +33,22 @@
<h4 class="header">Subsection Settings</h4>
<div class="window-contents">
<div class="scheduled-date-input row">
<label>Release date:<!-- <span class="description">Determines when this subsection and the units within it will be released publicly.</span>--></label>
<div class="datepair" data-language="javascript">
<input type="text" id="start_date" name="start_date" value="${get_time_struct_display(subsection.lms.start, '%m/%d/%Y')}" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
<input type="text" id="start_time" name="start_time" value="${get_time_struct_display(subsection.lms.start, '%H:%M')}" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
<div class="field field-start-date">
<label for="start_date">Release Day</label>
<input type="text" id="start_date" name="start_date" value="${get_time_struct_display(subsection.lms.start, '%m/%d/%Y')}" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
</div>
<div class="field field-start-time">
<label for="start_time">Release Time (<abbr title="Coordinated Universal Time">UTC</abbr>)</label>
<input type="text" id="start_time" name="start_time" value="${get_time_struct_display(subsection.lms.start, '%H:%M')}" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
</div>
</div>
% if subsection.lms.start != parent_item.lms.start and subsection.lms.start:
% if parent_item.lms.start is None:
<p class="notice">The date above differs from the release date of ${parent_item.display_name_with_default}, which is unset.
% else:
<p class="notice">The date above differs from the release date of ${parent_item.display_name_with_default} –
${get_time_struct_display(parent_item.lms.start, '%m/%d/%Y at %I:%M %p')}.
${get_time_struct_display(parent_item.lms.start, '%m/%d/%Y at %H:%M UTC')}.
% endif
<a href="#" class="sync-date no-spinner">Sync to ${parent_item.display_name_with_default}.</a></p>
% endif
......@@ -56,14 +61,17 @@
</div>
<div class="due-date-input row">
<label>Due date:</label>
<a href="#" class="set-date">Set a due date</a>
<div class="datepair date-setter">
<p class="date-description">
<div class="field field-start-date">
<label for="due_date">Due Day</label>
<input type="text" id="due_date" name="due_date" value="${get_time_struct_display(subsection.lms.due, '%m/%d/%Y')}" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
</div>
<div class="field field-start-time">
<label for="due_time">Due Time (<abbr title="Coordinated Universal Time">UTC</abbr>)</label>
<input type="text" id="due_time" name="due_time" value="${get_time_struct_display(subsection.lms.due, '%H:%M')}" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
<a href="#" class="remove-date">Remove due date</a>
</p>
</div>
<a href="#" class="remove-date">Remove due date</a>
</div>
</div>
<div class="row unit-actions">
......
......@@ -148,13 +148,13 @@
<div class="section-published-date">
<%
start_date_str = get_time_struct_display(section.lms.start, '%m/%d/%Y')
start_time_str = get_time_struct_display(section.lms.start, '%I:%M %p')
start_time_str = get_time_struct_display(section.lms.start, '%H:%M')
%>
%if section.lms.start is None:
<span class="published-status">This section has not been released.</span>
<a href="#" class="schedule-button" data-date="" data-time="" data-id="${section.location}">Schedule</a>
%else:
<span class="published-status"><strong>Will Release:</strong> ${start_date_str} at ${start_time_str}</span>
<span class="published-status"><strong>Will Release:</strong> ${get_time_struct_display(section.lms.start, '%m/%d/%Y at %H:%M UTC')}</span>
<a href="#" class="edit-button" data-date="${start_date_str}" data-time="${start_time_str}" data-id="${section.location}">Edit</a>
%endif
</div>
......@@ -207,8 +207,15 @@
<div class="settings">
<h3>Section Release Date</h3>
<div class="picker datepair">
<input class="start-date date" type="text" name="start_date" value="" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
<input class="start-time time" type="text" name="start_time" value="" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
<div class="field field-start-date">
<label for="">Release Day</label>
<input class="start-date date" type="text" name="start_date" value="" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
</div>
<div class="field field-start-time">
<label for="">Release Time (<abbr title="Coordinated Universal Time">UTC</abbr>)</label>
<input class="start-time time" type="text" name="start_time" value="" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
</div>
<div class="description">
<p>On the date set above, this section – <strong class="section-name"></strong> – will be released to students. Any units marked private will only be visible to admins.</p>
</div>
......
......@@ -180,6 +180,7 @@ class CourseFields(object):
has_children = True
checklists = List(scope=Scope.settings)
info_sidebar_name = String(scope=Scope.settings, default='Course Handouts')
show_timezone = Boolean(help="True if timezones should be shown on dates in the courseware", scope=Scope.settings, default=True)
# An extra property is used rather than the wiki_slug/number because
# there are courses that change the number for different runs. This allows
......
......@@ -2,6 +2,7 @@ from datetime import datetime
from . import ModuleStoreBase, Location, namedtuple_to_son
from .exceptions import ItemNotFoundError
from .inheritance import own_metadata
import logging
DRAFT = 'draft'
......@@ -181,7 +182,7 @@ class DraftModuleStore(ModuleStoreBase):
draft.cms.published_by = published_by_id
super(DraftModuleStore, self).update_item(location, draft._model_data._kvs._data)
super(DraftModuleStore, self).update_children(location, draft._model_data._kvs._children)
super(DraftModuleStore, self).update_metadata(location, draft._model_data._kvs._metadata)
super(DraftModuleStore, self).update_metadata(location, own_metadata(draft))
self.delete_item(location)
def unpublish(self, location):
......
......@@ -171,7 +171,10 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
model_data = DbModel(kvs, class_, None, MongoUsage(self.course_id, location))
module = class_(self, location, model_data)
if self.cached_metadata is not None:
metadata_to_inherit = self.cached_metadata.get(location.url(), {})
# parent container pointers don't differentiate between draft and non-draft
# so when we do the lookup, we should do so with a non-draft location
non_draft_loc = location._replace(revision=None)
metadata_to_inherit = self.cached_metadata.get(non_draft_loc.url(), {})
inherit_metadata(module, metadata_to_inherit)
return module
except:
......@@ -277,6 +280,17 @@ class MongoModuleStore(ModuleStoreBase):
# now go through the results and order them by the location url
for result in resultset:
location = Location(result['_id'])
# We need to collate between draft and non-draft
# i.e. draft verticals can have children which are not in non-draft versions
location = location._replace(revision=None)
location_url = location.url()
if location_url in results_by_url:
existing_children = results_by_url[location_url].get('definition', {}).get('children', [])
additional_children = result.get('definition', {}).get('children', [])
total_children = existing_children + additional_children
if 'definition' not in results_by_url[location_url]:
results_by_url[location_url]['definition'] = {}
results_by_url[location_url]['definition']['children'] = total_children
results_by_url[location.url()] = result
if location.category == 'course':
root = location.url()
......@@ -288,17 +302,12 @@ class MongoModuleStore(ModuleStoreBase):
"""
Helper method for computing inherited metadata for a specific location url
"""
my_metadata = {}
# check for presence of metadata key. Note that a given module may not yet be fully formed.
# example: update_item -> update_children -> update_metadata sequence on new item create
# if we get called here without update_metadata called first then 'metadata' hasn't been set
# as we're not fully transactional at the DB layer. Same comment applies to below key name
# check
my_metadata = results_by_url[url].get('metadata', {})
for key in my_metadata.keys():
if key not in INHERITABLE_METADATA:
del my_metadata[key]
results_by_url[url]['metadata'] = my_metadata
# go through all the children and recurse, but only if we have
# in the result set. Remember results will not contain leaf nodes
......
......@@ -5,6 +5,7 @@ from xmodule.util import date_utils
import datetime
import time
def test_get_time_struct_display():
assert_equals("", date_utils.get_time_struct_display(None, ""))
test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
......@@ -15,12 +16,20 @@ def test_get_time_struct_display():
def test_get_default_time_display():
assert_equals("", date_utils.get_default_time_display(None))
test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
assert_equals("Mar 12, 1992 at 03:03 PM",
assert_equals(
"Mar 12, 1992 at 15:03 UTC",
date_utils.get_default_time_display(test_time))
assert_equals(
"Mar 12, 1992 at 15:03 UTC",
date_utils.get_default_time_display(test_time, True))
assert_equals(
"Mar 12, 1992 at 15:03",
date_utils.get_default_time_display(test_time, False))
def test_time_to_datetime():
assert_equals(None, date_utils.time_to_datetime(None))
test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
assert_equals(datetime.datetime(1992, 3, 12, 15, 3, 30),
assert_equals(
datetime.datetime(1992, 3, 12, 15, 3, 30),
date_utils.time_to_datetime(test_time))
......@@ -2,15 +2,18 @@ import time
import datetime
def get_default_time_display(time_struct):
def get_default_time_display(time_struct, show_timezone=True):
"""
Converts a time struct to a string representation. This is the default
representation used in Studio and LMS.
It is of the form "Apr 09, 2013 at 04:00 PM".
It is of the form "Apr 09, 2013 at 16:00" or "Apr 09, 2013 at 16:00 UTC",
depending on the value of show_timezone.
If None is passed in, an empty string will be returned.
If None is passed in for time_struct, an empty string will be returned.
The default value of show_timezone is True.
"""
return get_time_struct_display(time_struct, "%b %d, %Y at %I:%M %p")
timezone = "" if time_struct is None or not show_timezone else " UTC"
return get_time_struct_display(time_struct, "%b %d, %Y at %H:%M") + timezone
def get_time_struct_display(time_struct, format):
......
......@@ -24,7 +24,7 @@ $(function() {
$('.datepair input.time').each(function() {
var $this = $(this);
var opts = { 'showDuration': true, 'timeFormat': 'g:ia', 'scrollDefaultNow': true };
var opts = { 'showDuration': true, 'timeFormat': 'H:i', 'scrollDefaultNow': true };
if ($this.hasClass('start') || $this.hasClass('end')) {
opts.onSelect = doDatepair;
......
......@@ -19,6 +19,13 @@
</sequential>
</section>
<video name="Lost Video" youtube="1.0:TBvX7HzxexQ"/>
<sequential format="Lecture Sequence">
<vertical url_name='test_verical'>
<html url_name='test_html'>
Foobar
</html>
</vertical>
</sequential>
</chapter>
</course>
......@@ -12,7 +12,6 @@ from django.contrib.auth.decorators import login_required
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string
#from django.views.decorators.csrf import ensure_csrf_cookie
from django_future.csrf import ensure_csrf_cookie
from django.views.decorators.cache import cache_control
......@@ -67,9 +66,9 @@ def user_groups(user):
@ensure_csrf_cookie
@cache_if_anonymous
def courses(request):
'''
"""
Render "find courses" page. The course selection work is done in courseware.courses.
'''
"""
courses = get_courses(request.user, request.META.get('HTTP_HOST'))
courses = sort_by_announcement(courses)
......@@ -77,14 +76,16 @@ def courses(request):
def render_accordion(request, course, chapter, section, model_data_cache):
''' Draws navigation bar. Takes current position in accordion as
parameter.
"""
Draws navigation bar. Takes current position in accordion as
parameter.
If chapter and section are '' or None, renders a default accordion.
If chapter and section are '' or None, renders a default accordion.
course, chapter, and section are the url_names.
course, chapter, and section are the url_names.
Returns the html string'''
Returns the html string
"""
# grab the table of contents
user = User.objects.prefetch_related("groups").get(id=request.user.id)
......@@ -92,7 +93,8 @@ def render_accordion(request, course, chapter, section, model_data_cache):
context = dict([('toc', toc),
('course_id', course.id),
('csrf', csrf(request)['csrf_token'])] + template_imports.items())
('csrf', csrf(request)['csrf_token']),
('show_timezone', course.show_timezone)] + template_imports.items())
return render_to_string('courseware/accordion.html', context)
......@@ -166,10 +168,10 @@ def save_child_position(seq_module, child_name):
def check_for_active_timelimit_module(request, course_id, course):
'''
"""
Looks for a timing module for the given user and course that is currently active.
If found, returns a context dict with timer-related values to enable display of time remaining.
'''
"""
context = {}
# TODO (cpennington): Once we can query the course structure, replace this with such a query
......@@ -201,11 +203,11 @@ def check_for_active_timelimit_module(request, course_id, course):
def update_timelimit_module(user, course_id, model_data_cache, timelimit_descriptor, timelimit_module):
'''
"""
Updates the state of the provided timing module, starting it if it hasn't begun.
Returns dict with timer-related values to enable display of time remaining.
Returns 'timer_expiration_duration' in dict if timer is still active, and not if timer has expired.
'''
"""
context = {}
# determine where to go when the exam ends:
if timelimit_descriptor.time_expired_redirect_url is None:
......@@ -391,14 +393,14 @@ def index(request, course_id, chapter=None, section=None,
@ensure_csrf_cookie
def jump_to(request, course_id, location):
'''
"""
Show the page that contains a specific location.
If the location is invalid or not in any class, return a 404.
Otherwise, delegates to the index view to figure out whether this user
has access, and what they should see.
'''
"""
# Complain if the location isn't valid
try:
location = Location(location)
......@@ -486,7 +488,9 @@ def syllabus(request, course_id):
def registered_for_course(course, user):
'''Return CourseEnrollment if user is registered for course, else False'''
"""
Return CourseEnrollment if user is registered for course, else False
"""
if user is None:
return False
if user.is_authenticated():
......
......@@ -1157,7 +1157,7 @@ def dump_grading_context(course):
msg += "--> Section %s:\n" % (gs)
for sec in gsvals:
s = sec['section_descriptor']
format = getattr(s, 'format', None)
format = getattr(s.lms, 'format', None)
aname = ''
if format in graders:
g = graders[format]
......
......@@ -11,7 +11,7 @@
<li class="${'active' if 'active' in section and section['active'] else ''} ${'graded' if 'graded' in section and section['graded'] else ''}">
<a href="${reverse('courseware_section', args=[course_id, chapter['url_name'], section['url_name']])}">
<p>${section['display_name']}</p>
<p class="subtitle">${section['format']} ${"due " + get_default_time_display(section['due']) if section.get('due') is not None else ''}</p>
<p class="subtitle">${section['format']} ${"due " + get_default_time_display(section['due'], show_timezone) if section.get('due') is not None else ''}</p>
</a>
</li>
% endfor
......
......@@ -64,7 +64,7 @@ ${progress_graph.body(grade_summary, course.grade_cutoffs, "grade-detail-graph",
%if section.get('due') is not None:
<em>
due ${get_default_time_display(section['due'])}
due ${get_default_time_display(section['due'], course.show_timezone)}
</em>
%endif
</p>
......
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