diff --git a/mod/forum/classes/event/subscription_mode_updated.php b/mod/forum/classes/event/subscription_mode_updated.php new file mode 100644 index 00000000000..eb2d5b2cc86 --- /dev/null +++ b/mod/forum/classes/event/subscription_mode_updated.php @@ -0,0 +1,99 @@ +. + +namespace mod_forum\event; + +use coding_exception; +use moodle_url; + +/** + * The mod_forum subscription mode updated event. + * + * @package mod_forum + * @copyright 2022 Université Rennes 2 {@link https://www.univ-rennes2.fr} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class subscription_mode_updated extends \core\event\base { + /** + * Init method. + * + * @return void + */ + protected function init(): void { + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'forum'; + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description(): string { + return "The user with id '$this->userid' has updated the forum subscription + from mode '{$this->other['oldvalue']}' to mode '{$this->other['newvalue']}' in the forum id '$this->objectid'"; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name(): string { + return get_string('eventforumsubscriptionupdated', 'mod_forum'); + } + + /** + * Get URL related to the action + * + * @return moodle_url + */ + public function get_url(): moodle_url { + return new moodle_url('/mod/forum/subscribers.php', ['id' => $this->objectid]); + } + + /** + * Custom validation. + * + * @throws coding_exception + * @return void + */ + protected function validate_data(): void { + parent::validate_data(); + if (!isset($this->other['oldvalue'])) { + throw new coding_exception('oldvalue must be set in $other.'); + } + if (!isset($this->other['newvalue'])) { + throw new coding_exception('newvalue must be set in $other.'); + } + if ($this->contextlevel != CONTEXT_MODULE) { + throw new coding_exception('Context passed must be module context.'); + } + if (!isset($this->objectid)) { + throw new coding_exception('objectid must be set to the forumid.'); + } + } + + /** + * Forum object id mappings. + * + * @return array + */ + public static function get_objectid_mapping(): array { + return ['db' => 'forum', 'restore' => 'forum']; + } +} diff --git a/mod/forum/classes/subscriptions.php b/mod/forum/classes/subscriptions.php index 7c65b1df9f6..f571b039cd2 100644 --- a/mod/forum/classes/subscriptions.php +++ b/mod/forum/classes/subscriptions.php @@ -176,11 +176,32 @@ class subscriptions { * * @param \stdClass $forum The record of the forum to set * @param int $status The new subscription state - * @return bool + * @return bool true + * @throws dml_exception A DML specific exception is thrown for any errors. */ - public static function set_subscription_mode($forumid, $status = 1) { + public static function set_subscription_mode($forum, $status = FORUM_FORCESUBSCRIBE): bool { global $DB; - return $DB->set_field("forum", "forcesubscribe", $status, array("id" => $forumid)); + + if (is_numeric($forum)) { + debugging(__METHOD__.': Argument #1 ($forum) must be a stdClass record of a forum', DEBUG_DEVELOPER); + + $forum = $DB->get_record("forum", ["id" => $forum], '*', MUST_EXIST); + } + + $DB->set_field("forum", "forcesubscribe", $status, ["id" => $forum->id]); + + if ($forum->forcesubscribe != $status) { + // Trigger event if subscription mode has been changed. + $event = \mod_forum\event\subscription_mode_updated::create([ + "context" => forum_get_context($forum->id), + "objectid" => $forum->id, + "other" => ["oldvalue" => $forum->forcesubscribe, "newvalue" => $status], + ]); + $event->add_record_snapshot("forum", $forum); + $event->trigger(); + } + + return true; } /** diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 27de70d4ff9..a3616066af5 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -242,6 +242,7 @@ $string['eventdiscussionsubscriptioncreated'] = 'Discussion subscription created $string['eventdiscussionsubscriptiondeleted'] = 'Discussion subscription deleted'; $string['eventdiscussionpinned'] = 'Discussion pinned'; $string['eventdiscussionunpinned'] = 'Discussion unpinned'; +$string['eventforumsubscriptionupdated'] = 'Subscription mode updated'; $string['eventuserreportviewed'] = 'User report viewed'; $string['eventpostcreated'] = 'Post created'; $string['eventpostdeleted'] = 'Post deleted'; diff --git a/mod/forum/subscribe.php b/mod/forum/subscribe.php index 8cd92c44e38..6aa0a8d848f 100644 --- a/mod/forum/subscribe.php +++ b/mod/forum/subscribe.php @@ -126,7 +126,7 @@ if (!is_null($mode) and has_capability('mod/forum:managesubscriptions', $context require_sesskey(); switch ($mode) { case FORUM_CHOOSESUBSCRIBE : // 0 - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_CHOOSESUBSCRIBE); + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_CHOOSESUBSCRIBE); redirect( $subscribersurl, get_string('everyonecannowchoose', 'forum'), @@ -135,7 +135,7 @@ if (!is_null($mode) and has_capability('mod/forum:managesubscriptions', $context ); break; case FORUM_FORCESUBSCRIBE : // 1 - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_FORCESUBSCRIBE); + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE); redirect( $subscribersurl, get_string('everyoneisnowsubscribed', 'forum'), @@ -144,7 +144,7 @@ if (!is_null($mode) and has_capability('mod/forum:managesubscriptions', $context ); break; case FORUM_INITIALSUBSCRIBE : // 2 - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_INITIALSUBSCRIBE); + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_INITIALSUBSCRIBE); if ($forum->forcesubscribe <> FORUM_INITIALSUBSCRIBE) { // Reload the forum again to get the updated forcesubscribe field. $forum = $DB->get_record('forum', array('id' => $id), '*', MUST_EXIST); @@ -161,7 +161,7 @@ if (!is_null($mode) and has_capability('mod/forum:managesubscriptions', $context ); break; case FORUM_DISALLOWSUBSCRIBE : // 3 - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_DISALLOWSUBSCRIBE); + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE); redirect( $subscribersurl, get_string('noonecansubscribenow', 'forum'), diff --git a/mod/forum/tests/subscriptions_test.php b/mod/forum/tests/subscriptions_test.php index 1194b60b92b..6fcb5ee4eb0 100644 --- a/mod/forum/tests/subscriptions_test.php +++ b/mod/forum/tests/subscriptions_test.php @@ -58,6 +58,11 @@ class subscriptions_test extends \advanced_testcase { \mod_forum\subscriptions::reset_discussion_cache(); } + /** + * Test subscription modes modifications. + * + * @covers \mod_forum\event\subscription_mode_updated + */ public function test_subscription_modes() { global $DB; @@ -68,6 +73,7 @@ class subscriptions_test extends \advanced_testcase { $options = array('course' => $course->id); $forum = $this->getDataGenerator()->create_module('forum', $options); + $context = \context_module::instance($forum->cmid); // Create a user enrolled in the course as a student. list($user) = $this->helper_create_users($course, 1); @@ -75,33 +81,69 @@ class subscriptions_test extends \advanced_testcase { // Must be logged in as the current user. $this->setUser($user); - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_FORCESUBSCRIBE); + $sink = $this->redirectEvents(); // Capturing the event. + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE); $forum = $DB->get_record('forum', array('id' => $forum->id)); $this->assertEquals(FORUM_FORCESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum)); $this->assertTrue(\mod_forum\subscriptions::is_forcesubscribed($forum)); $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum)); $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum)); - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_DISALLOWSUBSCRIBE); + $events = $sink->get_events(); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event); + $this->assertEquals($context, $event->get_context()); + $this->assertEventContextNotUsed($event); + $this->assertNotEmpty($event->get_name()); + + $sink = $this->redirectEvents(); // Capturing the event. + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE); $forum = $DB->get_record('forum', array('id' => $forum->id)); $this->assertEquals(FORUM_DISALLOWSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum)); $this->assertTrue(\mod_forum\subscriptions::subscription_disabled($forum)); $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum)); $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum)); - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_INITIALSUBSCRIBE); + $events = $sink->get_events(); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event); + $this->assertEquals($context, $event->get_context()); + $this->assertEventContextNotUsed($event); + $this->assertNotEmpty($event->get_name()); + + $sink = $this->redirectEvents(); // Capturing the event. + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_INITIALSUBSCRIBE); $forum = $DB->get_record('forum', array('id' => $forum->id)); $this->assertEquals(FORUM_INITIALSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum)); $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum)); $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum)); $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum)); - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_CHOOSESUBSCRIBE); + $events = $sink->get_events(); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event); + $this->assertEquals($context, $event->get_context()); + $this->assertEventContextNotUsed($event); + $this->assertNotEmpty($event->get_name()); + + $sink = $this->redirectEvents(); // Capturing the event. + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_CHOOSESUBSCRIBE); $forum = $DB->get_record('forum', array('id' => $forum->id)); $this->assertEquals(FORUM_CHOOSESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum)); $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum)); $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum)); $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum)); + + $events = $sink->get_events(); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event); + $this->assertEquals($context, $event->get_context()); + $this->assertEventContextNotUsed($event); + $this->assertNotEmpty($event->get_name()); } /** @@ -1436,12 +1478,12 @@ class subscriptions_test extends \advanced_testcase { // Subscribption disabled. $this->setUser($student->id); - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_DISALLOWSUBSCRIBE); + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE); $forum = $DB->get_record('forum', array('id' => $forum->id)); $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id)); $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null)); - \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_FORCESUBSCRIBE); + \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE); $forum = $DB->get_record('forum', array('id' => $forum->id)); $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id)); $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));