From f6b07feddeef28cfd196db14cf6bacbb4acc0f29 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 10 Jun 2015 07:32:06 -0700 Subject: [PATCH 1/9] MDL-31355 mod_forum: new db field for due and cutoff date --- mod/forum/db/install.xml | 4 +++- mod/forum/db/upgrade.php | 26 +++++++++++++++++++++++++- mod/forum/version.php | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/mod/forum/db/install.xml b/mod/forum/db/install.xml index 3c3cf624073..bf593194367 100644 --- a/mod/forum/db/install.xml +++ b/mod/forum/db/install.xml @@ -1,5 +1,5 @@ - @@ -12,6 +12,8 @@ + + diff --git a/mod/forum/db/upgrade.php b/mod/forum/db/upgrade.php index 978e8c95d74..9127de4fe96 100644 --- a/mod/forum/db/upgrade.php +++ b/mod/forum/db/upgrade.php @@ -43,7 +43,7 @@ defined('MOODLE_INTERNAL') || die(); function xmldb_forum_upgrade($oldversion) { - global $CFG, $DB; + global $DB; $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. @@ -118,5 +118,29 @@ function xmldb_forum_upgrade($oldversion) { upgrade_mod_savepoint(true, 2019031200, 'forum'); } + if ($oldversion < 2019040400) { + + $table = new xmldb_table('forum'); + + // Define field duedate to be added to forum. + $field = new xmldb_field('duedate', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'introformat'); + + // Conditionally launch add field duedate. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Define field cutoffdate to be added to forum. + $field = new xmldb_field('cutoffdate', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'duedate'); + + // Conditionally launch add field cutoffdate. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Forum savepoint reached. + upgrade_mod_savepoint(true, 2019040400, 'forum'); + } + return true; } diff --git a/mod/forum/version.php b/mod/forum/version.php index 52f7fce43dd..b84b45c4259 100644 --- a/mod/forum/version.php +++ b/mod/forum/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2019031300; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2019040400; // The current module version (Date: YYYYMMDDXX) $plugin->requires = 2018112800; // Requires this Moodle version $plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics) From ceea2d261858ab5da1ddd3b2a6489598b3507da1 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Thu, 4 Apr 2019 00:21:09 +1100 Subject: [PATCH 2/9] MDL-31355 mod_forum: Add duedate and cutoffdate to form AMOS BEGIN CPY [availability,mod_assign],[availability,mod_forum] CPY [cutoffdate,mod_assign],[cutoffdate,mod_forum] CPY [cutoffdatevalidation,mod_assign],[cutoffdatevalidation,mod_forum] CPY [duedate,mod_assign],[duedate,mod_forum] AMOS END --- mod/forum/lang/en/forum.php | 7 +++++++ mod/forum/mod_form.php | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 05c95c52f7c..1733e64da63 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -43,6 +43,7 @@ $string['attachment_help'] = 'You can optionally attach one or more files to a f $string['attachmentnopost'] = 'You cannot export attachments without a post id'; $string['attachments'] = 'Attachments'; $string['attachmentswordcount'] = 'Attachments and word count'; +$string['availability'] = 'Availability'; $string['blockafter'] = 'Post threshold for blocking'; $string['blockafter_help'] = 'This setting specifies the maximum number of posts which a user can post in the given time period. Users with the capability mod/forum:postwithoutthrottling are exempt from post limits.'; $string['blockperiod'] = 'Time period for blocking'; @@ -122,6 +123,9 @@ $string['couldnotadd'] = 'Could not add your post due to an unknown error'; $string['couldnotdeletereplies'] = 'Sorry, that cannot be deleted as people have already responded to it'; $string['couldnotupdate'] = 'Could not update your post due to an unknown error'; $string['crontask'] = 'Forum mailings and maintenance jobs'; +$string['cutoffdate'] = 'Cut-off date'; +$string['cutoffdate_help'] = 'If set, the forum will not accept posts after this date.'; +$string['cutoffdatevalidation'] = 'The cut-off date cannot be earlier than the due date.'; $string['delete'] = 'Delete'; $string['deleteddiscussion'] = 'The discussion topic has been deleted'; $string['deletedpost'] = 'The post has been deleted'; @@ -170,6 +174,9 @@ $string['displaystart'] = 'Display start'; $string['displaystart_help'] = 'This setting specifies whether a forum post should be displayed from a certain date. Note that administrators can always view forum posts.'; $string['displaywordcount'] = 'Display word count'; $string['displaywordcount_help'] = 'This setting specifies whether the word count of each post should be displayed or not.'; +$string['duedate'] = 'Due date'; +$string['duedate_help'] = 'This is when the forum is due. Although this date is displayed on the calendar as the due date for the forum, posting to the forum will still be allowed after this date. To prevent posting to the forum after a certain date - set the forum cut off date.'; +$string['duedatetodisplayincalendar'] = 'Due date to display in calendar'; $string['eachuserforum'] = 'Each person posts one discussion'; $string['edit'] = 'Edit'; $string['editedby'] = 'Edited by {$a->name} - original submission {$a->date}'; diff --git a/mod/forum/mod_form.php b/mod/forum/mod_form.php index decea410987..5a43c363eb6 100644 --- a/mod/forum/mod_form.php +++ b/mod/forum/mod_form.php @@ -54,6 +54,16 @@ class mod_forum_mod_form extends moodleform_mod { $mform->addHelpButton('type', 'forumtype', 'forum'); $mform->setDefault('type', 'general'); + $mform->addElement('header', 'availability', get_string('availability', 'forum')); + + $name = get_string('duedate', 'forum'); + $mform->addElement('date_time_selector', 'duedate', $name, array('optional' => true)); + $mform->addHelpButton('duedate', 'duedate', 'forum'); + + $name = get_string('cutoffdate', 'forum'); + $mform->addElement('date_time_selector', 'cutoffdate', $name, array('optional' => true)); + $mform->addHelpButton('cutoffdate', 'cutoffdate', 'forum'); + // Attachments and word count. $mform->addElement('header', 'attachmentswordcounthdr', get_string('attachmentswordcount', 'forum')); @@ -229,6 +239,18 @@ class mod_forum_mod_form extends moodleform_mod { } + public function validation($data, $files) { + $errors = parent::validation($data, $files); + + if ($data['duedate'] && $data['cutoffdate']) { + if ($data['duedate'] > $data['cutoffdate']) { + $errors['cutoffdate'] = get_string('cutoffdatevalidation', 'forum'); + } + } + + return $errors; + } + function data_preprocessing(&$default_values) { parent::data_preprocessing($default_values); From 0556f3937334097440a9161596cefbdf7c24bab9 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Thu, 4 Apr 2019 00:21:38 +1100 Subject: [PATCH 3/9] MDL-31355 mod_forum: backup and restore of duedate and cutoffdate fields --- mod/forum/backup/moodle2/backup_forum_stepslib.php | 2 +- mod/forum/backup/moodle2/restore_forum_stepslib.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mod/forum/backup/moodle2/backup_forum_stepslib.php b/mod/forum/backup/moodle2/backup_forum_stepslib.php index 63f45d9c6eb..7bc891faeb6 100644 --- a/mod/forum/backup/moodle2/backup_forum_stepslib.php +++ b/mod/forum/backup/moodle2/backup_forum_stepslib.php @@ -39,7 +39,7 @@ class backup_forum_activity_structure_step extends backup_activity_structure_ste // Define each element separated $forum = new backup_nested_element('forum', array('id'), array( - 'type', 'name', 'intro', 'introformat', + 'type', 'name', 'intro', 'introformat', 'duedate', 'cutoffdate', 'assessed', 'assesstimestart', 'assesstimefinish', 'scale', 'maxbytes', 'maxattachments', 'forcesubscribe', 'trackingtype', 'rsstype', 'rssarticles', 'timemodified', 'warnafter', diff --git a/mod/forum/backup/moodle2/restore_forum_stepslib.php b/mod/forum/backup/moodle2/restore_forum_stepslib.php index 771fd41af07..855e25c2c6f 100644 --- a/mod/forum/backup/moodle2/restore_forum_stepslib.php +++ b/mod/forum/backup/moodle2/restore_forum_stepslib.php @@ -62,6 +62,14 @@ class restore_forum_activity_structure_step extends restore_activity_structure_s // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. // See MDL-9367. + if (!isset($data->duedate)) { + $data->duedate = 0; + } + $data->duedate = $this->apply_date_offset($data->duedate); + if (!isset($data->cutoffdate)) { + $data->cutoffdate = 0; + } + $data->cutoffdate = $this->apply_date_offset($data->cutoffdate); $data->assesstimestart = $this->apply_date_offset($data->assesstimestart); $data->assesstimefinish = $this->apply_date_offset($data->assesstimefinish); if ($data->scale < 0) { // scale found, get mapping From bbbf1820896ed8c2dbda065167bc2db4cbcf4a30 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 13 Jun 2018 02:57:35 +1000 Subject: [PATCH 4/9] MDL-31355 mod_forum: Create, update and delete due date event --- mod/forum/lang/en/forum.php | 1 + mod/forum/lib.php | 8 +++- mod/forum/locallib.php | 55 ++++++++++++++++++++++- mod/forum/tests/locallib_test.php | 73 +++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 mod/forum/tests/locallib_test.php diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 1733e64da63..61494bf0dea 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -52,6 +52,7 @@ $string['blockperioddisabled'] = 'Don\'t block'; $string['blogforum'] = 'Standard forum displayed in a blog-like format'; $string['bynameondate'] = 'by {$a->name} - {$a->date}'; $string['cachedef_forum_is_tracked'] = 'Forum tracking status for user'; +$string['calendardue'] = '{$a} is due'; $string['cannotadd'] = 'Could not add the discussion for this forum'; $string['cannotadddiscussion'] = 'Adding discussions to this forum requires group membership.'; $string['cannotadddiscussionall'] = 'You do not have permission to add a new discussion topic for all participants.'; diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 361c6e70be4..cdecf8ae582 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -86,6 +86,8 @@ define('FORUM_DISCUSSION_UNPINNED', 0); function forum_add_instance($forum, $mform = null) { global $CFG, $DB; + require_once($CFG->dirroot.'/mod/forum/locallib.php'); + $forum->timemodified = time(); if (empty($forum->assessed)) { @@ -127,6 +129,7 @@ function forum_add_instance($forum, $mform = null) { } } + forum_update_calendar($forum, $forum->coursemodule); forum_grade_item_update($forum); $completiontimeexpected = !empty($forum->completionexpected) ? $forum->completionexpected : null; @@ -162,7 +165,9 @@ function forum_instance_created($context, $forum) { * @return bool success */ function forum_update_instance($forum, $mform) { - global $DB, $OUTPUT, $USER; + global $CFG, $DB, $OUTPUT, $USER; + + require_once($CFG->dirroot.'/mod/forum/locallib.php'); $forum->timemodified = time(); $forum->id = $forum->instance; @@ -249,6 +254,7 @@ function forum_update_instance($forum, $mform) { } } + forum_update_calendar($forum, $forum->coursemodule); forum_grade_item_update($forum); $completiontimeexpected = !empty($forum->completionexpected) ? $forum->completionexpected : null; diff --git a/mod/forum/locallib.php b/mod/forum/locallib.php index 6f57004d28c..ab333a993ae 100644 --- a/mod/forum/locallib.php +++ b/mod/forum/locallib.php @@ -1,5 +1,4 @@ dirroot . '/mod/forum/lib.php'); require_once($CFG->libdir . '/portfolio/caller.php'); @@ -700,3 +706,50 @@ function mod_forum_get_tagged_posts($tag, $exclusivemode = false, $fromctx = 0, $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages); } } + +/** + * Update the calendar entries for this forum activity. + * + * @param stdClass $forum the row from the database table forum. + * @param int $cmid The coursemodule id + * @return bool + */ +function forum_update_calendar($forum, $cmid) { + global $DB, $CFG; + + require_once($CFG->dirroot.'/calendar/lib.php'); + + $event = new stdClass(); + + if (!empty($forum->duedate)) { + $event->name = get_string('calendardue', 'forum', $forum->name); + $event->description = format_module_intro('forum', $forum, $cmid); + $event->courseid = $forum->course; + $event->modulename = 'forum'; + $event->instance = $forum->id; + $event->type = CALENDAR_EVENT_TYPE_ACTION; + $event->eventtype = FORUM_EVENT_TYPE_DUE; + $event->timestart = $forum->duedate; + $event->timesort = $forum->duedate; + $event->visible = instance_is_visible('forum', $forum); + } + + $event->id = $DB->get_field('event', 'id', + array('modulename' => 'forum', 'instance' => $forum->id, 'eventtype' => FORUM_EVENT_TYPE_DUE)); + + if ($event->id) { + $calendarevent = calendar_event::load($event->id); + if (!empty($forum->duedate)) { + // Calendar event exists so update it. + $calendarevent->update($event); + } else { + // Calendar event is no longer needed. + $calendarevent->delete(); + } + } else if (!empty($forum->duedate)) { + // Event doesn't exist so create one. + calendar_event::create($event); + } + + return true; +} \ No newline at end of file diff --git a/mod/forum/tests/locallib_test.php b/mod/forum/tests/locallib_test.php new file mode 100644 index 00000000000..4a03a0d1882 --- /dev/null +++ b/mod/forum/tests/locallib_test.php @@ -0,0 +1,73 @@ +. + +/** + * File containing the forum module local library function tests. + * + * @package mod_forum + * @category test + * @copyright 2018 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/mod/forum/lib.php'); + +/** + * Class mod_forum_locallib_testcase. + * + * @copyright 2018 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class mod_forum_locallib_testcase extends advanced_testcase { + public function test_forum_update_calendar() { + global $DB; + + $this->resetAfterTest(); + + $this->setAdminUser(); + + // Create a course. + $course = $this->getDataGenerator()->create_course(); + + // Create a forum activity. + $time = time(); + $forum = $this->getDataGenerator()->create_module('forum', + array( + 'course' => $course->id, + 'duedate' => $time + ) + ); + + // Check that there is now an event in the database. + $events = $DB->get_records('event'); + $this->assertCount(1, $events); + + // Get the event. + $event = reset($events); + + // Confirm the event is correct. + $this->assertEquals('forum', $event->modulename); + $this->assertEquals($forum->id, $event->instance); + $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type); + $this->assertEquals(FORUM_EVENT_TYPE_DUE, $event->eventtype); + $this->assertEquals($time, $event->timestart); + $this->assertEquals($time, $event->timesort); + } +} \ No newline at end of file From 99bcb318959adfaa8a6a6c23c1b5a781acc9636c Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 13 Jun 2018 03:08:14 +1000 Subject: [PATCH 5/9] MDL-31355 mod_forum: WS should return duedate and cutoffdate. --- mod/forum/externallib.php | 2 ++ mod/forum/upgrade.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mod/forum/externallib.php b/mod/forum/externallib.php index ba39260253d..a53e2c41ad9 100644 --- a/mod/forum/externallib.php +++ b/mod/forum/externallib.php @@ -127,6 +127,8 @@ class mod_forum_external extends external_api { 'intro' => new external_value(PARAM_RAW, 'The forum intro'), 'introformat' => new external_format_value('intro'), 'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL), + 'duedate' => new external_value(PARAM_INT, 'duedate for the user', VALUE_OPTIONAL), + 'cutoffdate' => new external_value(PARAM_INT, 'cutoffdate for the user', VALUE_OPTIONAL), 'assessed' => new external_value(PARAM_INT, 'Aggregate type'), 'assesstimestart' => new external_value(PARAM_INT, 'Assess start time'), 'assesstimefinish' => new external_value(PARAM_INT, 'Assess finish time'), diff --git a/mod/forum/upgrade.txt b/mod/forum/upgrade.txt index 0eba55f6a05..f275f7434f7 100644 --- a/mod/forum/upgrade.txt +++ b/mod/forum/upgrade.txt @@ -9,6 +9,8 @@ information provided here is intended especially for developers. * The get_forum_discussion_posts web service has been deprecated in favour of get_discussion_posts. * The forum_count_replies function has been deprecated in favour of get_reply_count_for_post_id_in_discussion_id in the Post vault. + * External function get_forums_by_courses now returns two additional fields "duedate" and "cutoffdate" containing the due date and the cutoff date + for posting to the forums respectively. === 3.6 === From cbf63d8efc874a1b6d9e66fbfde1c4ceb6352f4f Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Thu, 14 Jun 2018 14:13:23 +1000 Subject: [PATCH 6/9] MDL-31355 mod_forum: Prevent users from posting after cut-off date --- .../local/data_mappers/legacy/forum.php | 4 +- mod/forum/classes/local/entities/forum.php | 74 ++++++++++++++++- mod/forum/classes/local/factories/entity.php | 4 +- .../classes/local/managers/capability.php | 6 ++ .../classes/local/renderers/discussion.php | 12 +++ .../local/renderers/discussion_list.php | 12 +++ mod/forum/db/access.php | 10 +++ mod/forum/lang/en/forum.php | 3 + mod/forum/lib.php | 32 ++++++++ mod/forum/tests/entities_forum_test.php | 10 ++- mod/forum/tests/externallib_test.php | 27 ++++++ mod/forum/tests/lib_test.php | 82 ++++++++++++++++++- 12 files changed, 271 insertions(+), 5 deletions(-) diff --git a/mod/forum/classes/local/data_mappers/legacy/forum.php b/mod/forum/classes/local/data_mappers/legacy/forum.php index bc89b2c31f6..97aa7a9b2fd 100644 --- a/mod/forum/classes/local/data_mappers/legacy/forum.php +++ b/mod/forum/classes/local/data_mappers/legacy/forum.php @@ -69,7 +69,9 @@ class forum { 'completionreplies' => $forum->get_completion_replies(), 'completionposts' => $forum->get_completion_posts(), 'displaywordcount' => $forum->should_display_word_count(), - 'lockdiscussionafter' => $forum->get_lock_discussions_after() + 'lockdiscussionafter' => $forum->get_lock_discussions_after(), + 'duedate' => $forum->get_due_date(), + 'cutoffdate' => $forum->get_cutoff_date() ]; }, $forums); } diff --git a/mod/forum/classes/local/entities/forum.php b/mod/forum/classes/local/entities/forum.php index fe9e9395b30..34459634be5 100644 --- a/mod/forum/classes/local/entities/forum.php +++ b/mod/forum/classes/local/entities/forum.php @@ -99,6 +99,10 @@ class forum { private $displaywordcounts; /** @var bool $lockdiscussionafter Timestamp after which discussions should be locked */ private $lockdiscussionafter; + /** @var int $duedate Timestamp that represents the due date for forum posts */ + private $duedate; + /** @var int $cutoffdate Timestamp after which forum posts will no longer be accepted */ + private $cutoffdate; /** * Constructor @@ -132,6 +136,8 @@ class forum { * @param int $completionposts Completion posts * @param bool $displaywordcount Should display word counts in posts * @param int $lockdiscussionafter Timestamp after which discussions should be locked + * @param int $duedate Timestamp that represents the due date for forum posts + * @param int $cutoffdate Timestamp after which forum posts will no longer be accepted */ public function __construct( context $context, @@ -162,7 +168,9 @@ class forum { int $completionreplies, int $completionposts, bool $displaywordcount, - int $lockdiscussionafter + int $lockdiscussionafter, + int $duedate, + int $cutoffdate ) { $this->context = $context; $this->coursemodule = $coursemodule; @@ -193,6 +201,8 @@ class forum { $this->completionposts = $completionposts; $this->displaywordcount = $displaywordcount; $this->lockdiscussionafter = $lockdiscussionafter; + $this->duedate = $duedate; + $this->cutoffdate = $cutoffdate; } /** @@ -546,4 +556,66 @@ class forum { return (($discussion->get_time_modified() + $this->get_lock_discussions_after()) < time()); } + + /** + * Get the cutoff date. + * + * @return int + */ + public function get_cutoff_date() : int { + return $this->cutoffdate; + } + + /** + * Does the forum have a cutoff date? + * + * @return bool + */ + public function has_cutoff_date() : bool { + return !empty($this->get_cutoff_date()); + } + + /** + * Is the cutoff date for the forum reached? + * + * @return bool + */ + public function is_cutoff_date_reached() : bool { + if ($this->has_cutoff_date() && ($this->get_cutoff_date() < time())) { + return true; + } + + return false; + } + + /** + * Get the due date. + * + * @return int + */ + public function get_due_date() : int { + return $this->duedate; + } + + /** + * Does the forum have a due date? + * + * @return bool + */ + public function has_due_date() : bool { + return !empty($this->get_due_date()); + } + + /** + * Is the due date for the forum reached? + * + * @return bool + */ + public function is_due_date_reached() : bool { + if ($this->has_due_date() && ($this->get_due_date() < time())) { + return true; + } + + return false; + } } diff --git a/mod/forum/classes/local/factories/entity.php b/mod/forum/classes/local/factories/entity.php index b7f18379605..e3a322a672d 100644 --- a/mod/forum/classes/local/factories/entity.php +++ b/mod/forum/classes/local/factories/entity.php @@ -100,7 +100,9 @@ class entity { $record->completionreplies, $record->completionposts, $record->displaywordcount, - $record->lockdiscussionafter + $record->lockdiscussionafter, + $record->duedate, + $record->cutoffdate ); } diff --git a/mod/forum/classes/local/managers/capability.php b/mod/forum/classes/local/managers/capability.php index 23293e93473..8bc2046c7f1 100644 --- a/mod/forum/classes/local/managers/capability.php +++ b/mod/forum/classes/local/managers/capability.php @@ -110,6 +110,12 @@ class capability { return false; } + if ($this->forum->is_cutoff_date_reached()) { + if (!has_capability('mod/forum:canoverridecutoff', $this->get_context())) { + return false; + } + } + switch ($this->forum->get_type()) { case 'news': $capability = 'mod/forum:addnews'; diff --git a/mod/forum/classes/local/renderers/discussion.php b/mod/forum/classes/local/renderers/discussion.php index ca3e7db90d6..dcc59caffb0 100644 --- a/mod/forum/classes/local/renderers/discussion.php +++ b/mod/forum/classes/local/renderers/discussion.php @@ -377,6 +377,18 @@ class discussion { $forum = $this->forum; $renderer = $this->renderer; + if ($forum->is_cutoff_date_reached()) { + $notifications[] = (new notification( + get_string('cutoffdatereached', 'forum'), + notification::NOTIFY_INFO + ))->set_show_closebutton(); + } else if ($forum->has_due_date()) { + $notifications[] = (new notification( + get_string('thisforumhasduedate', 'forum', userdate($forum->get_due_date())), + notification::NOTIFY_INFO + ))->set_show_closebutton(); + } + if ($forum->is_discussion_locked($discussion)) { $notifications[] = (new notification( get_string('discussionlocked', 'forum'), diff --git a/mod/forum/classes/local/renderers/discussion_list.php b/mod/forum/classes/local/renderers/discussion_list.php index 7b7f0e02bae..f62a76986b4 100644 --- a/mod/forum/classes/local/renderers/discussion_list.php +++ b/mod/forum/classes/local/renderers/discussion_list.php @@ -327,6 +327,18 @@ class discussion_list { $renderer = $this->renderer; $capabilitymanager = $this->capabilitymanager; + if ($forum->is_cutoff_date_reached()) { + $notifications[] = (new notification( + get_string('cutoffdatereached', 'forum'), + notification::NOTIFY_INFO + ))->set_show_closebutton(); + } else if ($forum->has_due_date()) { + $notifications[] = (new notification( + get_string('thisforumhasduedate', 'forum', userdate($forum->get_due_date())), + notification::NOTIFY_INFO + ))->set_show_closebutton(); + } + if ($forum->has_blocking_enabled()) { $notifications[] = (new notification( get_string('thisforumisthrottled', 'forum', [ diff --git a/mod/forum/db/access.php b/mod/forum/db/access.php index 5e5244dbd6c..b9d201542cd 100644 --- a/mod/forum/db/access.php +++ b/mod/forum/db/access.php @@ -395,5 +395,15 @@ $capabilities = array( 'manager' => CAP_ALLOW ) ), + 'mod/forum:canoverridecutoff' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'mod/forum:canoverridediscussionlock' + ), ); diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 61494bf0dea..c898e519ff2 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -126,6 +126,7 @@ $string['couldnotupdate'] = 'Could not update your post due to an unknown error' $string['crontask'] = 'Forum mailings and maintenance jobs'; $string['cutoffdate'] = 'Cut-off date'; $string['cutoffdate_help'] = 'If set, the forum will not accept posts after this date.'; +$string['cutoffdatereached'] = 'The cut-off date for posting to this forum is reached so you can no longer post to it.'; $string['cutoffdatevalidation'] = 'The cut-off date cannot be earlier than the due date.'; $string['delete'] = 'Delete'; $string['deleteddiscussion'] = 'The discussion topic has been deleted'; @@ -235,6 +236,7 @@ $string['forum:addinstance'] = 'Add a new forum'; $string['forum:addnews'] = 'Add announcements'; $string['forum:addquestion'] = 'Add question'; $string['forum:allowforcesubscribe'] = 'Allow force subscribe'; +$string['forum:canoverridecutoff'] = 'Post to forums after their cut-off date'; $string['forum:canoverridediscussionlock'] = 'Reply to locked discussions'; $string['forumauthorhidden'] = 'Author (hidden)'; $string['forumblockingalmosttoomanyposts'] = 'You are approaching the posting threshold. You have posted {$a->numposts} times in the last {$a->blockperiod} and the limit is {$a->blockafter} posts.'; @@ -587,6 +589,7 @@ $string['subscriptions'] = 'Subscriptions'; $string['tagarea_forum_posts'] = 'Forum posts'; $string['tagsdeleted'] = 'Forum tags have been deleted'; $string['thisforumisthrottled'] = 'This forum has a limit to the number of forum postings you can make in a given time period - this is currently set at {$a->blockafter} posting(s) in {$a->blockperiod}'; +$string['thisforumhasduedate'] = 'The due date for posting to this forum is {$a}.'; $string['timedhidden'] = 'Timed status: Hidden from students'; $string['timedposts'] = 'Timed posts'; $string['timedvisible'] = 'Timed status: Visible to all users'; diff --git a/mod/forum/lib.php b/mod/forum/lib.php index cdecf8ae582..d7c8851b2ab 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -3703,6 +3703,12 @@ function forum_user_can_post_discussion($forum, $currentgroup=null, $unused=-1, $context = context_module::instance($cm->id); } + if (forum_is_cutoff_date_reached($forum)) { + if (!has_capability('mod/forum:canoverridecutoff', $context)) { + return false; + } + } + if ($currentgroup === null) { $currentgroup = groups_get_activity_group($cm); } @@ -3796,6 +3802,12 @@ function forum_user_can_post($forum, $discussion, $user=NULL, $cm=NULL, $course= $context = context_module::instance($cm->id); } + if (forum_is_cutoff_date_reached($forum)) { + if (!has_capability('mod/forum:canoverridecutoff', $context)) { + return false; + } + } + // Check whether the discussion is locked. if (forum_discussion_is_locked($forum, $discussion)) { if (!has_capability('mod/forum:canoverridediscussionlock', $context)) { @@ -6305,6 +6317,26 @@ function mod_forum_inplace_editable($itemtype, $itemid, $newvalue) { } } +/** + * Determine whether the specified forum's cutoff date is reached. + * + * @param stdClass $forum The forum + * @return bool + */ +function forum_is_cutoff_date_reached($forum) { + $entityfactory = \mod_forum\local\container::get_entity_factory(); + $coursemoduleinfo = get_fast_modinfo($forum->course); + $cminfo = $coursemoduleinfo->instances['forum'][$forum->id]; + $forumentity = $entityfactory->get_forum_from_stdclass( + $forum, + context_module::instance($cminfo->id), + $cminfo->get_course_module_record(), + $cminfo->get_course() + ); + + return $forumentity->is_cutoff_date_reached(); +} + /** * Determine whether the specified discussion is time-locked. * diff --git a/mod/forum/tests/entities_forum_test.php b/mod/forum/tests/entities_forum_test.php index 43071f911dd..0bbfb62efaf 100644 --- a/mod/forum/tests/entities_forum_test.php +++ b/mod/forum/tests/entities_forum_test.php @@ -92,6 +92,8 @@ class mod_forum_entities_forum_testcase extends advanced_testcase { $completionposts = 0; $displaywordcount = false; $lockdiscussionafter = 0; + $duedate = 0; + $cutoffdate = 0; $forum = new forum_entity( $context, @@ -122,7 +124,9 @@ class mod_forum_entities_forum_testcase extends advanced_testcase { $completionreplies, $completionposts, $displaywordcount, - $lockdiscussionafter + $lockdiscussionafter, + $duedate, + $cutoffdate ); $this->assertEquals($context, $forum->get_context()); @@ -160,5 +164,9 @@ class mod_forum_entities_forum_testcase extends advanced_testcase { $this->assertEquals($lockdiscussionafter, $forum->get_lock_discussions_after()); $this->assertEquals(false, $forum->has_lock_discussions_after()); $this->assertEquals(false, $forum->is_discussion_locked($discussion)); + $this->assertEquals(false, $forum->has_due_date()); + $this->assertEquals(false, $forum->is_due_date_reached()); + $this->assertEquals(false, $forum->has_cutoff_date()); + $this->assertEquals(false, $forum->is_cutoff_date_reached()); } } diff --git a/mod/forum/tests/externallib_test.php b/mod/forum/tests/externallib_test.php index 8fa9dceb49e..7017f17d5b8 100644 --- a/mod/forum/tests/externallib_test.php +++ b/mod/forum/tests/externallib_test.php @@ -1458,7 +1458,34 @@ class mod_forum_external_testcase extends externallib_advanced_testcase { $this->assertTrue($result['status']); $this->assertTrue($result['canpindiscussions']); $this->assertTrue($result['cancreateattachment']); + } + /* + * A basic test to make sure users cannot post to forum after the cutoff date. + */ + public function test_can_add_discussion_after_cutoff() { + $this->resetAfterTest(true); + + // Create courses to add the modules. + $course = self::getDataGenerator()->create_course(); + + $user = self::getDataGenerator()->create_user(); + + // Create a forum with cutoff date set to a past date. + $forum = self::getDataGenerator()->create_module('forum', ['course' => $course->id, 'cutoffdate' => time() - 1]); + + // User with no mod/forum:canoverridecutoff capability. + self::setUser($user); + $this->getDataGenerator()->enrol_user($user->id, $course->id); + + $result = mod_forum_external::can_add_discussion($forum->id); + $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result); + $this->assertFalse($result['status']); + + self::setAdminUser(); + $result = mod_forum_external::can_add_discussion($forum->id); + $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result); + $this->assertTrue($result['status']); } /** diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php index a6a8c8a4f9a..88f77327298 100644 --- a/mod/forum/tests/lib_test.php +++ b/mod/forum/tests/lib_test.php @@ -2200,7 +2200,7 @@ class mod_forum_lib_testcase extends advanced_testcase { * Test forum_user_can_post_discussion */ public function test_forum_user_can_post_discussion() { - global $CFG, $DB; + global $DB; $this->resetAfterTest(true); @@ -2297,6 +2297,40 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->assertTrue($can); } + /** + * Test forum_user_can_post_discussion_after_cutoff + */ + public function test_forum_user_can_post_discussion_after_cutoff() { + $this->resetAfterTest(true); + + // Create course to add the module. + $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1)); + $student = self::getDataGenerator()->create_user(); + $teacher = self::getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student->id, $course->id); + $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher'); + + // Forum forcing separate gropus. + $record = new stdClass(); + $record->course = $course->id; + $record->cutoffdate = time() - 1; + $forum = self::getDataGenerator()->create_module('forum', $record); + $cm = get_coursemodule_from_instance('forum', $forum->id); + $context = context_module::instance($cm->id); + + self::setUser($student); + + // Students usually don't have the mod/forum:canoverridecutoff capability. + $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); + $this->assertFalse($can); + + self::setUser($teacher); + + // Teachers usually have the mod/forum:canoverridecutoff capability. + $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); + $this->assertTrue($can); + } + /** * Test forum_user_has_posted_discussion with no groups. */ @@ -3138,6 +3172,52 @@ class mod_forum_lib_testcase extends advanced_testcase { ]; } + /** + * Test the forum_is_cutoff_date_reached function. + * + * @dataProvider forum_is_cutoff_date_reached_provider + * @param array $forum + * @param bool $expect + */ + public function test_forum_is_cutoff_date_reached($forum, $expect) { + $this->resetAfterTest(); + + $datagenerator = $this->getDataGenerator(); + $course = $datagenerator->create_course(); + $forum = $datagenerator->create_module('forum', (object) array_merge([ + 'course' => $course->id + ], $forum)); + + $this->assertEquals($expect, forum_is_cutoff_date_reached($forum)); + } + + /** + * Dataprovider for forum_is_cutoff_date_reached tests. + * + * @return array + */ + public function forum_is_cutoff_date_reached_provider() { + $now = time(); + return [ + 'cutoffdate is unset' => [ + [], + false + ], + 'cutoffdate is 0' => [ + ['cutoffdate' => 0], + false + ], + 'cutoffdate is set and is in future' => [ + ['cutoffdate' => $now + 86400], + false + ], + 'cutoffdate is set and is in past' => [ + ['cutoffdate' => $now - 86400], + true + ], + ]; + } + /** * Test that {@link forum_update_post()} keeps correct forum_discussions usermodified. */ From 82482e3d3e826d93feb8ffd95b2227544922a4ee Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Tue, 19 Mar 2019 15:12:40 +1100 Subject: [PATCH 7/9] MDL-31355 mod_forum: different message when duedate has passed --- .../classes/local/renderers/discussion.php | 5 ++ .../local/renderers/discussion_list.php | 5 ++ mod/forum/lang/en/forum.php | 1 + mod/forum/lib.php | 20 ++++++++ mod/forum/tests/lib_test.php | 48 +++++++++++++++++++ 5 files changed, 79 insertions(+) diff --git a/mod/forum/classes/local/renderers/discussion.php b/mod/forum/classes/local/renderers/discussion.php index dcc59caffb0..500bc75e8f8 100644 --- a/mod/forum/classes/local/renderers/discussion.php +++ b/mod/forum/classes/local/renderers/discussion.php @@ -382,6 +382,11 @@ class discussion { get_string('cutoffdatereached', 'forum'), notification::NOTIFY_INFO ))->set_show_closebutton(); + } else if ($forum->is_due_date_reached()) { + $notifications[] = (new notification( + get_string('thisforumisdue', 'forum', userdate($forum->get_due_date())), + notification::NOTIFY_INFO + ))->set_show_closebutton(); } else if ($forum->has_due_date()) { $notifications[] = (new notification( get_string('thisforumhasduedate', 'forum', userdate($forum->get_due_date())), diff --git a/mod/forum/classes/local/renderers/discussion_list.php b/mod/forum/classes/local/renderers/discussion_list.php index f62a76986b4..cd4ce425ef4 100644 --- a/mod/forum/classes/local/renderers/discussion_list.php +++ b/mod/forum/classes/local/renderers/discussion_list.php @@ -332,6 +332,11 @@ class discussion_list { get_string('cutoffdatereached', 'forum'), notification::NOTIFY_INFO ))->set_show_closebutton(); + } else if ($forum->is_due_date_reached()) { + $notifications[] = (new notification( + get_string('thisforumisdue', 'forum', userdate($forum->get_due_date())), + notification::NOTIFY_INFO + ))->set_show_closebutton(); } else if ($forum->has_due_date()) { $notifications[] = (new notification( get_string('thisforumhasduedate', 'forum', userdate($forum->get_due_date())), diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index c898e519ff2..7ae8c1c2886 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -589,6 +589,7 @@ $string['subscriptions'] = 'Subscriptions'; $string['tagarea_forum_posts'] = 'Forum posts'; $string['tagsdeleted'] = 'Forum tags have been deleted'; $string['thisforumisthrottled'] = 'This forum has a limit to the number of forum postings you can make in a given time period - this is currently set at {$a->blockafter} posting(s) in {$a->blockperiod}'; +$string['thisforumisdue'] = 'The due date for posting to this forum was {$a}.'; $string['thisforumhasduedate'] = 'The due date for posting to this forum is {$a}.'; $string['timedhidden'] = 'Timed status: Hidden from students'; $string['timedposts'] = 'Timed posts'; diff --git a/mod/forum/lib.php b/mod/forum/lib.php index d7c8851b2ab..57d8d717295 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -6337,6 +6337,26 @@ function forum_is_cutoff_date_reached($forum) { return $forumentity->is_cutoff_date_reached(); } +/** + * Determine whether the specified forum's due date is reached. + * + * @param stdClass $forum The forum + * @return bool + */ +function forum_is_due_date_reached($forum) { + $entityfactory = \mod_forum\local\container::get_entity_factory(); + $coursemoduleinfo = get_fast_modinfo($forum->course); + $cminfo = $coursemoduleinfo->instances['forum'][$forum->id]; + $forumentity = $entityfactory->get_forum_from_stdclass( + $forum, + context_module::instance($cminfo->id), + $cminfo->get_course_module_record(), + $cminfo->get_course() + ); + + return $forumentity->is_due_date_reached(); +} + /** * Determine whether the specified discussion is time-locked. * diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php index 88f77327298..496de01be5c 100644 --- a/mod/forum/tests/lib_test.php +++ b/mod/forum/tests/lib_test.php @@ -3218,6 +3218,54 @@ class mod_forum_lib_testcase extends advanced_testcase { ]; } + /** + * Test the forum_is_due_date_reached function. + * + * @dataProvider forum_is_due_date_reached_provider + * @param stdClass $forum + * @param bool $expect + */ + public function test_forum_is_due_date_reached($forum, $expect) { + $this->resetAfterTest(); + + $this->setAdminUser(); + + $datagenerator = $this->getDataGenerator(); + $course = $datagenerator->create_course(); + $forum = $datagenerator->create_module('forum', (object) array_merge([ + 'course' => $course->id + ], $forum)); + + $this->assertEquals($expect, forum_is_due_date_reached($forum)); + } + + /** + * Dataprovider for forum_is_due_date_reached tests. + * + * @return array + */ + public function forum_is_due_date_reached_provider() { + $now = time(); + return [ + 'duedate is unset' => [ + [], + false + ], + 'duedate is 0' => [ + ['duedate' => 0], + false + ], + 'duedate is set and is in future' => [ + ['duedate' => $now + 86400], + false + ], + 'duedate is set and is in past' => [ + ['duedate' => $now - 86400], + true + ], + ]; + } + /** * Test that {@link forum_update_post()} keeps correct forum_discussions usermodified. */ From 7a6b701a90bdd48a191d834aff57d96083816887 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Tue, 14 Aug 2018 06:46:59 +1000 Subject: [PATCH 8/9] MDL-31355 mod_forum: Add drag and drop support to forum duedate events --- mod/forum/lib.php | 95 +++++++++++++++++ mod/forum/tests/lib_test.php | 196 +++++++++++++++++++++++++++++++++++ 2 files changed, 291 insertions(+) diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 57d8d717295..e1b7a826d82 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -6649,3 +6649,98 @@ function forum_user_can_reply_privately(\context_module $context, \stdClass $par return has_capability('mod/forum:postprivatereply', $context); } + +/** + * This function calculates the minimum and maximum cutoff values for the timestart of + * the given event. + * + * It will return an array with two values, the first being the minimum cutoff value and + * the second being the maximum cutoff value. Either or both values can be null, which + * indicates there is no minimum or maximum, respectively. + * + * If a cutoff is required then the function must return an array containing the cutoff + * timestamp and error string to display to the user if the cutoff value is violated. + * + * A minimum and maximum cutoff return value will look like: + * [ + * [1505704373, 'The date must be after this date'], + * [1506741172, 'The date must be before this date'] + * ] + * + * @param calendar_event $event The calendar event to get the time range for + * @param stdClass $forum The module instance to get the range from + * @return array Returns an array with min and max date. + */ +function mod_forum_core_calendar_get_valid_event_timestart_range(\calendar_event $event, \stdClass $forum) { + global $CFG; + + require_once($CFG->dirroot . '/mod/forum/locallib.php'); + + $mindate = null; + $maxdate = null; + + if ($event->eventtype == FORUM_EVENT_TYPE_DUE) { + if (!empty($forum->cutoffdate)) { + $maxdate = [ + $forum->cutoffdate, + get_string('cutoffdatevalidation', 'forum'), + ]; + } + } + + return [$mindate, $maxdate]; +} + +/** + * This function will update the forum module according to the + * event that has been modified. + * + * It will set the timeclose value of the forum instance + * according to the type of event provided. + * + * @throws \moodle_exception + * @param \calendar_event $event + * @param stdClass $forum The module instance to get the range from + */ +function mod_forum_core_calendar_event_timestart_updated(\calendar_event $event, \stdClass $forum) { + global $CFG, $DB; + + require_once($CFG->dirroot . '/mod/forum/locallib.php'); + + if ($event->eventtype != FORUM_EVENT_TYPE_DUE) { + return; + } + + $courseid = $event->courseid; + $modulename = $event->modulename; + $instanceid = $event->instance; + + // Something weird going on. The event is for a different module so + // we should ignore it. + if ($modulename != 'forum') { + return; + } + + if ($forum->id != $instanceid) { + return; + } + + $coursemodule = get_fast_modinfo($courseid)->instances[$modulename][$instanceid]; + $context = context_module::instance($coursemodule->id); + + // The user does not have the capability to modify this activity. + if (!has_capability('moodle/course:manageactivities', $context)) { + return; + } + + if ($event->eventtype == FORUM_EVENT_TYPE_DUE) { + if ($forum->duedate != $event->timestart) { + $forum->duedate = $event->timestart; + $forum->timemodified = time(); + // Persist the instance changes. + $DB->update_record('forum', $forum); + $event = \core\event\course_module_updated::create_from_cm($coursemodule, $context); + $event->trigger(); + } + } +} diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php index 496de01be5c..80e27732d16 100644 --- a/mod/forum/tests/lib_test.php +++ b/mod/forum/tests/lib_test.php @@ -3767,4 +3767,200 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->setUser($otheruser->id); $this->assertFalse(forum_post_is_visible_privately($post, $cm)); } + + /** + * An unkown event type should not have any limits + */ + public function test_mod_forum_core_calendar_get_valid_event_timestart_range_unknown_event() { + global $CFG; + require_once($CFG->dirroot . "/calendar/lib.php"); + + $this->resetAfterTest(true); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $duedate = time() + DAYSECS; + $forum = new \stdClass(); + $forum->duedate = $duedate; + + // Create a valid event. + $event = new \calendar_event([ + 'name' => 'Test event', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'forum', + 'instance' => 1, + 'eventtype' => FORUM_EVENT_TYPE_DUE . "SOMETHING ELSE", + 'timestart' => 1, + 'timeduration' => 86400, + 'visible' => 1 + ]); + + list ($min, $max) = mod_forum_core_calendar_get_valid_event_timestart_range($event, $forum); + $this->assertNull($min); + $this->assertNull($max); + } + + /** + * Forums configured without a cutoff date should not have any limits applied. + */ + public function test_mod_forum_core_calendar_get_valid_event_timestart_range_due_no_limit() { + global $CFG; + require_once($CFG->dirroot . '/calendar/lib.php'); + + $this->resetAfterTest(true); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $duedate = time() + DAYSECS; + $forum = new \stdClass(); + $forum->duedate = $duedate; + + // Create a valid event. + $event = new \calendar_event([ + 'name' => 'Test event', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'forum', + 'instance' => 1, + 'eventtype' => FORUM_EVENT_TYPE_DUE, + 'timestart' => 1, + 'timeduration' => 86400, + 'visible' => 1 + ]); + + list($min, $max) = mod_forum_core_calendar_get_valid_event_timestart_range($event, $forum); + $this->assertNull($min); + $this->assertNull($max); + } + + /** + * Forums should be top bound by the cutoff date. + */ + public function test_mod_forum_core_calendar_get_valid_event_timestart_range_due_with_limits() { + global $CFG; + require_once($CFG->dirroot . '/calendar/lib.php'); + + $this->resetAfterTest(true); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $duedate = time() + DAYSECS; + $cutoffdate = $duedate + DAYSECS; + $forum = new \stdClass(); + $forum->duedate = $duedate; + $forum->cutoffdate = $cutoffdate; + + // Create a valid event. + $event = new \calendar_event([ + 'name' => 'Test event', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'forum', + 'instance' => 1, + 'eventtype' => FORUM_EVENT_TYPE_DUE, + 'timestart' => 1, + 'timeduration' => 86400, + 'visible' => 1 + ]); + + list($min, $max) = mod_forum_core_calendar_get_valid_event_timestart_range($event, $forum); + $this->assertNull($min); + $this->assertEquals($cutoffdate, $max[0]); + $this->assertNotEmpty($max[1]); + } + + /** + * An unknown event type should not change the forum instance. + */ + public function test_mod_forum_core_calendar_event_timestart_updated_unknown_event() { + global $CFG, $DB; + require_once($CFG->dirroot . "/calendar/lib.php"); + + $this->resetAfterTest(true); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $forumgenerator = $generator->get_plugin_generator('mod_forum'); + $duedate = time() + DAYSECS; + $cutoffdate = $duedate + DAYSECS; + $forum = $forumgenerator->create_instance(['course' => $course->id]); + $forum->duedate = $duedate; + $forum->cutoffdate = $cutoffdate; + $DB->update_record('forum', $forum); + + // Create a valid event. + $event = new \calendar_event([ + 'name' => 'Test event', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'forum', + 'instance' => $forum->id, + 'eventtype' => FORUM_EVENT_TYPE_DUE . "SOMETHING ELSE", + 'timestart' => 1, + 'timeduration' => 86400, + 'visible' => 1 + ]); + + mod_forum_core_calendar_event_timestart_updated($event, $forum); + + $forum = $DB->get_record('forum', ['id' => $forum->id]); + $this->assertEquals($duedate, $forum->duedate); + $this->assertEquals($cutoffdate, $forum->cutoffdate); + } + + /** + * Due date events should update the forum due date. + */ + public function test_mod_forum_core_calendar_event_timestart_updated_due_event() { + global $CFG, $DB; + require_once($CFG->dirroot . "/calendar/lib.php"); + + $this->resetAfterTest(true); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $forumgenerator = $generator->get_plugin_generator('mod_forum'); + $duedate = time() + DAYSECS; + $cutoffdate = $duedate + DAYSECS; + $newduedate = $duedate + 1; + $forum = $forumgenerator->create_instance(['course' => $course->id]); + $forum->duedate = $duedate; + $forum->cutoffdate = $cutoffdate; + $DB->update_record('forum', $forum); + + // Create a valid event. + $event = new \calendar_event([ + 'name' => 'Test event', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'forum', + 'instance' => $forum->id, + 'eventtype' => FORUM_EVENT_TYPE_DUE, + 'timestart' => $newduedate, + 'timeduration' => 86400, + 'visible' => 1 + ]); + + mod_forum_core_calendar_event_timestart_updated($event, $forum); + + $forum = $DB->get_record('forum', ['id' => $forum->id]); + $this->assertEquals($newduedate, $forum->duedate); + $this->assertEquals($cutoffdate, $forum->cutoffdate); + } } From 1c96922da587ed098fa0dd1feba30d6301e747e7 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Thu, 11 Apr 2019 02:25:02 +1000 Subject: [PATCH 9/9] MDL-31355 core: Bump $lastmajordbchanges to trigger upgrade immediately --- lib/setuplib.php | 2 +- version.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/setuplib.php b/lib/setuplib.php index 98a8666ada1..9d6c1f2b382 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -1407,7 +1407,7 @@ function disable_output_buffering() { */ function is_major_upgrade_required() { global $CFG; - $lastmajordbchanges = 2019032900.00; + $lastmajordbchanges = 2019041000.01; $required = empty($CFG->version); $required = $required || (float)$CFG->version < $lastmajordbchanges; diff --git a/version.php b/version.php index 5368791a889..1368f74b77e 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2019041000.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2019041000.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.