Commit 9cf0b335 by Jose Antonio Gonzlez

Merge remote-tracking branch 'upstream/master' into…

Merge remote-tracking branch 'upstream/master' into proversity/add-recover-password-endpoint [ci skip]
parents 0decade2 c21895a8
...@@ -1188,11 +1188,17 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F ...@@ -1188,11 +1188,17 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
xblock_info.update({ xblock_info.update({
'hide_after_due': xblock.hide_after_due, 'hide_after_due': xblock.hide_after_due,
}) })
elif xblock.category == 'chapter': elif xblock.category in ('chapter', 'course'):
if xblock.category == 'chapter':
xblock_info.update({ xblock_info.update({
'highlights': xblock.highlights, 'highlights': xblock.highlights,
'highlights_enabled': highlights_setting.is_enabled(), })
elif xblock.category == 'course':
xblock_info.update({
'highlights_enabled_for_messaging': course.highlights_enabled_for_messaging, 'highlights_enabled_for_messaging': course.highlights_enabled_for_messaging,
})
xblock_info.update({
'highlights_enabled': highlights_setting.is_enabled(),
'highlights_preview_only': not COURSE_UPDATE_WAFFLE_FLAG.is_enabled(course.id), 'highlights_preview_only': not COURSE_UPDATE_WAFFLE_FLAG.is_enabled(course.id),
'highlights_doc_url': HelpUrlExpert.the_one().url_for_token('content_highlights'), 'highlights_doc_url': HelpUrlExpert.the_one().url_for_token('content_highlights'),
}) })
......
...@@ -2577,8 +2577,10 @@ class TestXBlockInfo(ItemTest): ...@@ -2577,8 +2577,10 @@ class TestXBlockInfo(ItemTest):
self.store.update_item(self.course, None) self.store.update_item(self.course, None)
chapter = self.store.get_item(self.chapter.location) chapter = self.store.get_item(self.chapter.location)
with highlights_setting.override(): with highlights_setting.override():
xblock_info = create_xblock_info(chapter) chapter_xblock_info = create_xblock_info(chapter)
self.assertTrue(xblock_info['highlights_enabled']) course_xblock_info = create_xblock_info(self.course)
self.assertTrue(chapter_xblock_info['highlights_enabled'])
self.assertTrue(course_xblock_info['highlights_enabled_for_messaging'])
def validate_course_xblock_info(self, xblock_info, has_child_info=True, course_outline=False): def validate_course_xblock_info(self, xblock_info, has_child_info=True, course_outline=False):
""" """
...@@ -2588,6 +2590,7 @@ class TestXBlockInfo(ItemTest): ...@@ -2588,6 +2590,7 @@ class TestXBlockInfo(ItemTest):
self.assertEqual(xblock_info['id'], unicode(self.course.location)) self.assertEqual(xblock_info['id'], unicode(self.course.location))
self.assertEqual(xblock_info['display_name'], self.course.display_name) self.assertEqual(xblock_info['display_name'], self.course.display_name)
self.assertTrue(xblock_info['published']) self.assertTrue(xblock_info['published'])
self.assertFalse(xblock_info['highlights_enabled_for_messaging'])
# Finally, validate the entire response for consistency # Finally, validate the entire response for consistency
self.validate_xblock_info_consistency(xblock_info, has_child_info=has_child_info, course_outline=course_outline) self.validate_xblock_info_consistency(xblock_info, has_child_info=has_child_info, course_outline=course_outline)
...@@ -2608,7 +2611,6 @@ class TestXBlockInfo(ItemTest): ...@@ -2608,7 +2611,6 @@ class TestXBlockInfo(ItemTest):
self.assertEqual(xblock_info['format'], None) self.assertEqual(xblock_info['format'], None)
self.assertEqual(xblock_info['highlights'], self.chapter.highlights) self.assertEqual(xblock_info['highlights'], self.chapter.highlights)
self.assertFalse(xblock_info['highlights_enabled']) self.assertFalse(xblock_info['highlights_enabled'])
self.assertFalse(xblock_info['highlights_enabled_for_messaging'])
# Finally, validate the entire response for consistency # Finally, validate the entire response for consistency
self.validate_xblock_info_consistency(xblock_info, has_child_info=has_child_info) self.validate_xblock_info_consistency(xblock_info, has_child_info=has_child_info)
......
...@@ -165,6 +165,7 @@ function(Backbone, _, str, ModuleUtils) { ...@@ -165,6 +165,7 @@ function(Backbone, _, str, ModuleUtils) {
*/ */
highlights: [], highlights: [],
highlights_enabled: false, highlights_enabled: false,
highlights_enabled_for_messaging: false,
highlights_preview_only: true, highlights_preview_only: true,
highlights_doc_url: '' highlights_doc_url: ''
}, },
......
define([
'jquery', 'underscore', 'backbone', 'js/views/utils/xblock_utils', 'js/utils/templates',
'js/views/modals/course_outline_modals', 'edx-ui-toolkit/js/utils/html-utils'],
function(
$, _, Backbone, XBlockViewUtils, TemplateUtils, CourseOutlineModalsFactory, HtmlUtils
) {
'use strict';
var CourseHighlightsEnableView = Backbone.View.extend({
events: {
'click button.status-highlights-enabled-value': 'handleEnableButtonPress',
'keypress button.status-highlights-enabled-value': 'handleEnableButtonPress'
},
initialize: function() {
this.template = TemplateUtils.loadTemplate('course-highlights-enable');
},
handleEnableButtonPress: function(event) {
if (event.type === 'click' || event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.highlightsEnableXBlock();
}
},
highlightsEnableXBlock: function() {
var modal = CourseOutlineModalsFactory.getModal('highlights_enable', this.model, {
onSave: this.refresh.bind(this),
xblockType: XBlockViewUtils.getXBlockType(
this.model.get('category')
)
});
if (modal) {
window.analytics.track('edx.bi.highlights_enable.modal_open');
modal.show();
}
},
refresh: function() {
this.model.fetch({
success: this.render.bind(this)
});
},
render: function() {
var html = this.template(this.model.attributes);
HtmlUtils.setHtml(this.$el, HtmlUtils.HTML(html));
return this;
}
});
return CourseHighlightsEnableView;
}
);
...@@ -17,7 +17,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', ...@@ -17,7 +17,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
AbstractEditor, BaseDateEditor, AbstractEditor, BaseDateEditor,
ReleaseDateEditor, DueDateEditor, GradingEditor, PublishEditor, AbstractVisibilityEditor, ReleaseDateEditor, DueDateEditor, GradingEditor, PublishEditor, AbstractVisibilityEditor,
StaffLockEditor, UnitAccessEditor, ContentVisibilityEditor, TimedExaminationPreferenceEditor, StaffLockEditor, UnitAccessEditor, ContentVisibilityEditor, TimedExaminationPreferenceEditor,
AccessEditor, ShowCorrectnessEditor, HighlightsEditor; AccessEditor, ShowCorrectnessEditor, HighlightsEditor, HighlightsEnableXBlockModal, HighlightsEnableEditor;
CourseOutlineXBlockModal = BaseModal.extend({ CourseOutlineXBlockModal = BaseModal.extend({
events: _.extend({}, BaseModal.prototype.events, { events: _.extend({}, BaseModal.prototype.events, {
...@@ -242,7 +242,11 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', ...@@ -242,7 +242,11 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
callAnalytics: function(event) { callAnalytics: function(event) {
event.preventDefault(); event.preventDefault();
window.analytics.track('edx.bi.highlights.' + event.target.innerText.toLowerCase()); window.analytics.track('edx.bi.highlights.' + event.target.innerText.toLowerCase());
if (event.target.className.indexOf('save') !== -1) {
this.save(event); this.save(event);
} else {
this.hide();
}
}, },
addActionButtons: function() { addActionButtons: function() {
...@@ -251,6 +255,44 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', ...@@ -251,6 +255,44 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
} }
}); });
HighlightsEnableXBlockModal = CourseOutlineXBlockModal.extend({
events: _.extend({}, CourseOutlineXBlockModal.prototype.events, {
'click .action-save': 'callAnalytics',
'click .action-cancel': 'callAnalytics'
}),
initialize: function() {
CourseOutlineXBlockModal.prototype.initialize.call(this);
if (this.options.xblockType) {
this.options.modalName = 'highlights-enable-' + this.options.xblockType;
}
},
getTitle: function() {
return gettext('Enable Weekly Course Highlight Messages');
},
getIntroductionMessage: function() {
return '';
},
callAnalytics: function(event) {
event.preventDefault();
window.analytics.track('edx.bi.highlights_enable.' + event.target.innerText.toLowerCase());
if (event.target.className.indexOf('save') !== -1) {
this.save(event);
} else {
this.hide();
}
},
addActionButtons: function() {
this.addActionButton('save', gettext('Enable'), true);
this.addActionButton('cancel', gettext('Not yet'));
}
});
AbstractEditor = BaseView.extend({ AbstractEditor = BaseView.extend({
tagName: 'section', tagName: 'section',
templateName: null, templateName: null,
...@@ -933,6 +975,42 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', ...@@ -933,6 +975,42 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
} }
}); });
HighlightsEnableEditor = AbstractEditor.extend({
templateName: 'highlights-enable-editor',
className: 'edit-enable-highlights',
currentValue: function() {
return true;
},
hasChanges: function() {
return this.model.get('highlights_enabled_for_messaging') !== this.currentValue();
},
getRequestData: function() {
if (this.hasChanges()) {
return {
publish: 'republish',
metadata: {
highlights_enabled_for_messaging: this.currentValue()
}
};
} else {
return {};
}
},
getContext: function() {
return $.extend(
{},
AbstractEditor.prototype.getContext.call(this),
{
highlights_enabled: this.model.get('highlights_enabled_for_messaging'),
highlights_doc_url: this.model.get('highlights_doc_url')
}
);
}
});
return { return {
getModal: function(type, xblockInfo, options) { getModal: function(type, xblockInfo, options) {
if (type === 'edit') { if (type === 'edit') {
...@@ -941,6 +1019,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', ...@@ -941,6 +1019,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
return this.getPublishModal(xblockInfo, options); return this.getPublishModal(xblockInfo, options);
} else if (type === 'highlights') { } else if (type === 'highlights') {
return this.getHighlightsModal(xblockInfo, options); return this.getHighlightsModal(xblockInfo, options);
} else if (type === 'highlights_enable') {
return this.getHighlightsEnableModal(xblockInfo, options);
} else { } else {
return null; return null;
} }
...@@ -1018,6 +1098,13 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', ...@@ -1018,6 +1098,13 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
editors: [HighlightsEditor], editors: [HighlightsEditor],
model: xblockInfo model: xblockInfo
}, options)); }, options));
},
getHighlightsEnableModal: function(xblockInfo, options) {
return new HighlightsEnableXBlockModal($.extend({
editors: [HighlightsEnableEditor],
model: xblockInfo
}, options));
} }
}; };
}); });
/** /**
* This page is used to show the user an outline of the course. * This page is used to show the user an outline of the course.
*/ */
define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'js/views/utils/xblock_utils', define([
'jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'js/views/utils/xblock_utils',
'js/views/course_outline', 'common/js/components/utils/view_utils', 'common/js/components/views/feedback_alert', 'js/views/course_outline', 'common/js/components/utils/view_utils', 'common/js/components/views/feedback_alert',
'common/js/components/views/feedback_notification'], 'common/js/components/views/feedback_notification', 'js/views/course_highlights_enable'],
function($, _, gettext, BasePage, XBlockViewUtils, CourseOutlineView, ViewUtils, AlertView, NoteView) { function($, _, gettext, BasePage, XBlockViewUtils, CourseOutlineView, ViewUtils, AlertView, NoteView,
CourseHighlightsEnableView
) {
'use strict';
var expandedLocators, CourseOutlinePage; var expandedLocators, CourseOutlinePage;
CourseOutlinePage = BasePage.extend({ CourseOutlinePage = BasePage.extend({
...@@ -65,6 +69,15 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'js/views ...@@ -65,6 +69,15 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'js/views
this.expandedLocators.addAll(this.initialState.expanded_locators); this.expandedLocators.addAll(this.initialState.expanded_locators);
} }
/* globals course */
if (this.model.get('highlights_enabled') && course.get('self_paced')) {
this.highlightsEnableView = new CourseHighlightsEnableView({
el: this.$('.status-highlights-enabled'),
model: this.model
});
this.highlightsEnableView.render();
}
this.outlineView = new CourseOutlineView({ this.outlineView = new CourseOutlineView({
el: this.$('.outline'), el: this.$('.outline'),
model: this.model, model: this.model,
......
...@@ -184,11 +184,13 @@ ...@@ -184,11 +184,13 @@
margin-bottom: $baseline; margin-bottom: $baseline;
.status-release, .status-release,
.status-pacing { .status-pacing,
.status-highlights-enabled {
@extend %t-copy-base; @extend %t-copy-base;
display: inline-block; display: inline-block;
color: $color-copy-base; color: $color-copy-base;
margin-right: $baseline;
// STATE: hover // STATE: hover
&:hover { &:hover {
...@@ -198,10 +200,17 @@ ...@@ -198,10 +200,17 @@
} }
} }
.status-highlights-enabled {
margin-left: $baseline * 1.6;
}
.status-release-label, .status-release-label,
.status-release-value, .status-release-value,
.status-pacing-label, .status-pacing-label,
.status-pacing-value, .status-pacing-value,
.status-highlights-enabled-label,
.status-highlights-enabled-value,
.status-highlights-enabled-info,
.status-actions { .status-actions {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
...@@ -209,13 +218,28 @@ ...@@ -209,13 +218,28 @@
} }
.status-release-label, .status-release-label,
.status-pacing-label { .status-pacing-label,
.status-highlights-enabled-label {
margin-right: ($baseline/4); margin-right: ($baseline/4);
} }
.status-release-value, .status-release-value,
.status-pacing-value { .status-pacing-value,
.status-highlights-enabled-value {
@extend %t-strong; @extend %t-strong;
font-size: smaller;
}
.status-highlights-enabled-info {
font-size: smaller;
margin-left: $baseline / 2;
}
.status-highlights-enabled-value.button {
@extend %btn-primary-blue;
@extend %sizing;
padding: 5px 8px;
margin-top: 2px;
} }
.status-actions { .status-actions {
......
...@@ -26,7 +26,7 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -26,7 +26,7 @@ from openedx.core.djangolib.markup import HTML, Text
<%block name="header_extras"> <%block name="header_extras">
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" /> <link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" />
% for template_name in ['course-outline', 'xblock-string-field-editor', 'basic-modal', 'modal-button', 'course-outline-modal', 'due-date-editor', 'release-date-editor', 'grading-editor', 'publish-editor', 'staff-lock-editor', 'unit-access-editor', 'content-visibility-editor', 'verification-access-editor', 'timed-examination-preference-editor', 'access-editor', 'settings-modal-tabs', 'show-correctness-editor', 'highlights-editor']: % for template_name in ['course-outline', 'xblock-string-field-editor', 'basic-modal', 'modal-button', 'course-outline-modal', 'due-date-editor', 'release-date-editor', 'grading-editor', 'publish-editor', 'staff-lock-editor', 'unit-access-editor', 'content-visibility-editor', 'verification-access-editor', 'timed-examination-preference-editor', 'access-editor', 'settings-modal-tabs', 'show-correctness-editor', 'highlights-editor', 'highlights-enable-editor', 'course-highlights-enable']:
<script type="text/template" id="${template_name}-tpl"> <script type="text/template" id="${template_name}-tpl">
<%static:include path="js/${template_name}.underscore" /> <%static:include path="js/${template_name}.underscore" />
</script> </script>
...@@ -152,7 +152,8 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -152,7 +152,8 @@ from openedx.core.djangolib.markup import HTML, Text
<article class="content-primary" role="main"> <article class="content-primary" role="main">
<div class="course-status"> <div class="course-status">
<div class="status-release"> <div class="status-release">
<h2 class="status-release-label">${_("Course Start Date:")}</h2> <h2 class="status-release-label">${_("Course Start Date")}</h2>
<br>
<p class="status-release-value">${course_release_date}</p> <p class="status-release-value">${course_release_date}</p>
<ul class="status-actions"> <ul class="status-actions">
...@@ -166,7 +167,8 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -166,7 +167,8 @@ from openedx.core.djangolib.markup import HTML, Text
</div> </div>
% if SelfPacedConfiguration.current().enabled: % if SelfPacedConfiguration.current().enabled:
<div class="status-pacing"> <div class="status-pacing">
<h2 class=status-pacing-label>${_("Course Pacing:")}</h2> <h2 class=status-pacing-label>${_("Course Pacing")}</h2>
<br>
% if context_course.self_paced: % if context_course.self_paced:
<p class="status-pacing-value">${_("Self-Paced")}</p> <p class="status-pacing-value">${_("Self-Paced")}</p>
% else: % else:
...@@ -174,6 +176,7 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -174,6 +176,7 @@ from openedx.core.djangolib.markup import HTML, Text
% endif % endif
</div> </div>
% endif % endif
<div class="status-highlights-enabled"></div>
</div> </div>
<div class="wrapper-dnd" <div class="wrapper-dnd"
% if getattr(context_course, 'language'): % if getattr(context_course, 'language'):
......
<div class="course-highlights-setting">
<h2 id="highlights-enabled-label" class="status-highlights-enabled-label">
<%- gettext('Weekly Highlight Emails') %>
</h2>
<br>
<% if (highlights_enabled_for_messaging) { %>
<span class="status-highlights-enabled-value text"><%- gettext('Enabled') %></span>
<% } else { %>
<button class="status-highlights-enabled-value button" aria-labelledby="highlights-enabled-label"><%- gettext('Enable Now') %></button>
<% } %>
<a class="status-highlights-enabled-info" href="<%- highlights_doc_url %>">Learn more</a>
</div>
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
'read our {linkStart}documentation{linkEnd}.' 'read our {linkStart}documentation{linkEnd}.'
), ),
{ {
linkStart: edx.HtmlUtils.HTML('<a href="' + highlights_doc_url + '">'), linkStart: edx.HtmlUtils.interpolateHtml(
edx.HtmlUtils.HTML('<a href={highlightsDocUrl}">'),
{highlightsDocUrl: highlights_doc_url}
),
linkEnd: edx.HtmlUtils.HTML('</a>') linkEnd: edx.HtmlUtils.HTML('</a>')
} }
) %> ) %>
......
<p>
<%- gettext(
'When you enable weekly course highlight messages, learners ' +
'automatically receive weekly email messages for each section that ' +
'has highlights. You cannot disable highlights after you start ' +
'sending them.'
) %>
</p>
<p>
<% // xss-lint: disable=underscore-not-escaped %>
<%= edx.HtmlUtils.interpolateHtml(
gettext(
'Are you sure you want to enable weekly course highlight messages? '
+ '{linkStart}Learn more.{linkEnd}'
),
{
linkStart: edx.HtmlUtils.interpolateHtml(
edx.HtmlUtils.HTML('<a href="{highlightsDocUrl}" target="_blank">'),
{highlightsDocUrl: xblockInfo.attributes.highlights_doc_url}
),
linkEnd: edx.HtmlUtils.HTML('</a>')
}
) %>
</p>
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
<div class="wrapper-content wrapper"> <div class="wrapper-content wrapper">
<section class="content"> <section class="content">
<article class="content-primary" role="main"> <article class="content-primary" role="main">
<div class=course-status"">
<div class="status-highlights-enabled"></div>
</div>
<div class="wrapper-dnd"> <div class="wrapper-dnd">
<article class="outline outline-course" data-locator="mock-course" data-course-key="slashes:MockCourse"> <article class="outline outline-course" data-locator="mock-course" data-course-key="slashes:MockCourse">
<div class="no-content add-xblock-component"> <div class="no-content add-xblock-component">
......
...@@ -5,6 +5,7 @@ Acceptance tests for studio related to the outline page. ...@@ -5,6 +5,7 @@ Acceptance tests for studio related to the outline page.
import itertools import itertools
import json import json
from datetime import datetime, timedelta from datetime import datetime, timedelta
from unittest import skip
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from pytz import UTC from pytz import UTC
...@@ -115,6 +116,7 @@ class CourseOutlineDragAndDropTest(CourseOutlineTest): ...@@ -115,6 +116,7 @@ class CourseOutlineDragAndDropTest(CourseOutlineTest):
expected_ordering expected_ordering
) )
@skip("Fails in Firefox 45 but passes in Chrome")
def test_drop_unit_in_collapsed_subsection(self): def test_drop_unit_in_collapsed_subsection(self):
""" """
Drag vertical "1.1.2" from subsection "1.1" into collapsed subsection "1.2" which already Drag vertical "1.1.2" from subsection "1.1" into collapsed subsection "1.2" which already
......
"""
Contains methods for accessing weekly course highlights. Weekly highlights is a
schedule experience built on the Schedules app.
"""
import logging
from courseware.module_render import get_module_for_descriptor from courseware.module_render import get_module_for_descriptor
from courseware.model_data import FieldDataCache from courseware.model_data import FieldDataCache
from openedx.core.djangoapps.schedules.config import COURSE_UPDATE_WAFFLE_FLAG from openedx.core.djangoapps.schedules.config import COURSE_UPDATE_WAFFLE_FLAG
...@@ -6,6 +12,8 @@ from request_cache import get_request_or_stub ...@@ -6,6 +12,8 @@ from request_cache import get_request_or_stub
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
log = logging.getLogger(__name__)
def course_has_highlights(course_key): def course_has_highlights(course_key):
""" """
...@@ -13,35 +21,63 @@ def course_has_highlights(course_key): ...@@ -13,35 +21,63 @@ def course_has_highlights(course_key):
This ignores access checks, since highlights may be lurking in currently This ignores access checks, since highlights may be lurking in currently
inaccessible content. inaccessible content.
""" """
if not COURSE_UPDATE_WAFFLE_FLAG.is_enabled(course_key): try:
course = _get_course_with_highlights(course_key)
except CourseUpdateDoesNotExist:
return False return False
course = modulestore().get_course(course_key, depth=1) else:
return any( highlights_are_available = any(
section.highlights section.highlights
for section in course.get_children() for section in course.get_children()
if not section.hide_from_toc if not section.hide_from_toc
) )
if not highlights_are_available:
log.error(
"Course team enabled highlights and provided no highlights."
)
return highlights_are_available
def get_week_highlights(user, course_key, week_num): def get_week_highlights(user, course_key, week_num):
""" """
Get highlights (list of unicode strings) for a given week. Get highlights (list of unicode strings) for a given week.
week_num starts at 1. week_num starts at 1.
Raises CourseUpdateDoesNotExist if highlights do not exist for
Raises:
CourseUpdateDoesNotExist: if highlights do not exist for
the requested week_num. the requested week_num.
""" """
course_descriptor = _get_course_with_highlights(course_key)
course_module = _get_course_module(course_descriptor, user)
sections_with_highlights = _get_sections_with_highlights(course_module)
highlights = _get_highlights_for_week(
sections_with_highlights,
week_num,
course_key,
)
return highlights
def _get_course_with_highlights(course_key):
# pylint: disable=missing-docstring
if not COURSE_UPDATE_WAFFLE_FLAG.is_enabled(course_key): if not COURSE_UPDATE_WAFFLE_FLAG.is_enabled(course_key):
raise CourseUpdateDoesNotExist( raise CourseUpdateDoesNotExist(
"%s does not have Course Updates enabled.", "%s Course Update Messages waffle flag is disabled.",
course_key course_key,
) )
course_descriptor = _get_course_descriptor(course_key) course_descriptor = _get_course_descriptor(course_key)
course_module = _get_course_module(course_descriptor, user) if not course_descriptor.highlights_enabled_for_messaging:
sections_with_highlights = _get_sections_with_highlights(course_module) raise CourseUpdateDoesNotExist(
highlights = _get_highlights_for_week(sections_with_highlights, week_num, course_key) "%s Course Update Messages are disabled.",
return highlights course_key,
)
return course_descriptor
def _get_course_descriptor(course_key): def _get_course_descriptor(course_key):
......
...@@ -21,7 +21,9 @@ class TestContentHighlights(ModuleStoreTestCase): ...@@ -21,7 +21,9 @@ class TestContentHighlights(ModuleStoreTestCase):
self._setup_user() self._setup_user()
def _setup_course(self): def _setup_course(self):
self.course = CourseFactory.create() self.course = CourseFactory.create(
highlights_enabled_for_messaging=True
)
self.course_key = self.course.id self.course_key = self.course.id
def _setup_user(self): def _setup_user(self):
...@@ -67,6 +69,23 @@ class TestContentHighlights(ModuleStoreTestCase): ...@@ -67,6 +69,23 @@ class TestContentHighlights(ModuleStoreTestCase):
) )
@override_waffle_flag(COURSE_UPDATE_WAFFLE_FLAG, True) @override_waffle_flag(COURSE_UPDATE_WAFFLE_FLAG, True)
def test_highlights_disabled_for_messaging(self):
highlights = [u'A test highlight.']
with self.store.bulk_operations(self.course_key):
self._create_chapter(highlights=highlights)
self.course.highlights_enabled_for_messaging = False
self.store.update_item(self.course, self.user.id)
self.assertFalse(course_has_highlights(self.course_key))
with self.assertRaises(CourseUpdateDoesNotExist):
get_week_highlights(
self.user,
self.course_key,
week_num=1,
)
@override_waffle_flag(COURSE_UPDATE_WAFFLE_FLAG, True)
def test_course_with_no_highlights(self): def test_course_with_no_highlights(self):
with self.store.bulk_operations(self.course_key): with self.store.bulk_operations(self.course_key):
self._create_chapter(display_name=u"Week 1") self._create_chapter(display_name=u"Week 1")
......
...@@ -47,7 +47,7 @@ edx-lint==0.4.3 ...@@ -47,7 +47,7 @@ edx-lint==0.4.3
astroid==1.3.8 astroid==1.3.8
edx-django-oauth2-provider==1.2.5 edx-django-oauth2-provider==1.2.5
edx-django-sites-extensions==2.3.0 edx-django-sites-extensions==2.3.0
edx-enterprise==0.53.16 edx-enterprise==0.53.18
edx-oauth2-provider==1.2.2 edx-oauth2-provider==1.2.2
edx-opaque-keys==0.4.0 edx-opaque-keys==0.4.0
edx-organizations==0.4.8 edx-organizations==0.4.8
...@@ -204,3 +204,6 @@ py2neo==3.1.2 ...@@ -204,3 +204,6 @@ py2neo==3.1.2
# Support for plugins # Support for plugins
web-fragments==0.2.2 web-fragments==0.2.2
xblock==1.0.0 xblock==1.0.0
# Redis version
redis==2.10.6
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