diff --git a/admin/tool/uploadcourse/classes/course.php b/admin/tool/uploadcourse/classes/course.php index de8c1459ce320..c08871776eb00 100644 --- a/admin/tool/uploadcourse/classes/course.php +++ b/admin/tool/uploadcourse/classes/course.php @@ -93,7 +93,7 @@ class tool_uploadcourse_course { protected $updatemode; /** @var array fields allowed as course data. */ - static protected $validfields = array('fullname', 'shortname', 'idnumber', 'category', 'visible', 'startdate', + static protected $validfields = array('fullname', 'shortname', 'idnumber', 'category', 'visible', 'startdate', 'enddate', 'summary', 'format', 'theme', 'lang', 'newsitems', 'showgrades', 'showreports', 'legacyfiles', 'maxbytes', 'groupmode', 'groupmodeforce', 'groupmodeforce', 'enablecompletion'); @@ -587,6 +587,11 @@ public function prepare() { $coursedata['startdate'] = strtotime($coursedata['startdate']); } + // Course end date. + if (!empty($coursedata['enddate'])) { + $coursedata['enddate'] = strtotime($coursedata['enddate']); + } + // Ultimate check mode vs. existence. switch ($mode) { case tool_uploadcourse_processor::MODE_CREATE_NEW: @@ -897,6 +902,10 @@ protected function reset($course) { } $resetdata->reset_start_date_old = $course->startdate; + if (empty($course->enddate)) { + $course->enddate = $DB->get_field_select('course', 'enddate', 'id = :id', array('id' => $course->id)); + } + // Add roles. $roles = tool_uploadcourse_helper::get_role_ids(); $resetdata->unenrol_users = array_values($roles); diff --git a/admin/tool/uploadcourse/classes/step2_form.php b/admin/tool/uploadcourse/classes/step2_form.php index 24f9a9e1f545b..ab3031c901530 100644 --- a/admin/tool/uploadcourse/classes/step2_form.php +++ b/admin/tool/uploadcourse/classes/step2_form.php @@ -95,6 +95,10 @@ public function definition () { $mform->addHelpButton('defaults[startdate]', 'startdate'); $mform->setDefault('defaults[startdate]', time() + 3600 * 24); + $mform->addElement('date_selector', 'defaults[enddate]', get_string('enddate')); + $mform->addHelpButton('defaults[enddate]', 'enddate'); + $mform->setDefault('defaults[enddate]', 0); + $courseformats = get_sorted_course_formats(true); $formcourseformats = array(); foreach ($courseformats as $courseformat) { diff --git a/admin/tool/uploadcourse/cli/uploadcourse.php b/admin/tool/uploadcourse/cli/uploadcourse.php index 511d6029828a6..3a7ef2a5099d2 100644 --- a/admin/tool/uploadcourse/cli/uploadcourse.php +++ b/admin/tool/uploadcourse/cli/uploadcourse.php @@ -156,6 +156,7 @@ $defaults = array(); $defaults['category'] = $options['category']; $defaults['startdate'] = time() + 3600 * 24; +$defaults['enddate'] = 0; $defaults['newsitems'] = $courseconfig->newsitems; $defaults['showgrades'] = $courseconfig->showgrades; $defaults['showreports'] = $courseconfig->showreports; diff --git a/admin/tool/uploadcourse/tests/course_test.php b/admin/tool/uploadcourse/tests/course_test.php index 6ae620c98ff46..a15de21e3fb79 100644 --- a/admin/tool/uploadcourse/tests/course_test.php +++ b/admin/tool/uploadcourse/tests/course_test.php @@ -245,6 +245,7 @@ public function test_data_saved() { 'category' => '1', 'visible' => '0', 'startdate' => '8 June 1990', + 'enddate' => '18 June 1990', 'idnumber' => '123abc', 'summary' => 'Summary', 'format' => 'weeks', @@ -282,6 +283,7 @@ public function test_data_saved() { $this->assertEquals($data['category'], $course->category); $this->assertEquals($data['visible'], $course->visible); $this->assertEquals(mktime(0, 0, 0, 6, 8, 1990), $course->startdate); + $this->assertEquals(mktime(0, 0, 0, 6, 18, 1990), $course->enddate); $this->assertEquals($data['idnumber'], $course->idnumber); $this->assertEquals($data['summary'], $course->summary); $this->assertEquals($data['format'], $course->format); @@ -334,6 +336,7 @@ public function test_data_saved() { 'category' => $cat->id, 'visible' => '1', 'startdate' => '11 June 1984', + 'enddate' => '31 June 1984', 'idnumber' => 'changeidn', 'summary' => 'Summary 2', 'format' => 'topics', @@ -370,6 +373,7 @@ public function test_data_saved() { $this->assertEquals($data['category'], $course->category); $this->assertEquals($data['visible'], $course->visible); $this->assertEquals(mktime(0, 0, 0, 6, 11, 1984), $course->startdate); + $this->assertEquals(mktime(0, 0, 0, 6, 31, 1984), $course->enddate); $this->assertEquals($data['idnumber'], $course->idnumber); $this->assertEquals($data['summary'], $course->summary); $this->assertEquals($data['format'], $course->format); @@ -425,6 +429,7 @@ public function test_default_data_saved() { 'category' => '1', 'visible' => '0', 'startdate' => 644803200, + 'enddate' => 645667200, 'idnumber' => '123abc', 'summary' => 'Summary', 'format' => 'weeks', @@ -452,6 +457,7 @@ public function test_default_data_saved() { $this->assertEquals($defaultdata['category'], $course->category); $this->assertEquals($defaultdata['visible'], $course->visible); $this->assertEquals($defaultdata['startdate'], $course->startdate); + $this->assertEquals($defaultdata['enddate'], $course->enddate); $this->assertEquals($defaultdata['idnumber'], $course->idnumber); $this->assertEquals($defaultdata['summary'], $course->summary); $this->assertEquals($defaultdata['format'], $course->format); @@ -478,6 +484,7 @@ public function test_default_data_saved() { 'category' => $cat->id, 'visible' => '1', 'startdate' => 455760000, + 'enddate' => 457488000, 'idnumber' => 'changedid', 'summary' => 'Summary 2', 'format' => 'topics', @@ -505,6 +512,7 @@ public function test_default_data_saved() { $this->assertEquals($defaultdata['category'], $course->category); $this->assertEquals($defaultdata['visible'], $course->visible); $this->assertEquals($defaultdata['startdate'], $course->startdate); + $this->assertEquals($defaultdata['enddate'], $course->enddate); $this->assertEquals($defaultdata['idnumber'], $course->idnumber); $this->assertEquals($defaultdata['summary'], $course->summary); $this->assertEquals($defaultdata['format'], $course->format); diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index ac786ede3657d..a51d34d74ef5d 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -375,7 +375,7 @@ protected function define_structure() { $course = new backup_nested_element('course', array('id', 'contextid'), array( 'shortname', 'fullname', 'idnumber', 'summary', 'summaryformat', 'format', 'showgrades', - 'newsitems', 'startdate', + 'newsitems', 'startdate', 'enddate', 'marker', 'maxbytes', 'legacyfiles', 'showreports', 'visible', 'groupmode', 'groupmodeforce', 'defaultgroupingid', 'lang', 'theme', @@ -1780,6 +1780,7 @@ protected function define_structure() { $info['original_course_fullname'] = $originalcourseinfo->fullname; $info['original_course_shortname'] = $originalcourseinfo->shortname; $info['original_course_startdate'] = $originalcourseinfo->startdate; + $info['original_course_enddate'] = $originalcourseinfo->enddate; $info['original_course_contextid'] = context_course::instance($this->get_courseid())->id; $info['original_system_contextid'] = context_system::instance()->id; @@ -1795,7 +1796,7 @@ protected function define_structure() { 'name', 'moodle_version', 'moodle_release', 'backup_version', 'backup_release', 'backup_date', 'mnet_remoteusers', 'include_files', 'include_file_references_to_external_content', 'original_wwwroot', 'original_site_identifier_hash', 'original_course_id', 'original_course_format', - 'original_course_fullname', 'original_course_shortname', 'original_course_startdate', + 'original_course_fullname', 'original_course_shortname', 'original_course_startdate', 'original_course_enddate', 'original_course_contextid', 'original_system_contextid')); $details = new backup_nested_element('details'); diff --git a/backup/moodle2/restore_course_task.class.php b/backup/moodle2/restore_course_task.class.php index 733ab1f95a908..20cdb0dba751c 100644 --- a/backup/moodle2/restore_course_task.class.php +++ b/backup/moodle2/restore_course_task.class.php @@ -172,6 +172,17 @@ protected function define_settings() { $startdate->set_ui(new backup_setting_ui_dateselector($startdate, get_string('setting_course_startdate', 'backup'))); $this->add_setting($startdate); + // Old versions may not have this data. + if (isset($this->get_info()->original_course_enddate)) { + $courseenddate = $this->get_info()->original_course_enddate; + } else { + $courseenddate = 0; + } + $enddate = new restore_course_generic_text_setting('course_enddate', + base_setting::IS_INTEGER, $courseenddate); + $enddate->set_ui(new backup_setting_ui_dateselector($enddate, get_string('setting_course_enddate', 'backup'))); + $this->add_setting($enddate); + $keep_enrols = new restore_course_generic_setting('keep_roles_and_enrolments', base_setting::IS_BOOLEAN, false); $keep_enrols->set_ui(new backup_setting_ui_select($keep_enrols, $keep_enrols->get_name(), array(1=>get_string('yes'), 0=>get_string('no')))); $keep_enrols->get_ui()->set_label(get_string('setting_keep_roles_and_enrolments', 'backup')); diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index e7e1ee29f6b56..dc3cc2b738bc2 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -1824,6 +1824,7 @@ public function process_course($data) { $fullname = $this->get_setting_value('course_fullname'); $shortname = $this->get_setting_value('course_shortname'); $startdate = $this->get_setting_value('course_startdate'); + $enddate = $this->get_setting_value('course_enddate'); // Calculate final course names, to avoid dupes. list($fullname, $shortname) = restore_dbops::calculate_course_names($this->get_courseid(), $fullname, $shortname); @@ -1893,6 +1894,9 @@ public function process_course($data) { $data->format = 'singleactivity'; $data->activitytype = 'scorm'; } + if (isset($data->enddate)) { + $data->enddate = $this->apply_date_offset($data->enddate); + } // Course record ready, update it $DB->update_record('course', $data); diff --git a/backup/util/checks/restore_check.class.php b/backup/util/checks/restore_check.class.php index dd71293ccc565..c4ef0b5ec1d43 100644 --- a/backup/util/checks/restore_check.class.php +++ b/backup/util/checks/restore_check.class.php @@ -203,6 +203,10 @@ public static function check_security($restore_controller, $apply) { $overwritesetting = $restore_controller->get_plan()->get_setting('overwrite_conf'); $overwritesetting->set_status(base_setting::LOCKED_BY_PERMISSION); } + $datesetting = $restore_controller->get_plan()->get_setting('course_enddate'); + if ($datesetting) { + $datesetting->set_status(base_setting::LOCKED_BY_PERMISSION); + } } return true; diff --git a/backup/util/dbops/backup_controller_dbops.class.php b/backup/util/dbops/backup_controller_dbops.class.php index 59bc3abc97798..ffaa34d016c19 100644 --- a/backup/util/dbops/backup_controller_dbops.class.php +++ b/backup/util/dbops/backup_controller_dbops.class.php @@ -530,7 +530,7 @@ public static function backup_includes_file_references($backupid) { */ public static function backup_get_original_course_info($courseid) { global $DB; - return $DB->get_record('course', array('id' => $courseid), 'fullname, shortname, startdate, format'); + return $DB->get_record('course', array('id' => $courseid), 'fullname, shortname, startdate, enddate, format'); } /** diff --git a/backup/util/helper/backup_general_helper.class.php b/backup/util/helper/backup_general_helper.class.php index 98b1f8911afc3..fd5a935d3606f 100644 --- a/backup/util/helper/backup_general_helper.class.php +++ b/backup/util/helper/backup_general_helper.class.php @@ -152,12 +152,16 @@ public static function get_backup_information($tempdir) { $info->mnet_remoteusers = $infoarr['mnet_remoteusers']; $info->original_wwwroot = $infoarr['original_wwwroot']; $info->original_site_identifier_hash = $infoarr['original_site_identifier_hash']; - $info->original_course_id = $infoarr['original_course_id']; - $info->original_course_fullname = $infoarr['original_course_fullname']; - $info->original_course_shortname= $infoarr['original_course_shortname']; - $info->original_course_startdate= $infoarr['original_course_startdate']; - $info->original_course_contextid= $infoarr['original_course_contextid']; - $info->original_system_contextid= $infoarr['original_system_contextid']; + $info->original_course_id = $infoarr['original_course_id']; + $info->original_course_fullname = $infoarr['original_course_fullname']; + $info->original_course_shortname = $infoarr['original_course_shortname']; + $info->original_course_startdate = $infoarr['original_course_startdate']; + // Old versions may not have this. + if (isset($infoarr['original_course_enddate'])) { + $info->original_course_enddate = $infoarr['original_course_enddate']; + } + $info->original_course_contextid = $infoarr['original_course_contextid']; + $info->original_system_contextid = $infoarr['original_system_contextid']; // Moodle backup file don't have this option before 2.3 if (!empty($infoarr['include_file_references_to_external_content'])) { $info->include_file_references_to_external_content = 1; diff --git a/course/edit_form.php b/course/edit_form.php index 7c9f43edf99fb..e6ec4045d6bd6 100644 --- a/course/edit_form.php +++ b/course/edit_form.php @@ -125,6 +125,9 @@ function definition() { $mform->addHelpButton('startdate', 'startdate'); $mform->setDefault('startdate', time() + 3600 * 24); + $mform->addElement('date_selector', 'enddate', get_string('enddate'), array('optional' => true)); + $mform->addHelpButton('enddate', 'enddate'); + $mform->addElement('text','idnumber', get_string('idnumbercourse'),'maxlength="100" size="10"'); $mform->addHelpButton('idnumber', 'idnumbercourse'); $mform->setType('idnumber', PARAM_RAW); @@ -392,6 +395,11 @@ function validation($data, $files) { } } + // Add field validation check for end date must be after start date. + if (($data['enddate'] > 0) && ($data['enddate'] < $data['startdate'])) { + $errors['enddate'] = get_string('enddatebeforstartdate', 'error'); + } + $errors = array_merge($errors, enrol_course_edit_validation($data, $this->context)); $courseformat = course_get_format((object)array('format' => $data['format'])); diff --git a/course/externallib.php b/course/externallib.php index 8b5025695e3de..ce137a5f9d5b0 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -441,6 +441,7 @@ public static function get_courses($options = array()) { external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0); $courseinfo['format'] = $course->format; $courseinfo['startdate'] = $course->startdate; + $courseinfo['enddate'] = $course->enddate; if (array_key_exists('numsections', $courseformatoptions)) { // For backward-compartibility $courseinfo['numsections'] = $courseformatoptions['numsections']; @@ -515,6 +516,8 @@ public static function get_courses_returns() { 'number of recent items appearing on the course page', VALUE_OPTIONAL), 'startdate' => new external_value(PARAM_INT, 'timestamp when the course start'), + 'enddate' => new external_value(PARAM_INT, + 'timestamp when the course end'), 'numsections' => new external_value(PARAM_INT, '(deprecated, use courseformatoptions) number of weeks/topics', VALUE_OPTIONAL), @@ -590,6 +593,8 @@ public static function create_courses_parameters() { VALUE_DEFAULT, $courseconfig->newsitems), 'startdate' => new external_value(PARAM_INT, 'timestamp when the course start', VALUE_OPTIONAL), + 'enddate' => new external_value(PARAM_INT, + 'timestamp when the course end', VALUE_OPTIONAL), 'numsections' => new external_value(PARAM_INT, '(deprecated, use courseformatoptions) number of weeks/topics', VALUE_OPTIONAL), @@ -765,6 +770,8 @@ public static function update_courses_parameters() { 'number of recent items appearing on the course page', VALUE_OPTIONAL), 'startdate' => new external_value(PARAM_INT, 'timestamp when the course start', VALUE_OPTIONAL), + 'enddate' => new external_value(PARAM_INT, + 'timestamp when the course end', VALUE_OPTIONAL), 'numsections' => new external_value(PARAM_INT, '(deprecated, use courseformatoptions) number of weeks/topics', VALUE_OPTIONAL), 'maxbytes' => new external_value(PARAM_INT, diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php index 2a49a47578556..73e10f97b5f04 100644 --- a/course/tests/externallib_test.php +++ b/course/tests/externallib_test.php @@ -383,7 +383,8 @@ public function test_create_courses() { $course2['format'] = 'weeks'; $course2['showgrades'] = 1; $course2['newsitems'] = 3; - $course2['startdate'] = 1420092000; // 01/01/2015 + $course2['startdate'] = 1420092000; // 01/01/2015. + $course2['enddate'] = 1422669600; // 01/31/2015. $course2['numsections'] = 4; $course2['maxbytes'] = 100000; $course2['showreports'] = 1; @@ -432,6 +433,7 @@ public function test_create_courses() { $this->assertEquals($courseinfo->showgrades, $course2['showgrades']); $this->assertEquals($courseinfo->newsitems, $course2['newsitems']); $this->assertEquals($courseinfo->startdate, $course2['startdate']); + $this->assertEquals($courseinfo->enddate, $course2['enddate']); $this->assertEquals($courseinfo->numsections, $course2['numsections']); $this->assertEquals($courseinfo->maxbytes, $course2['maxbytes']); $this->assertEquals($courseinfo->showreports, $course2['showreports']); @@ -597,6 +599,7 @@ public function test_get_courses () { $this->assertEquals($course['showgrades'], $dbcourse->showgrades); $this->assertEquals($course['newsitems'], $dbcourse->newsitems); $this->assertEquals($course['startdate'], $dbcourse->startdate); + $this->assertEquals($course['enddate'], $dbcourse->enddate); $this->assertEquals($course['numsections'], $dbcourse->numsections); $this->assertEquals($course['maxbytes'], $dbcourse->maxbytes); $this->assertEquals($course['showreports'], $dbcourse->showreports); @@ -1051,6 +1054,7 @@ public function test_update_courses() { $course2['showgrades'] = 1; $course2['newsitems'] = 3; $course2['startdate'] = 1420092000; // 01/01/2015. + $course2['enddate'] = 1422669600; // 01/31/2015. $course2['numsections'] = 4; $course2['maxbytes'] = 100000; $course2['showreports'] = 1; @@ -1086,6 +1090,7 @@ public function test_update_courses() { $this->assertEquals($course2['showgrades'], $courseinfo->showgrades); $this->assertEquals($course2['newsitems'], $courseinfo->newsitems); $this->assertEquals($course2['startdate'], $courseinfo->startdate); + $this->assertEquals($course2['enddate'], $courseinfo->enddate); $this->assertEquals($course2['numsections'], $courseinfo->numsections); $this->assertEquals($course2['maxbytes'], $courseinfo->maxbytes); $this->assertEquals($course2['showreports'], $courseinfo->showreports); diff --git a/lang/en/backup.php b/lang/en/backup.php index c3c432e663153..a3898b49b2f38 100644 --- a/lang/en/backup.php +++ b/lang/en/backup.php @@ -266,6 +266,7 @@ $string['setting_course_fullname'] = 'Course name'; $string['setting_course_shortname'] = 'Course short name'; $string['setting_course_startdate'] = 'Course start date'; +$string['setting_course_enddate'] = 'Course end date'; $string['setting_keep_roles_and_enrolments'] = 'Keep current roles and enrolments'; $string['setting_keep_groups_and_groupings'] = 'Keep current groups and groupings'; $string['showtypes'] = 'Show type options'; diff --git a/lang/en/error.php b/lang/en/error.php index 93db2e57ee616..8fae7d05c2fb5 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -223,6 +223,7 @@ $string['duplicateroleshortname'] = 'There is already a role with this short name!'; $string['duplicateusername'] = 'Duplicate username - skipping record'; $string['emailfail'] = 'Emailing failed'; +$string['enddatebeforstartdate'] = 'The end date must be after start date.'; $string['error'] = 'Error occurred'; $string['error_question_answers_missing_in_db'] = 'Failed to find an answer matching "{$a->answer}" in the question_answers database table. This occurred while restoring the question with id {$a->filequestionid} in the backup file, which has been matched to the existing question with id {$a->dbquestionid} in the database.'; $string['errorprocessingarchive'] = 'Error processing archive file'; diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 22c1ca3afbaf9..86a61b5854ed7 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -708,6 +708,8 @@ $string['emptydragdropregion'] = 'empty region'; $string['enable'] = 'Enable'; $string['encryptedcode'] = 'Encrypted code'; +$string['enddate'] = 'Course end date'; +$string['enddate_help'] = 'This setting determines the end of the course. Nothing special happens, but you can use on your reports and plugins.'; $string['english'] = 'English'; $string['enrolmentmethods'] = 'Enrolment methods'; $string['entercourse'] = 'Click to enter this course'; diff --git a/lib/coursecatlib.php b/lib/coursecatlib.php index 0c3afdecb5b58..1cd52699c439a 100644 --- a/lib/coursecatlib.php +++ b/lib/coursecatlib.php @@ -934,7 +934,7 @@ protected static function get_course_records($whereclause, $params, $options, $c $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $fields = array('c.id', 'c.category', 'c.sortorder', 'c.shortname', 'c.fullname', 'c.idnumber', - 'c.startdate', 'c.visible', 'c.cacherev'); + 'c.startdate', 'c.enddate', 'c.visible', 'c.cacherev'); if (!empty($options['summary'])) { $fields[] = 'c.summary'; $fields[] = 'c.summaryformat'; @@ -2745,6 +2745,7 @@ public static function can_approve_course_requests() { * @property-read int $showgrades Retrieved from DB on first request * @property-read int $newsitems Retrieved from DB on first request * @property-read int $startdate + * @property-read int $enddate * @property-read int $marker Retrieved from DB on first request * @property-read int $maxbytes Retrieved from DB on first request * @property-read int $legacyfiles Retrieved from DB on first request diff --git a/lib/db/install.xml b/lib/db/install.xml index c038172af5cb9..a10201b726ff8 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -81,6 +81,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 2dc080cf9f07f..be5b918adee3f 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2215,5 +2215,20 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2016091900.02); } + if ($oldversion < 2016092900.01) { + + // Define field enddate to be added to course. + $table = new xmldb_table('course'); + $field = new xmldb_field('enddate', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'startdate'); + + // Conditionally launch add field enddate. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2016092900.01); + } + return true; } diff --git a/version.php b/version.php index 3c09cea3d01b0..0ab7567123cdc 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2016092900.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2016092900.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.