feat: create feature flag for PLS custom pacing

This commit is contained in:
Sofia Yoon
2021-06-21 10:38:52 -04:00
parent 87a620612f
commit 4d96449134
10 changed files with 132 additions and 6 deletions

View File

@@ -67,3 +67,33 @@ REDIRECT_TO_LIBRARY_AUTHORING_MICROFRONTEND = LegacyWaffleFlag(
flag_name='library_authoring_mfe',
module_name=__name__,
)
# .. toggle_name: studio.pages_and_resources_mfe
# .. toggle_implementation: CourseWaffleFlag
# .. toggle_default: False
# .. toggle_description: Waffle flag to link existing studio views to the new Pages and Resources experience.
# .. toggle_use_cases: temporary, open_edx
# .. toggle_creation_date: 2021-05-24
# .. toggle_target_removal_date: 2021-12-31
# .. toggle_warnings: Also set settings.COURSE_AUTHORING_MICROFRONTEND_URL.
# .. toggle_tickets: None
ENABLE_PAGES_AND_RESOURCES_MICROFRONTEND = CourseWaffleFlag(
waffle_namespace=waffle_flags(),
flag_name='pages_and_resources_mfe',
module_name=__name__,
)
# .. toggle_name: studio.custom_pls
# .. toggle_implementation: CourseWaffleFlag
# .. toggle_default: False (except for SuperUsers)
# .. toggle_description: Waffle flag to enable custom pacing for PLS
# .. toggle_use_cases: temporary
# .. toggle_creation_date: 2021-06-15
# .. toggle_target_removal_date: 2021-12-31
# .. toggle_warnings: None
# .. toggle_tickets: None
CUSTOM_PLS = CourseWaffleFlag(WAFFLE_NAMESPACE, 'custom_pls', module_name=__name__,)
def custom_pls_is_active(course_key):
return CUSTOM_PLS.is_enabled(course_key)

View File

@@ -2,7 +2,7 @@
import logging
from collections import OrderedDict
from datetime import datetime
from datetime import datetime, timedelta
from functools import partial
from uuid import uuid4

View File

@@ -294,7 +294,7 @@ describe('CourseOutlinePage', function() {
TemplateHelpers.installTemplates([
'course-outline', 'xblock-string-field-editor', 'modal-button',
'basic-modal', 'course-outline-modal', 'release-date-editor',
'due-date-editor', 'grading-editor', 'publish-editor',
'due-date-editor', 'self-paced-due-date-editor', 'grading-editor', 'publish-editor',
'staff-lock-editor', 'unit-access-editor', 'content-visibility-editor',
'settings-modal-tabs', 'timed-examination-preference-editor', 'access-editor',
'show-correctness-editor', 'highlights-editor', 'highlights-enable-editor',

View File

@@ -17,7 +17,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
AbstractEditor, BaseDateEditor,
ReleaseDateEditor, DueDateEditor, GradingEditor, PublishEditor, AbstractVisibilityEditor,
StaffLockEditor, UnitAccessEditor, ContentVisibilityEditor, TimedExaminationPreferenceEditor,
AccessEditor, ShowCorrectnessEditor, HighlightsEditor, HighlightsEnableXBlockModal, HighlightsEnableEditor;
AccessEditor, ShowCorrectnessEditor, HighlightsEditor, HighlightsEnableXBlockModal, HighlightsEnableEditor,
SelfPacedDueDateEditor;
CourseOutlineXBlockModal = BaseModal.extend({
events: _.extend({}, BaseModal.prototype.events, {
@@ -74,6 +75,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
event.preventDefault();
requestData = this.getRequestData();
console.log(requestData)
if (!_.isEqual(requestData, {metadata: {}})) {
XBlockViewUtils.updateXBlockFields(this.model, requestData, {
success: this.options.onSave
@@ -389,6 +391,35 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
}
});
SelfPacedDueDateEditor = BaseDateEditor.extend({
fieldName: 'due',
templateName: 'self-paced-due-date-editor',
className: 'modal-section-content has-actions due-date-input grading-due-date',
getValue: function() {
return this.$('#due_date').val();
},
clearValue: function(event) {
event.preventDefault();
this.$('#due_date').val('');
},
getRequestData: function() {
let currentDate = parseInt(this.getValue())
if (parseInt(this.getValue())){
currentDate = new Date()
currentDate.setDate(currentDate.getDate() + parseInt(this.getValue())*7)
};
// due_num_weeks
return {
metadata: {
due: currentDate
}
};
}
});
ReleaseDateEditor = BaseDateEditor.extend({
fieldName: 'start',
templateName: 'release-date-editor',
@@ -1078,6 +1109,10 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
tabs[0].editors = [ReleaseDateEditor, GradingEditor, DueDateEditor];
tabs[1].editors = [ContentVisibilityEditor, ShowCorrectnessEditor];
if (course.get('self_paced')) {
tabs[0].editors.push(SelfPacedDueDateEditor)
}
if (options.enable_proctored_exams || options.enable_timed_exams) {
advancedTab.editors.push(TimedExaminationPreferenceEditor);
}

View File

@@ -29,7 +29,7 @@ from django.urls import reverse
<%block name="header_extras">
<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', 'highlights-enable-editor', 'course-highlights-enable']:
% for template_name in ['course-outline', 'xblock-string-field-editor', 'basic-modal', 'modal-button', 'course-outline-modal', 'due-date-editor', 'self-paced-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">
<%static:include path="js/${template_name}.underscore" />
</script>

View File

@@ -0,0 +1,16 @@
<ul class="list-fields list-input datepair date-setter">
<li class="field field-text field-due-date">
<label for="due_date"><%- gettext('Due in:') %></label>
<input type="number" id="due_date" name="due_date" value=""
placeholder="" autocomplete="off"/> weeks
</li>
</ul>
<ul class="list-actions">
<li class="action-item">
<a href="#" data-tooltip="<%- gettext('Clear Grading Due Date') %>" class="clear-date action-button action-clear">
<span class="icon fa fa-undo" aria-hidden="true"></span>
<span class="sr"><%- gettext('Clear Grading Due Date') %></span>
</a>
</li>
</ul>

View File

@@ -1051,7 +1051,7 @@ def allowed_metadata_by_category(category):
return {
'vertical': [],
'chapter': ['start'],
'sequential': ['due', 'format', 'start', 'graded']
'sequential': ['due', 'due_num_weeks', 'format', 'start', 'graded']
}.get(category, ['*'])

View File

@@ -79,6 +79,12 @@ class SequenceFields: # lint-amnesty, pylint: disable=missing-class-docstring
scope=Scope.settings,
)
due_num_weeks = Integer(
display_name = _("Number of Weeks Due By"),
help=_("Enter the number of weeks the problems are due by"),
scope = Scope.settings,
)
hide_after_due = Boolean(
display_name=_("Hide sequence content After Due Date"),
help=_(
@@ -195,6 +201,7 @@ class ProctoringFields:
default=False,
scope=Scope.settings,
)
def _get_course(self):
"""

View File

@@ -51,6 +51,7 @@ SUPPORTED_FIELDS = [
SupportedFieldType('format'),
SupportedFieldType('start'),
SupportedFieldType('due'),
SupportedFieldType('due_num_weeks'),
SupportedFieldType('contains_gated_content'),
SupportedFieldType('has_score'),
SupportedFieldType('has_scheduled_content'),

View File

@@ -1,8 +1,11 @@
"""Signal handlers for writing course dates into edx_when."""
from datetime import timedelta, datetime
import datetime
import logging
from cms.djangoapps.contentstore.config.waffle import custom_pls_is_active
from django.dispatch import receiver
from edx_when.api import FIELDS_TO_EXTRACT, set_dates_for_course
@@ -27,6 +30,11 @@ def _field_values(fields, xblock):
if field_name not in xblock.fields:
continue
field = xblock.fields[field_name]
if field_name == 'due':
print("THIS IS THE FIELD ", field)
print(xblock)
result[field.name] = field.read_from(xblock)
continue
if field.scope == Scope.settings and field.is_set_on(xblock):
try:
result[field.name] = field.read_from(xblock)
@@ -83,7 +91,34 @@ def extract_dates_from_course(course):
Extract all dates from the supplied course.
"""
log.info('Extracting course dates for %s', course.id)
if course.self_paced:
if course.self_paced and custom_pls_is_active(course.id):
print("This is self paced ")
date_items = []
store = modulestore()
with store.branch_setting(ModuleStoreEnum.Branch.published_only, course.id):
items = store.get_items(course.id)
log.info('Extracting dates from %d items in %s', len(items), course.id)
print("B4 the items sections")
# new_fields_to_extract = FIELDS_TO_EXTRACT + ('due_num_weeks',)
# print("THe new fields to extract ", new_fields_to_extract)
for item in items:
metadata = _field_values(FIELDS_TO_EXTRACT, item)
print("THIS IS THE METADATA ", metadata)
metadata['due'] = datetime.datetime.now() - metadata['due']
# print("TYPE OF DATES: ", metadata)
# print("RIGHT NOW, ", datetime.datetime.now())
# print(metadata['due'])
# metadata['due'] = datetime.datetime.now() - metadata['due']
# print('metadata due: ', metadata['due'])
metadata.pop('due_num_weeks',None)
# print("THIS IS THE DUE DATE: ", metadata['due'])
date_items.append((item.location, metadata))
# date_items.append((item.location, _field_values(FIELDS_TO_EXTRACT, item)))
print("Here are the date items: ", date_items)
elif course.self_paced and not custom_pls_is_active(course.id):
metadata = _field_values(FIELDS_TO_EXTRACT, course)
# self-paced courses may accidentally have a course due date
metadata.pop('due', None)
@@ -94,6 +129,7 @@ def extract_dates_from_course(course):
# unless that item already has a relative date set
for _, section, weeks_to_complete in spaced_out_sections(course):
section_date_items = []
print("THESE IS THE WEEKS TO COMPLETE ,", weeks_to_complete)
for subsection in section.get_children():
section_date_items.extend(_gather_graded_items(subsection, weeks_to_complete))
@@ -108,6 +144,7 @@ def extract_dates_from_course(course):
log.info('Extracting dates from %d items in %s', len(items), course.id)
for item in items:
date_items.append((item.location, _field_values(FIELDS_TO_EXTRACT, item)))
return date_items