Commit 720bde1d by Ibrahim Committed by Douglas Hall

add new text fields to schedule and details settings page

parent 31ca2a63
...@@ -245,6 +245,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): ...@@ -245,6 +245,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
self.assertContains(response, "Introducing Your Course") self.assertContains(response, "Introducing Your Course")
self.assertContains(response, "Course Image") self.assertContains(response, "Course Image")
self.assertContains(response, "Course Short Description") self.assertContains(response, "Course Short Description")
self.assertNotContains(response, "Course Title")
self.assertNotContains(response, "Course Subtitle")
self.assertNotContains(response, "Course Duration")
self.assertNotContains(response, "Course Description")
self.assertNotContains(response, "Course Overview") self.assertNotContains(response, "Course Overview")
self.assertNotContains(response, "Course Introduction Video") self.assertNotContains(response, "Course Introduction Video")
self.assertNotContains(response, "Requirements") self.assertNotContains(response, "Requirements")
...@@ -355,7 +359,8 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): ...@@ -355,7 +359,8 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
def test_regular_site_fetch(self): def test_regular_site_fetch(self):
settings_details_url = get_url(self.course.id) settings_details_url = get_url(self.course.id)
with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': False}): with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': False,
'ENABLE_EXTENDED_COURSE_DETAILS': True}):
response = self.client.get_html(settings_details_url) response = self.client.get_html(settings_details_url)
self.assertContains(response, "Course Summary Page") self.assertContains(response, "Course Summary Page")
self.assertContains(response, "Send a note to students via email") self.assertContains(response, "Send a note to students via email")
...@@ -369,6 +374,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): ...@@ -369,6 +374,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
self.assertContains(response, "Introducing Your Course") self.assertContains(response, "Introducing Your Course")
self.assertContains(response, "Course Image") self.assertContains(response, "Course Image")
self.assertContains(response, "Course Title")
self.assertContains(response, "Course Subtitle")
self.assertContains(response, "Course Duration")
self.assertContains(response, "Course Description")
self.assertContains(response, "Course Short Description") self.assertContains(response, "Course Short Description")
self.assertContains(response, "Course Overview") self.assertContains(response, "Course Overview")
self.assertContains(response, "Course Introduction Video") self.assertContains(response, "Course Introduction Video")
......
...@@ -976,11 +976,15 @@ def settings_handler(request, course_key_string): ...@@ -976,11 +976,15 @@ def settings_handler(request, course_key_string):
'ENABLE_MKTG_SITE', 'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False) settings.FEATURES.get('ENABLE_MKTG_SITE', False)
) )
enable_extended_course_details = microsite.get_value_for_org(
course_module.location.org,
'ENABLE_EXTENDED_COURSE_DETAILS',
settings.FEATURES.get('ENABLE_EXTENDED_COURSE_DETAILS', False)
)
about_page_editable = not marketing_site_enabled about_page_editable = not marketing_site_enabled
enrollment_end_editable = GlobalStaff().has_user(request.user) or not marketing_site_enabled enrollment_end_editable = GlobalStaff().has_user(request.user) or not marketing_site_enabled
short_description_editable = settings.FEATURES.get('EDITABLE_SHORT_DESCRIPTION', True) short_description_editable = settings.FEATURES.get('EDITABLE_SHORT_DESCRIPTION', True)
self_paced_enabled = SelfPacedConfiguration.current().enabled self_paced_enabled = SelfPacedConfiguration.current().enabled
settings_context = { settings_context = {
...@@ -1001,6 +1005,7 @@ def settings_handler(request, course_key_string): ...@@ -1001,6 +1005,7 @@ def settings_handler(request, course_key_string):
'is_prerequisite_courses_enabled': is_prerequisite_courses_enabled(), 'is_prerequisite_courses_enabled': is_prerequisite_courses_enabled(),
'is_entrance_exams_enabled': is_entrance_exams_enabled(), 'is_entrance_exams_enabled': is_entrance_exams_enabled(),
'self_paced_enabled': self_paced_enabled, 'self_paced_enabled': self_paced_enabled,
'enable_extended_course_details': enable_extended_course_details
} }
if is_prerequisite_courses_enabled(): if is_prerequisite_courses_enabled():
courses, in_process_course_actions = get_courses_accessible_to_user(request) courses, in_process_course_actions = get_courses_accessible_to_user(request)
......
...@@ -12,6 +12,10 @@ var CourseDetails = Backbone.Model.extend({ ...@@ -12,6 +12,10 @@ var CourseDetails = Backbone.Model.extend({
enrollment_start: null, enrollment_start: null,
enrollment_end: null, enrollment_end: null,
syllabus: null, syllabus: null,
title: "",
subtitle: "",
duration: "",
description: "",
short_description: "", short_description: "",
overview: "", overview: "",
intro_video: null, intro_video: null,
...@@ -32,9 +36,30 @@ var CourseDetails = Backbone.Model.extend({ ...@@ -32,9 +36,30 @@ var CourseDetails = Backbone.Model.extend({
newattrs, ["start_date", "end_date", "enrollment_start", "enrollment_end"] newattrs, ["start_date", "end_date", "enrollment_start", "enrollment_end"]
); );
if (newattrs.title.length > 50) {
errors.title = gettext("The title field must be limited to 50 characters.");
}
if (newattrs.subtitle.length > 150) {
errors.subtitle = gettext("The subtitle field must be limited to 150 characters.");
}
if (newattrs.duration.length > 50) {
errors.duration = gettext("The duration field must be limited to 50 characters.");
}
if (newattrs.short_description.length > 150) {
errors.short_description = gettext("The short description field must be limited to 150 characters.");
}
if (newattrs.description.length > 1000) {
errors.description = gettext("The description field must be limited to 1000 characters.");
}
if (newattrs.start_date === null) { if (newattrs.start_date === null) {
errors.start_date = gettext("The course must have an assigned start date."); errors.start_date = gettext("The course must have an assigned start date.");
} }
if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) { if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) {
errors.end_date = gettext("The course end date must be later than the course start date."); errors.end_date = gettext("The course end date must be later than the course start date.");
} }
......
...@@ -21,6 +21,10 @@ define([ ...@@ -21,6 +21,10 @@ define([
course_id : '', course_id : '',
run : '', run : '',
syllabus : null, syllabus : null,
title: '',
subtitle: '',
duration: '',
description: '',
short_description : '', short_description : '',
overview : '', overview : '',
intro_video : null, intro_video : null,
......
...@@ -71,6 +71,16 @@ var DetailsView = ValidatingView.extend({ ...@@ -71,6 +71,16 @@ var DetailsView = ValidatingView.extend({
this.$el.find('#' + this.fieldToSelectorMap['overview']).val(this.model.get('overview')); this.$el.find('#' + this.fieldToSelectorMap['overview']).val(this.model.get('overview'));
this.codeMirrorize(null, $('#course-overview')[0]); this.codeMirrorize(null, $('#course-overview')[0]);
if (this.model.get('title') !== '') {
this.$el.find('#' + this.fieldToSelectorMap.title).val(this.model.get('title'));
} else {
var displayName = this.$el.find('#' + this.fieldToSelectorMap.title).attr('data-display-name');
this.$el.find('#' + this.fieldToSelectorMap.title).val(displayName);
}
this.$el.find('#' + this.fieldToSelectorMap.subtitle).val(this.model.get('subtitle'));
this.$el.find('#' + this.fieldToSelectorMap.duration).val(this.model.get('duration'));
this.$el.find('#' + this.fieldToSelectorMap.description).val(this.model.get('description'));
this.$el.find('#' + this.fieldToSelectorMap['short_description']).val(this.model.get('short_description')); this.$el.find('#' + this.fieldToSelectorMap['short_description']).val(this.model.get('short_description'));
this.$el.find('.current-course-introduction-video iframe').attr('src', this.model.videosourceSample()); this.$el.find('.current-course-introduction-video iframe').attr('src', this.model.videosourceSample());
...@@ -126,6 +136,10 @@ var DetailsView = ValidatingView.extend({ ...@@ -126,6 +136,10 @@ var DetailsView = ValidatingView.extend({
'enrollment_start' : 'enrollment-start', 'enrollment_start' : 'enrollment-start',
'enrollment_end' : 'enrollment-end', 'enrollment_end' : 'enrollment-end',
'overview' : 'course-overview', 'overview' : 'course-overview',
'title': 'course-title',
'subtitle': 'course-subtitle',
'duration': 'course-duration',
'description': 'course-description',
'short_description' : 'course-short-description', 'short_description' : 'course-short-description',
'intro_video' : 'course-introduction-video', 'intro_video' : 'course-introduction-video',
'effort' : "course-effort", 'effort' : "course-effort",
...@@ -194,9 +208,6 @@ var DetailsView = ValidatingView.extend({ ...@@ -194,9 +208,6 @@ var DetailsView = ValidatingView.extend({
updateModel: function(event) { updateModel: function(event) {
switch (event.currentTarget.id) { switch (event.currentTarget.id) {
case 'course-language':
this.setField(event);
break;
case 'course-image-url': case 'course-image-url':
this.setField(event); this.setField(event);
var url = $(event.currentTarget).val(); var url = $(event.currentTarget).val();
...@@ -208,9 +219,6 @@ var DetailsView = ValidatingView.extend({ ...@@ -208,9 +219,6 @@ var DetailsView = ValidatingView.extend({
$('#course-image').attr('src', $(event.currentTarget).val()); $('#course-image').attr('src', $(event.currentTarget).val());
}, 1000); }, 1000);
break; break;
case 'course-effort':
this.setField(event);
break;
case 'entrance-exam-enabled': case 'entrance-exam-enabled':
if($(event.currentTarget).is(":checked")){ if($(event.currentTarget).is(":checked")){
this.$('.div-grade-requirements').show(); this.$('.div-grade-requirements').show();
...@@ -228,9 +236,6 @@ var DetailsView = ValidatingView.extend({ ...@@ -228,9 +236,6 @@ var DetailsView = ValidatingView.extend({
this.setField(event); this.setField(event);
} }
break; break;
case 'course-short-description':
this.setField(event);
break;
case 'pre-requisite-course': case 'pre-requisite-course':
var value = $(event.currentTarget).val(); var value = $(event.currentTarget).val();
value = value == "" ? [] : [value]; value = value == "" ? [] : [value];
...@@ -257,6 +262,15 @@ var DetailsView = ValidatingView.extend({ ...@@ -257,6 +262,15 @@ var DetailsView = ValidatingView.extend({
case 'course-pace-instructor-paced': case 'course-pace-instructor-paced':
this.model.set('self_paced', JSON.parse(event.currentTarget.value)); this.model.set('self_paced', JSON.parse(event.currentTarget.value));
break; break;
case 'course-language':
case 'course-effort':
case 'course-title':
case 'course-subtitle':
case 'course-duration':
case 'course-description':
case 'course-short-description':
this.setField(event);
break;
default: // Everything else is handled by datepickers and CodeMirror. default: // Everything else is handled by datepickers and CodeMirror.
break; break;
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
<script type="text/javascript"> <script type="text/javascript">
window.CMS = window.CMS || {}; window.CMS = window.CMS || {};
CMS.URL = CMS.URL || {}; CMS.URL = CMS.URL || {};
CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'; CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'
</script> </script>
</%block> </%block>
...@@ -292,9 +292,33 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'; ...@@ -292,9 +292,33 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
<span class="tip">${_("Information for prospective students")}</span> <span class="tip">${_("Information for prospective students")}</span>
</header> </header>
<ol class="list-input"> <ol class="list-input">
% if enable_extended_course_details:
<li class="field text" id="field-course-title">
<label for="course-title">${_("Course Title")}</label>
<input type="text" id="course-title" data-display-name="${context_course.display_name}">
<span class="tip tip-stacked">${_("Displayed as hero image overlay on the course details page. Limit to 50 characters.")}</span>
</li>
<li class="field text" id="field-course-subtitle">
<label for="course-subtitle">${_("Course Subtitle")}</label>
<input type="text" id="course-subtitle">
<span class="tip tip-stacked">${_("Displayed as hero image overlay on the course details page below the Course Title in a smaller font. Limit to 150 characters.")}</span>
</li>
<li class="field text" id="field-course-duration">
<label for="course-duration">${_("Course Duration")}</label>
<input type="text" id="course-duration">
<span class="tip tip-stacked">${_("Displayed on the course details page below the hero image. Limit to 50 characters.")}</span>
</li>
<li class="field text" id="field-course-description">
<label for="course-description">${_("Course Description")}</label>
<textarea class="text" id="course-description"></textarea>
<span class="tip tip-stacked">${_("Displayed on the course details page. Limit to 1000 characters.")}</span>
</li>
% endif
% if short_description_editable: % if short_description_editable:
<li class="field text" id="field-course-short-description"> <li class="field text" id="field-course-short-description">
<label for="course-overview">${_("Course Short Description")}</label> <label for="course-short-description">${_("Course Short Description")}</label>
<textarea class="text" id="course-short-description"></textarea> <textarea class="text" id="course-short-description"></textarea>
<span class="tip tip-stacked">${_("Appears on the course catalog page when students roll over the course name. Limit to ~150 characters")}</span> <span class="tip tip-stacked">${_("Appears on the course catalog page when students roll over the course name. Limit to ~150 characters")}</span>
</li> </li>
...@@ -315,7 +339,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'; ...@@ -315,7 +339,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
% endif % endif
<li class="field image" id="field-course-image"> <li class="field image" id="field-course-image">
<label>${_("Course Image")}</label> <label for="course-image-url">${_("Course Image")}</label>
<div class="current current-course-image"> <div class="current current-course-image">
% if context_course.course_image: % if context_course.course_image:
<span class="wrapper-course-image"> <span class="wrapper-course-image">
...@@ -346,7 +370,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'; ...@@ -346,7 +370,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
% if about_page_editable: % if about_page_editable:
<li class="field video" id="field-course-introduction-video"> <li class="field video" id="field-course-introduction-video">
<label for="course-overview">${_("Course Introduction Video")}</label> <label for="course-introduction-video">${_("Course Introduction Video")}</label>
<div class="input input-existing"> <div class="input input-existing">
<div class="current current-course-introduction-video"> <div class="current current-course-introduction-video">
<iframe width="618" height="350" title="${_('Course Introduction Video')}" src="" frameborder="0" allowfullscreen></iframe> <iframe width="618" height="350" title="${_('Course Introduction Video')}" src="" frameborder="0" allowfullscreen></iframe>
......
...@@ -475,3 +475,36 @@ class ContentLicenseTest(StudioCourseTest): ...@@ -475,3 +475,36 @@ class ContentLicenseTest(StudioCourseTest):
# The course_license text will include a bunch of screen reader text to explain # The course_license text will include a bunch of screen reader text to explain
# the selected options # the selected options
self.assertIn("Some Rights Reserved", self.lms_courseware.course_license) self.assertIn("Some Rights Reserved", self.lms_courseware.course_license)
@attr('a11y')
class StudioSettingsA11yTest(StudioCourseTest):
"""
Class to test Studio pages accessibility.
"""
def setUp(self): # pylint: disable=arguments-differ
super(StudioSettingsA11yTest, self).setUp()
self.settings_page = SettingsPage(self.browser, self.course_info['org'], self.course_info['number'],
self.course_info['run'])
def test_studio_settings_page_a11y(self):
"""
Check accessibility of SettingsPage.
"""
self.settings_page.visit()
self.settings_page.wait_for_page()
# There are several existing color contrast errors on this page,
# we will ignore this error in the test until we fix them.
self.settings_page.a11y_audit.config.set_rules({
"ignore": [
'color-contrast', # TODO: AC-225
'link-href', # TODO: AC-226
'nav-aria-label', # TODO: AC-227
'icon-aria-hidden', # TODO: AC-229
],
})
self.settings_page.a11y_audit.check_for_accessibility_errors()
...@@ -18,6 +18,10 @@ from xmodule.modulestore.django import modulestore ...@@ -18,6 +18,10 @@ from xmodule.modulestore.django import modulestore
# handled separately; its value maps to an alternate key name. # handled separately; its value maps to an alternate key name.
ABOUT_ATTRIBUTES = [ ABOUT_ATTRIBUTES = [
'syllabus', 'syllabus',
'title',
'subtitle',
'duration',
'description',
'short_description', 'short_description',
'overview', 'overview',
'effort', 'effort',
...@@ -43,6 +47,10 @@ class CourseDetails(object): ...@@ -43,6 +47,10 @@ class CourseDetails(object):
self.enrollment_start = None self.enrollment_start = None
self.enrollment_end = None self.enrollment_end = None
self.syllabus = None # a pdf file asset self.syllabus = None # a pdf file asset
self.title = ""
self.subtitle = ""
self.duration = ""
self.description = ""
self.short_description = "" self.short_description = ""
self.overview = "" # html to render as the overview self.overview = "" # html to render as the overview
self.intro_video = None # a video pointer self.intro_video = None # a video pointer
......
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