Merge branch 'master' into feature/btalbot/studio-alerts
This commit is contained in:
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user