From bd6fdd70d680ceec020bed28c43ad05c111c0f9d Mon Sep 17 00:00:00 2001 From: Tomo Tsuyuki Date: Fri, 27 May 2022 12:35:54 +1000 Subject: [PATCH] MDL-74623 mod_forum: Add course full name option for notification --- .../backup/moodle2/backup_forum_stepslib.php | 2 +- .../local/data_mappers/legacy/forum.php | 3 +- mod/forum/classes/local/entities/forum.php | 16 ++++++- mod/forum/classes/local/factories/entity.php | 3 +- mod/forum/classes/output/forum_post.php | 17 ++++++- .../classes/task/send_user_notifications.php | 3 +- mod/forum/db/install.xml | 1 + mod/forum/db/upgrade.php | 13 ++++++ mod/forum/externallib.php | 1 + mod/forum/lang/en/forum.php | 5 +- mod/forum/lib.php | 9 +++- mod/forum/mod_form.php | 4 ++ mod/forum/settings.php | 4 ++ mod/forum/tests/entities_forum_test.php | 5 +- mod/forum/tests/mail_test.php | 46 ++++++++++++++++++- mod/forum/version.php | 2 +- 16 files changed, 120 insertions(+), 14 deletions(-) diff --git a/mod/forum/backup/moodle2/backup_forum_stepslib.php b/mod/forum/backup/moodle2/backup_forum_stepslib.php index 8255dd81f74..7a48fee3f97 100644 --- a/mod/forum/backup/moodle2/backup_forum_stepslib.php +++ b/mod/forum/backup/moodle2/backup_forum_stepslib.php @@ -44,7 +44,7 @@ class backup_forum_activity_structure_step extends backup_activity_structure_ste 'maxbytes', 'maxattachments', 'forcesubscribe', 'trackingtype', 'rsstype', 'rssarticles', 'timemodified', 'warnafter', 'blockafter', 'blockperiod', 'completiondiscussions', 'completionreplies', - 'completionposts', 'displaywordcount', 'lockdiscussionafter', 'grade_forum')); + 'completionposts', 'displaywordcount', 'lockdiscussionafter', 'grade_forum', 'usecoursefullname')); $discussions = new backup_nested_element('discussions'); diff --git a/mod/forum/classes/local/data_mappers/legacy/forum.php b/mod/forum/classes/local/data_mappers/legacy/forum.php index 6b8ec772b80..f98cf159a2a 100644 --- a/mod/forum/classes/local/data_mappers/legacy/forum.php +++ b/mod/forum/classes/local/data_mappers/legacy/forum.php @@ -73,7 +73,8 @@ class forum { 'displaywordcount' => $forum->should_display_word_count(), 'lockdiscussionafter' => $forum->get_lock_discussions_after(), 'duedate' => $forum->get_due_date(), - 'cutoffdate' => $forum->get_cutoff_date() + 'cutoffdate' => $forum->get_cutoff_date(), + 'usecoursefullname' => $forum->use_course_fullname() ]; }, $forums); } diff --git a/mod/forum/classes/local/entities/forum.php b/mod/forum/classes/local/entities/forum.php index 4d4808b824b..5730a68672f 100644 --- a/mod/forum/classes/local/entities/forum.php +++ b/mod/forum/classes/local/entities/forum.php @@ -107,6 +107,8 @@ class forum { private $duedate; /** @var int $cutoffdate Timestamp after which forum posts will no longer be accepted */ private $cutoffdate; + /** @var bool $usecoursefullname Whether to use course full name instead of short name in notifications */ + private $usecoursefullname; /** * Constructor @@ -144,6 +146,7 @@ class forum { * @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 + * @param bool $usecoursefullname Whether to use course full name instead of short name in notifications */ public function __construct( context $context, @@ -178,7 +181,8 @@ class forum { bool $displaywordcount, int $lockdiscussionafter, int $duedate, - int $cutoffdate + int $cutoffdate, + bool $usecoursefullname = false ) { $this->context = $context; $this->coursemodule = $coursemodule; @@ -213,6 +217,7 @@ class forum { $this->lockdiscussionafter = $lockdiscussionafter; $this->duedate = $duedate; $this->cutoffdate = $cutoffdate; + $this->usecoursefullname = $usecoursefullname; } /** @@ -669,4 +674,13 @@ class forum { return $this->is_discussion_time_locked($discussion); } + + /** + * Should use course full name instead of short name in notifications? + * + * @return bool + */ + public function use_course_fullname(): bool { + return $this->usecoursefullname; + } } diff --git a/mod/forum/classes/local/factories/entity.php b/mod/forum/classes/local/factories/entity.php index 9ed4c5498ae..3a4a14fe138 100644 --- a/mod/forum/classes/local/factories/entity.php +++ b/mod/forum/classes/local/factories/entity.php @@ -104,7 +104,8 @@ class entity { $record->displaywordcount, $record->lockdiscussionafter, $record->duedate, - $record->cutoffdate + $record->cutoffdate, + $record->usecoursefullname ?? false ); } diff --git a/mod/forum/classes/output/forum_post.php b/mod/forum/classes/output/forum_post.php index 072f310436e..0c192a64018 100644 --- a/mod/forum/classes/output/forum_post.php +++ b/mod/forum/classes/output/forum_post.php @@ -155,7 +155,7 @@ class forum_post implements \renderable, \templatable { $data = $this->export_for_template_shared($renderer); return $data + array( 'id' => html_entity_decode($this->post->id), - 'coursename' => html_entity_decode($this->get_coursename()), + 'coursename' => html_entity_decode($this->get_forum_coursename()), 'courselink' => html_entity_decode($this->get_courselink()), 'forumname' => html_entity_decode($this->get_forumname()), 'showdiscussionname' => html_entity_decode($this->get_showdiscussionname()), @@ -197,7 +197,7 @@ class forum_post implements \renderable, \templatable { $data = $this->export_for_template_shared($renderer); return $data + array( 'id' => $this->post->id, - 'coursename' => $this->get_coursename(), + 'coursename' => $this->get_forum_coursename(), 'courselink' => $this->get_courselink(), 'forumname' => $this->get_forumname(), 'showdiscussionname' => $this->get_showdiscussionname(), @@ -485,6 +485,19 @@ class forum_post implements \renderable, \templatable { )); } + /** + * The name of the course that the forum is in, based on forum setting. + * + * @return string + */ + public function get_forum_coursename() { + if ($this->forum->usecoursefullname) { + return $this->get_coursefullname(); + } else { + return $this->get_coursename(); + } + } + /** * The name of the forum. * diff --git a/mod/forum/classes/task/send_user_notifications.php b/mod/forum/classes/task/send_user_notifications.php index ef7ac0fb90a..059081dc836 100644 --- a/mod/forum/classes/task/send_user_notifications.php +++ b/mod/forum/classes/task/send_user_notifications.php @@ -327,8 +327,7 @@ class send_user_notifications extends \core\task\adhoc_task { 'sitefullname' => format_string($site->fullname), 'siteshortname' => format_string($site->shortname), 'courseidnumber' => $data->get_courseidnumber(), - 'coursefullname' => $data->get_coursefullname(), - 'courseshortname' => $data->get_coursename(), + 'coursename' => $data->get_forum_coursename(), ]; $postsubject = html_to_text(get_string('postmailsubject', 'forum', $a), 0); diff --git a/mod/forum/db/install.xml b/mod/forum/db/install.xml index 0edb6ab22c4..60136752047 100644 --- a/mod/forum/db/install.xml +++ b/mod/forum/db/install.xml @@ -35,6 +35,7 @@ + diff --git a/mod/forum/db/upgrade.php b/mod/forum/db/upgrade.php index c48863680b0..54a07f99f17 100644 --- a/mod/forum/db/upgrade.php +++ b/mod/forum/db/upgrade.php @@ -338,5 +338,18 @@ function xmldb_forum_upgrade($oldversion) { // Automatically generated Moodle v4.0.0 release upgrade line. // Put any upgrade step following this. + if ($oldversion < 2022041901) { + // Define field usecoursefullname to be added to forum. + $table = new xmldb_table('forum'); + $field = new xmldb_field('usecoursefullname', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', + 'lockdiscussionafter'); + + // Conditionally launch add field usecoursefullname. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + upgrade_mod_savepoint(true, 2022041901, 'forum'); + } + return true; } diff --git a/mod/forum/externallib.php b/mod/forum/externallib.php index 43be7e6506a..5bd7f131aca 100644 --- a/mod/forum/externallib.php +++ b/mod/forum/externallib.php @@ -159,6 +159,7 @@ class mod_forum_external extends external_api { 'numdiscussions' => new external_value(PARAM_INT, 'Number of discussions in the forum', VALUE_OPTIONAL), 'cancreatediscussions' => new external_value(PARAM_BOOL, 'If the user can create discussions', VALUE_OPTIONAL), 'lockdiscussionafter' => new external_value(PARAM_INT, 'After what period a discussion is locked', VALUE_OPTIONAL), + 'usecoursefullname' => new external_value(PARAM_INT, 'Whether to use course full name for notifications'), 'istracked' => new external_value(PARAM_BOOL, 'If the user is tracking the forum', VALUE_OPTIONAL), 'unreadpostscount' => new external_value(PARAM_INT, 'The number of unread posts for tracked forums', VALUE_OPTIONAL), diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index f466ab43479..c300ce9151b 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -138,6 +138,7 @@ $string['configsubscriptiontype'] = 'Default setting for subscription mode.'; $string['configshortpost'] = 'Any post under this length (in characters not including HTML) is considered short (see below).'; $string['configtrackingtype'] = 'Default setting for read tracking.'; $string['configtrackreadposts'] = 'Set to \'yes\' if you want to track read/unread for each user.'; +$string['configusecoursefullname'] = 'Default setting to use course full name instead of course short name for notifications.'; $string['configusermarksread'] = 'If \'yes\', the user must manually mark a post as read. If \'no\', when the post is viewed it is marked as read.'; $string['confirmsubscribediscussion'] = 'Do you really want to subscribe to discussion \'{$a->discussion}\' in forum \'{$a->forum}\'?'; $string['confirmunsubscribediscussion'] = 'Do you really want to unsubscribe from discussion \'{$a->discussion}\' in forum \'{$a->forum}\'?'; @@ -524,7 +525,7 @@ $string['postincontext'] = 'See this post in context'; $string['postmailinfo'] = 'This is a copy of a message posted in {$a}.'; $string['postmailnow'] = '

This post will be mailed out immediately to all forum subscribers.

'; $string['postmailreply'] = 'To reply click on this link: {$a}'; -$string['postmailsubject'] = '{$a->courseshortname}: {$a->subject}'; +$string['postmailsubject'] = '{$a->coursename}: {$a->subject}'; $string['postrating1'] = 'Mostly separate knowing'; $string['postrating2'] = 'Separate and connected'; $string['postrating3'] = 'Mostly connected knowing'; @@ -743,6 +744,8 @@ $string['unsubscribealldone'] = 'All optional forum subscriptions were removed. $string['unsubscribeallempty'] = 'You are not subscribed to any forums. To disable all notifications from this server go to Messaging in My Profile Settings.'; $string['unsubscribed'] = 'Unsubscribed'; $string['unsubscribeshort'] = 'Unsubscribe'; +$string['usecoursefullname'] = 'Use course full name in notifications'; +$string['usecoursefullname_help'] = 'Use course full name instead of course short name for notifications.'; $string['useexperimentalui'] = 'Use experimental nested discussion view'; $string['usermarksread'] = 'Manual message read marking'; $string['usernavigation'] = 'User navigation'; diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 3ad968c3881..807aebfc602 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -184,6 +184,10 @@ function forum_update_instance($forum, $mform) { $forum->assesstimefinish = 0; } + if (empty($forum->usecoursefullname)) { + $forum->usecoursefullname = 0; + } + $oldforum = $DB->get_record('forum', array('id'=>$forum->id)); // MDL-3942 - if the aggregation type or scale (i.e. max grade) changes then recalculate the grades for the entire forum @@ -592,7 +596,7 @@ function forum_print_recent_activity($course, $viewfullnames, $timestart) { f.scale, f.grade_forum, f.maxbytes, f.maxattachments, f.forcesubscribe, f.trackingtype, f.rsstype, f.rssarticles, f.timemodified, f.warnafter, f.blockafter, f.blockperiod, f.completiondiscussions, f.completionreplies, f.completionposts, - f.displaywordcount, f.lockdiscussionafter, f.grade_forum_notify, + f.displaywordcount, f.lockdiscussionafter, f.grade_forum_notify, f.usecoursefullname, d.name AS discussionname, d.firstpost, d.userid AS discussionstarter, d.assessed AS discussionassessed, d.timemodified, d.usermodified, d.forum, d.groupid, d.timestart, d.timeend, d.pinned, d.timelocked, @@ -684,7 +688,8 @@ function forum_print_recent_activity($course, $viewfullnames, $timestart) { 'completionposts' => $post->completionposts, 'displaywordcount' => $post->displaywordcount, 'lockdiscussionafter' => $post->lockdiscussionafter, - 'grade_forum_notify' => $post->grade_forum_notify + 'grade_forum_notify' => $post->grade_forum_notify, + 'usecoursefullname' => $post->usecoursefullname ]; // Build the forum entity from the factory. $forumentity = $entityfactory->get_forum_from_stdclass($forumrecord, $context, $coursemodule, $course); diff --git a/mod/forum/mod_form.php b/mod/forum/mod_form.php index 65cd77a75ea..cde04a88f26 100644 --- a/mod/forum/mod_form.php +++ b/mod/forum/mod_form.php @@ -126,6 +126,10 @@ class mod_forum_mod_form extends moodleform_mod { } $mform->setDefault('trackingtype', $default); + $mform->addElement('checkbox', 'usecoursefullname', get_string('usecoursefullname', 'forum'), null); + $mform->addHelpButton('usecoursefullname', 'usecoursefullname', 'forum'); + $mform->setDefault('usecoursefullname', $CFG->forum_usecoursefullname); + if ($CFG->enablerssfeeds && isset($CFG->forum_enablerssfeeds) && $CFG->forum_enablerssfeeds) { //------------------------------------------------------------------------------- $mform->addElement('header', 'rssheader', get_string('rss')); diff --git a/mod/forum/settings.php b/mod/forum/settings.php index bbe59ca3d27..16b317dcfa0 100644 --- a/mod/forum/settings.php +++ b/mod/forum/settings.php @@ -95,6 +95,10 @@ if ($ADMIN->fulltree) { $settings->add(new admin_setting_configselect('digestmailtime', get_string('digestmailtime', 'forum'), get_string('configdigestmailtime', 'forum'), 17, $options)); + // Use full course name for notification. + $settings->add(new admin_setting_configcheckbox('forum_usecoursefullname', get_string('usecoursefullname', 'forum'), + get_string('configusecoursefullname', 'forum'), 0)); + if (empty($CFG->enablerssfeeds)) { $options = array(0 => get_string('rssglobaldisabled', 'admin')); $str = get_string('configenablerssfeeds', 'forum').'
'.get_string('configenablerssfeedsdisabled2', 'admin'); diff --git a/mod/forum/tests/entities_forum_test.php b/mod/forum/tests/entities_forum_test.php index 2d52ba37910..099d9c456ac 100644 --- a/mod/forum/tests/entities_forum_test.php +++ b/mod/forum/tests/entities_forum_test.php @@ -90,6 +90,7 @@ class entities_forum_test extends \advanced_testcase { $lockdiscussionafter = 0; $duedate = 0; $cutoffdate = 0; + $usecoursefullname = 0; $sendnotification = false; $forum = new forum_entity( $context, @@ -124,7 +125,8 @@ class entities_forum_test extends \advanced_testcase { $displaywordcount, $lockdiscussionafter, $duedate, - $cutoffdate + $cutoffdate, + $usecoursefullname ); $this->assertEquals($context, $forum->get_context()); @@ -167,5 +169,6 @@ class entities_forum_test extends \advanced_testcase { $this->assertEquals(false, $forum->is_due_date_reached()); $this->assertEquals(false, $forum->has_cutoff_date()); $this->assertEquals(false, $forum->is_cutoff_date_reached()); + $this->assertEquals(false, $forum->use_course_fullname()); } } diff --git a/mod/forum/tests/mail_test.php b/mod/forum/tests/mail_test.php index 0a4db889641..78d2bd99a66 100644 --- a/mod/forum/tests/mail_test.php +++ b/mod/forum/tests/mail_test.php @@ -910,7 +910,7 @@ class mail_test extends \advanced_testcase { // Post a discussion to the forum. $subject = 'This is the very long forum post subject that somebody was very kind of leaving, it is intended to check if long subject comes in mail correctly. Thank you.'; - $a = (object)array('courseshortname' => $course->shortname, 'forumname' => $forum->name, 'subject' => $subject); + $a = (object)array('coursename' => $course->shortname, 'forumname' => $forum->name, 'subject' => $subject); $expectedsubject = get_string('postmailsubject', 'forum', $a); list($discussion, $post) = $this->helper_post_to_forum($forum, $author, array('name' => $subject)); @@ -930,6 +930,50 @@ class mail_test extends \advanced_testcase { $this->assertEquals($expectedsubject, $message->subject); } + /** + * Test usecoursefullname option for notification. + * + * @covers \mod_forum\task\send_user_notifications + */ + public function test_usecoursefullname() { + $this->resetAfterTest(); + + $record = []; + $record['fullname'] = 'Test Course Full Name'; + $record['shortname'] = 'Shortname'; + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course($record); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE, 'usecoursefullname' => true); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create a user enrolled in the course as student. + list($author) = $this->helper_create_users($course, 1); + + // Post a discussion to the forum. + $subject = 'This is the forum post subject.'; + // Expect coursefullname instead of shortname. + $a = (object)array('coursename' => $course->fullname, 'subject' => $subject); + $expectedsubject = get_string('postmailsubject', 'forum', $a); + list($discussion, $post) = $this->helper_post_to_forum($forum, $author, array('name' => $subject)); + + // Run cron and check that the expected number of users received the notification. + $expect = [ + 'author' => (object) [ + 'userid' => $author->id, + 'messages' => 1, + ], + ]; + $this->queue_tasks_and_assert($expect); + + $this->send_notifications_and_assert($author, [$post]); + $messages = $this->messagesink->get_messages(); + $this->assertEquals($expectedsubject, $messages[0]->subject); + $this->assertStringContainsString($course->fullname, $messages[0]->fullmessage); + $this->assertStringContainsString($course->fullname, $messages[0]->fullmessagehtml); + } + /** * Test inital email and reply email subjects */ diff --git a/mod/forum/version.php b/mod/forum/version.php index 1f9bc3a3b06..dcbbb6af475 100644 --- a/mod/forum/version.php +++ b/mod/forum/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2022041900; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2022041901; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2022041200; // Requires this Moodle version. $plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)