diff --git a/admin/settings/appearance.php b/admin/settings/appearance.php index caf9e8af839..b971e30c0e4 100644 --- a/admin/settings/appearance.php +++ b/admin/settings/appearance.php @@ -227,6 +227,10 @@ preferences,moodle|/user/preferences.php|t/preferences', new lang_string('configcourseoverviewfileslimit', 'admin'), 1, PARAM_INT)); $temp->add(new admin_setting_configtext('courseoverviewfilesext', new lang_string('courseoverviewfilesext'), new lang_string('configcourseoverviewfilesext', 'admin'), '.jpg,.gif,.png')); + $temp->add(new admin_setting_configtext('coursegraceperiodbefore', new lang_string('coursegraceperiodbefore', 'admin'), + new lang_string('configcoursegraceperiodbefore', 'admin'), 0, PARAM_INT)); + $temp->add(new admin_setting_configtext('coursegraceperiodafter', new lang_string('coursegraceperiodafter', 'admin'), + new lang_string('configcoursegraceperiodafter', 'admin'), 0, PARAM_INT)); $ADMIN->add('appearance', $temp); $temp = new admin_settingpage('ajax', new lang_string('ajaxuse')); @@ -252,4 +256,3 @@ preferences,moodle|/user/preferences.php|t/preferences', $ADMIN->add('appearance', $temp); } // end of speedup - diff --git a/course/lib.php b/course/lib.php index 2db5dffcb51..1e0322f4057 100644 --- a/course/lib.php +++ b/course/lib.php @@ -4063,7 +4063,7 @@ function course_classify_for_timeline($course, $user = null, $completioninfo = n $today = time(); // End date past. - if (!empty($course->enddate) && $course->enddate < $today) { + if (!empty($course->enddate) && (course_classify_end_date($course) < $today)) { return COURSE_TIMELINE_PAST; } @@ -4077,7 +4077,7 @@ function course_classify_for_timeline($course, $user = null, $completioninfo = n } // Start date not reached. - if (!empty($course->startdate) && $course->startdate > $today) { + if (!empty($course->startdate) && (course_classify_start_date($course) > $today)) { return COURSE_TIMELINE_FUTURE; } @@ -4085,6 +4085,34 @@ function course_classify_for_timeline($course, $user = null, $completioninfo = n return COURSE_TIMELINE_INPROGRESS; } +/** + * This function calculates the end date to use for display classification purposes, + * incorporating the grace period, if any. + * + * @param stdClass $course The course record. + * @return int The new enddate. + */ +function course_classify_end_date($course) { + global $CFG; + $coursegraceperiodafter = (empty($CFG->coursegraceperiodafter)) ? 0 : $CFG->coursegraceperiodafter; + $enddate = (new \DateTimeImmutable())->setTimestamp($course->enddate)->modify("+{$coursegraceperiodafter} days"); + return $enddate->getTimestamp(); +} + +/** + * This function calculates the start date to use for display classification purposes, + * incorporating the grace period, if any. + * + * @param stdClass $course The course record. + * @return int The new startdate. + */ +function course_classify_start_date($course) { + global $CFG; + $coursegraceperiodbefore = (empty($CFG->coursegraceperiodbefore)) ? 0 : $CFG->coursegraceperiodbefore; + $startdate = (new \DateTimeImmutable())->setTimestamp($course->startdate)->modify("-{$coursegraceperiodbefore} days"); + return $startdate->getTimestamp(); +} + /** * Check module updates since a given time. * This function checks for updates in the module config, file areas, completion, grades, comments and ratings. diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php index 0174dab798a..463c8243980 100644 --- a/course/tests/courselib_test.php +++ b/course/tests/courselib_test.php @@ -3838,6 +3838,8 @@ class core_course_courselib_testcase extends advanced_testcase { require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php'); set_config('enablecompletion', COMPLETION_ENABLED); + set_config('coursegraceperiodbefore', 0); + set_config('coursegraceperiodafter', 0); $this->resetAfterTest(true); $this->setAdminUser(); @@ -3878,6 +3880,14 @@ class core_course_courselib_testcase extends advanced_testcase { $this->assertEquals(COURSE_TIMELINE_FUTURE, course_classify_for_timeline($futurecourse)); $this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($completedcourse)); $this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($inprogresscourse)); + + // Test grace period. + set_config('coursegraceperiodafter', 1); + set_config('coursegraceperiodbefore', 1); + $this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($pastcourse)); + $this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($futurecourse)); + $this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($completedcourse)); + $this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($inprogresscourse)); } /** diff --git a/lang/en/admin.php b/lang/en/admin.php index d2e61192c99..1c93d92f1a8 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -171,6 +171,8 @@ $string['configcalendarexportsalt'] = 'This random text is used for improving of $string['configcookiehttponly'] = 'Enables new PHP 5.2.0 feature - browsers are instructed to send cookie with real http requests only, cookies should not be accessible by scripting languages. This is not supported in all browsers and it may not be fully compatible with current code. It helps to prevent some types of XSS attacks.'; $string['configcookiesecure'] = 'If server is accepting only https connections it is recommended to enable sending of secure cookies. If enabled please make sure that web server is not accepting http:// or set up permanent redirection to https:// address and ideally send HSTS headers. When wwwroot address does not start with https:// this setting is ignored.'; $string['configcountry'] = 'If you set a country here, then this country will be selected by default on new user accounts. To force users to choose a country, just leave this unset.'; +$string['configcoursegraceperiodafter'] = 'Classify past courses as in progress for these many days after the course end date.'; +$string['configcoursegraceperiodbefore'] = 'Classify future courses as in progress for these many days prior to the course start date.'; $string['configcourseoverviewfilesext'] = 'A comma-separated list of allowed course summary files extensions.'; $string['configcourseoverviewfileslimit'] = 'The maximum number of files that can be attached to a course summary.'; $string['configcourserequestnotify'] = 'Type username of user to be notified when new course requested.'; @@ -380,6 +382,8 @@ $string['cookiesecure'] = 'Secure cookies only'; $string['country'] = 'Default country'; $string['coursecontact'] = 'Course contacts'; $string['coursecontact_desc'] = 'This setting allows you to control who appears on the course description. Users need to have at least one of these roles in a course to be shown on the course description for that course.'; +$string['coursegraceperiodafter'] = 'Grace period for past courses'; +$string['coursegraceperiodbefore'] = 'Grace period for future courses'; $string['courselistshortnames'] = 'Display extended course names'; $string['courselistshortnames_desc'] = 'If enabled, course short names will be displayed in addition to full names in course lists. If required, extended course names may be customised by editing the \'courseextendednamedisplay\' language string using the language customisation feature.'; $string['coursemgmt'] = 'Manage courses and categories';