diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index 867963c17c..7ef262559b 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -22,6 +22,7 @@ from pytz import UTC from contentstore.config.waffle import ENABLE_PROCTORING_PROVIDER_OVERRIDES from contentstore.utils import reverse_course_url, reverse_usage_url +from course_modes.models import CourseMode from models.settings.course_grading import GRADING_POLICY_CHANGED_EVENT_TYPE, CourseGradingModel, hash_grading_policy from models.settings.course_metadata import CourseMetadata from models.settings.encoder import CourseSettingsEncoder @@ -179,6 +180,29 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): elif field in encoded and encoded[field] is not None: self.fail(field + " included in encoding but missing from details at " + context) + @ddt.data( + (False, False), + (True, False), + (True, True), + ) + @ddt.unpack + def test_upgrade_deadline(self, has_verified_mode, has_expiration_date): + if has_verified_mode: + deadline = None + if has_expiration_date: + deadline = self.course.start + datetime.timedelta(days=2) + CourseMode.objects.get_or_create( + course_id=self.course.id, + mode_display_name="Verified", + mode_slug="verified", + min_price=1, + _expiration_datetime=deadline, + ) + + settings_details_url = get_url(self.course.id) + response = self.client.get_html(settings_details_url) + self.assertEqual("Upgrade Deadline Date" in response.content, has_expiration_date and has_verified_mode) + @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True}) def test_pre_requisite_course_list_present(self): settings_details_url = get_url(self.course.id) diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 0c6dbf5331..16513ed128 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -54,6 +54,7 @@ from contentstore.views.entrance_exam import create_entrance_exam, delete_entran from course_action_state.managers import CourseActionStateItemNotFoundError from course_action_state.models import CourseRerunState, CourseRerunUIStateManager from course_creators.views import add_user_with_status_unrequested, get_course_creator_status +from course_modes.models import CourseMode from edxmako.shortcuts import render_to_response from models.settings.course_grading import CourseGradingModel from models.settings.course_metadata import CourseMetadata @@ -1066,6 +1067,10 @@ def settings_handler(request, course_key_string): sidebar_html_enabled = course_experience_waffle().is_enabled(ENABLE_COURSE_ABOUT_SIDEBAR_HTML) # self_paced_enabled = SelfPacedConfiguration.current().enabled + verified_mode = CourseMode.verified_mode_for_course(course_key) + upgrade_deadline = (verified_mode and verified_mode.expiration_datetime and + verified_mode.expiration_datetime.isoformat()) + settings_context = { 'context_course': course_module, 'course_locator': course_key, @@ -1086,7 +1091,8 @@ def settings_handler(request, course_key_string): 'enrollment_end_editable': enrollment_end_editable, 'is_prerequisite_courses_enabled': is_prerequisite_courses_enabled(), 'is_entrance_exams_enabled': is_entrance_exams_enabled(), - 'enable_extended_course_details': enable_extended_course_details + 'enable_extended_course_details': enable_extended_course_details, + 'upgrade_deadline': upgrade_deadline, } if is_prerequisite_courses_enabled(): courses, in_process_course_actions = get_courses_accessible_to_user(request) diff --git a/cms/static/js/factories/settings.js b/cms/static/js/factories/settings.js index 5e010e08c9..6ed11c4916 100644 --- a/cms/static/js/factories/settings.js +++ b/cms/static/js/factories/settings.js @@ -2,7 +2,7 @@ define([ 'jquery', 'js/models/settings/course_details', 'js/views/settings/main' ], function($, CourseDetailsModel, MainView) { 'use strict'; - return function(detailsUrl, showMinGradeWarning, showCertificateAvailableDate) { + return function(detailsUrl, showMinGradeWarning, showCertificateAvailableDate, upgradeDeadline) { var model; // highlighting labels when fields are focused in $('form :input') @@ -16,6 +16,7 @@ define([ model = new CourseDetailsModel(); model.urlRoot = detailsUrl; model.showCertificateAvailableDate = showCertificateAvailableDate; + model.set('upgrade_deadline', upgradeDeadline); model.fetch({ success: function(model) { var editor = new MainView({ diff --git a/cms/static/js/views/settings/main.js b/cms/static/js/views/settings/main.js index 358d6cbb08..03ddc9ace1 100644 --- a/cms/static/js/views/settings/main.js +++ b/cms/static/js/views/settings/main.js @@ -83,6 +83,7 @@ define(['js/views/validation', 'codemirror', 'underscore', 'jquery', 'jquery.ui' DateUtils.setupDatePicker('certificate_available_date', this); DateUtils.setupDatePicker('enrollment_start', this); DateUtils.setupDatePicker('enrollment_end', this); + DateUtils.setupDatePicker('upgrade_deadline', this); this.$el.find('#' + this.fieldToSelectorMap.overview).val(this.model.get('overview')); this.codeMirrorize(null, $('#course-overview')[0]); @@ -162,6 +163,7 @@ define(['js/views/validation', 'codemirror', 'underscore', 'jquery', 'jquery.ui' end_date: 'course-end', enrollment_start: 'enrollment-start', enrollment_end: 'enrollment-end', + upgrade_deadline: 'upgrade-deadline', certificate_available_date: 'certificate-available', overview: 'course-overview', title: 'course-title', diff --git a/cms/templates/settings.html b/cms/templates/settings.html index c78eb1eee3..5490afe738 100644 --- a/cms/templates/settings.html +++ b/cms/templates/settings.html @@ -39,7 +39,8 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url | n, js_escaped_string}' SettingsFactory( "${details_url | n, js_escaped_string}", ${show_min_grade_warning | n, dump_js_escaped_json}, - ${can_show_certificate_available_date_field(context_course) | n, dump_js_escaped_json} + ${can_show_certificate_available_date_field(context_course) | n, dump_js_escaped_json}, + "${upgrade_deadline | n, js_escaped_string}" ); }); @@ -203,9 +204,9 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url | n, js_escaped_string}' - +
- +

${_('Course Schedule')}

@@ -291,6 +292,27 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url | n, js_escaped_string}'
+ + % if upgrade_deadline: +
    +
  1. +
    + + + + ${_("Last day students can upgrade to a verified enrollment.")} + ${_("Contact your edX partner manager to update these settings.")} + +
    + +
    + + + ${_("(UTC)")} +
    +
  2. +
+ % endif % if about_page_editable: