diff --git a/README.md b/README.md index 16ea29f..d4daa2c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # Moodle - Local Reminders --- -![Version](https://img.shields.io/badge/version-v2.4-blue) +![Version](https://img.shields.io/badge/version-v2.5-blue) ![Moodle Version](https://img.shields.io/badge/moodle-%3E%3D%203.5-orange) +![Maturiy](https://img.shields.io/badge/maturity-STABLE-brightgreen) ![License](https://img.shields.io/badge/license-GPL%20v3-green) +![Maintenance](https://img.shields.io/maintenance/yes/2022) [![Build Status](https://github.com/isuru89/moodle-local_reminders/actions/workflows/moodle-ci.yml/badge.svg?branch=release_2.0)](https://github.com/isuru89/moodle-local_reminders/actions/workflows/moodle-ci.yml) This plugin will send email reminders for [Moodle](https://moodle.org/) calendar events. @@ -25,11 +27,12 @@ In addition to that, there are lot of new features introduced in v2 of the plugi * Send reminders to users who unable to complete an expired activity. * Send email reminders when a calendar event is created, updated or removed. * Ability to enable/disable and scheduling reminders per activity basis. + * Ability to customize email header and footer contents * Ability to exclude specific set of activity types from sending reminders. * No reminders after a user has completed activity. * Added event location / timezone information to the reminder email. - * New category event type support - * Improved email style + * New category event type support. + * Honours activity overriddes and extensions. And many bug fixes too. @@ -96,6 +99,11 @@ In addition to above, user can control reminders for calendar event changes per ## Changelog +### v2.5 + * Ability to customize reminder email header and footer #137 #135 + * Bug fix on user and group overrides and extensions #134 + * Minor bug fixes #136 + ### v2.4 * Ability to explicitly turn on reminders instead of enabling by default for all (#129, #130) diff --git a/classes/calendar_observer.php b/classes/calendar_observer.php index bb37985..4e81f4a 100644 --- a/classes/calendar_observer.php +++ b/classes/calendar_observer.php @@ -69,4 +69,4 @@ public static function calendar_event_added($event) { when_calendar_event_updated($event, REMINDERS_CALENDAR_EVENT_ADDED); } -} \ No newline at end of file +} diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php index 9e92997..1ef4bd8 100644 --- a/classes/privacy/provider.php +++ b/classes/privacy/provider.php @@ -43,4 +43,4 @@ class provider implements public static function get_reason() : string { return 'privacy:metadata'; } -} \ No newline at end of file +} diff --git a/contents/category_reminder.class.php b/contents/category_reminder.class.php index dead684..4a70d98 100644 --- a/contents/category_reminder.class.php +++ b/contents/category_reminder.class.php @@ -67,6 +67,7 @@ public function __construct($event, $coursecategory, $aheaddays = 1) { public function get_message_html($user=null, $changetype=null, $ctxinfo=null) { $htmlmail = $this->get_html_header(); $htmlmail .= html_writer::start_tag('body', array('id' => 'email')); + $htmlmail .= $this->get_reminder_header(); $htmlmail .= html_writer::start_tag('div'); $htmlmail .= html_writer::start_tag('table', array('cellspacing' => 0, 'cellpadding' => 8, 'style' => $this->tbodycssstyle)); diff --git a/contents/course_reminder.class.php b/contents/course_reminder.class.php index 69adcb2..8179974 100644 --- a/contents/course_reminder.class.php +++ b/contents/course_reminder.class.php @@ -67,6 +67,7 @@ public function __construct($event, $course, $aheaddays = 1) { public function get_message_html($user=null, $changetype=null, $ctxinfo=null) { $htmlmail = $this->get_html_header(); $htmlmail .= html_writer::start_tag('body', array('id' => 'email')); + $htmlmail .= $this->get_reminder_header(); $htmlmail .= html_writer::start_tag('div'); $htmlmail .= html_writer::start_tag('table', array('cellspacing' => 0, 'cellpadding' => 8, 'style' => $this->tbodycssstyle)); diff --git a/contents/due_reminder.class.php b/contents/due_reminder.class.php index a854504..302cf35 100644 --- a/contents/due_reminder.class.php +++ b/contents/due_reminder.class.php @@ -140,6 +140,7 @@ public function filter_authorized_users($users, $type=null) { public function get_message_html($user=null, $changetype=null, $ctxinfo=null) { $htmlmail = $this->get_html_header(); $htmlmail .= html_writer::start_tag('body', array('id' => 'email')); + $htmlmail .= $this->get_reminder_header(); $htmlmail .= html_writer::start_tag('div'); $htmlmail .= html_writer::start_tag('table', array('cellspacing' => 0, 'cellpadding' => 8, 'style' => $this->tbodycssstyle)); diff --git a/contents/group_reminder.class.php b/contents/group_reminder.class.php index 60cc877..31653f0 100644 --- a/contents/group_reminder.class.php +++ b/contents/group_reminder.class.php @@ -135,6 +135,7 @@ public function get_message_html($user=null, $changetype=null, $ctxinfo=null) { $htmlmail = $this->get_html_header(); $htmlmail .= html_writer::start_tag('body', array('id' => 'email')); + $htmlmail .= $this->get_reminder_header(); $htmlmail .= html_writer::start_tag('div'); $htmlmail .= html_writer::start_tag('table', array('cellspacing' => 0, 'cellpadding' => 8, 'style' => $this->tbodycssstyle)); diff --git a/contents/site_reminder.class.php b/contents/site_reminder.class.php index 15db37a..95e957f 100644 --- a/contents/site_reminder.class.php +++ b/contents/site_reminder.class.php @@ -48,6 +48,7 @@ class site_reminder extends local_reminder { public function get_message_html($user=null, $changetype=null, $ctxinfo=null) { $htmlmail = $this->get_html_header(); $htmlmail .= html_writer::start_tag('body', array('id' => 'email')); + $htmlmail .= $this->get_reminder_header(); $htmlmail .= html_writer::start_tag('div'); $htmlmail .= html_writer::start_tag('table', array('cellspacing' => 0, 'cellpadding' => 8, 'style' => $this->tbodycssstyle)); diff --git a/contents/user_reminder.class.php b/contents/user_reminder.class.php index 282958f..a723790 100644 --- a/contents/user_reminder.class.php +++ b/contents/user_reminder.class.php @@ -78,6 +78,7 @@ public function cleanup() { public function get_message_html($user=null, $changetype=null, $ctxinfo=null) { $htmlmail = $this->get_html_header(); $htmlmail .= html_writer::start_tag('body', array('id' => 'email')); + $htmlmail .= $this->get_reminder_header(); $htmlmail .= html_writer::start_tag('div'); $htmlmail .= html_writer::start_tag('table', array('cellspacing' => 0, 'cellpadding' => 8, 'style' => $this->tbodycssstyle)); diff --git a/coursesettings_form.php b/coursesettings_form.php index ba9c957..ee8785b 100644 --- a/coursesettings_form.php +++ b/coursesettings_form.php @@ -211,4 +211,4 @@ private function generate_event_link($event) { return $calurl->out(false); } -} \ No newline at end of file +} diff --git a/db/events.php b/db/events.php index b2e1ea7..090f2da 100644 --- a/db/events.php +++ b/db/events.php @@ -37,4 +37,4 @@ 'eventname' => '\core\event\calendar_event_deleted', 'callback' => '\local_reminders\calendar_observer::calendar_event_removed' ) -); \ No newline at end of file +); diff --git a/db/upgrade.php b/db/upgrade.php index 28e23b8..85a087e 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -140,4 +140,4 @@ function create_local_reminders_post_activity_table($dbman) { if (!$dbman->table_exists($table)) { $dbman->create_table($table); } -} \ No newline at end of file +} diff --git a/lang/en/local_reminders.php b/lang/en/local_reminders.php index 8470b83..40f6c2a 100644 --- a/lang/en/local_reminders.php +++ b/lang/en/local_reminders.php @@ -57,6 +57,13 @@ $string['days3'] = '3 Days'; $string['days1'] = '1 Day'; $string['dueheading'] = 'Activity Event Reminders'; +$string['emailconfigsheading'] = 'Reminder Email Customization'; +$string['emailfootercustomname'] = 'Custom Email Footer'; +$string['emailfootercustomnamedesc'] = 'Specify the footer content to be embedded in every reminder email message. If this content is empty and default footer is disabled, then footer will remove completely from reminders.'; +$string['emailfooterdefaultname'] = 'Use Default Email Footer'; +$string['emailfooterdefaultnamedesc'] = 'If checked, then default reminder email footer will contain a link to the Moodle calendar. Otherwise, the content provided in customized footer will be used.'; +$string['emailheadercustomname'] = 'Custom Email Header'; +$string['emailheadercustomnamedesc'] = 'Specify the header content to be embedded in every reminder email message. This can be use to brand these email messages to your site.'; $string['enabled'] = 'Enabled'; $string['enabledoverdue'] = 'Overdue Enabled'; $string['enableddescription'] = 'Enable/disable reminder plugin'; diff --git a/lib.php b/lib.php index 0e4cc4b..67828c9 100644 --- a/lib.php +++ b/lib.php @@ -76,6 +76,10 @@ define('REMINDERS_CLEAN_TABLE', 'local_reminders'); define('REMINDERS_ENABLED_KEY', 'enabled'); +define('REMINDERS_SUPPORTED_OVERRIDES', array('assign', 'quiz')); +define('REMINDERS_SUPPORTED_OVERRIDES_REF_IDS', array('assign' => 'assignid', 'quiz' => 'quiz')); + + /** * ======== FUNCTIONS ========================================= */ diff --git a/locallib.php b/locallib.php index 87218f6..ecddfab 100644 --- a/locallib.php +++ b/locallib.php @@ -287,7 +287,7 @@ function handle_course_activity_event($event, $course, $cm, $options) { $showtrace && mtrace(" [Local Reminder] Event #".$event->id." is a user overridden ".$event->modulename." event."); $user = $DB->get_record('user', array('id' => $event->userid)); $sendusers[] = $user; - } else if ($event->courseid <= 0 && $event->groupid > 0) { + } else if ($event->groupid > 0) { // A group overridden activity. $showtrace && mtrace(" [Local Reminder] Event #".$event->id." is a group overridden ".$event->modulename." event."); $group = $DB->get_record('groups', array('id' => $event->groupid)); @@ -296,6 +296,7 @@ function handle_course_activity_event($event, $course, $cm, $options) { // Here 'ra.id field added to avoid printing debug message, // from get_role_users (has odd behaivior when called with an array for $roleid param'. $sendusers = get_active_role_users($options->activityroleids, $context); + $sendusers = filter_user_group_overrides($event, $sendusers, $showtrace); // Filter user list, // see: https://docs.moodle.org/dev/Availability_API. @@ -689,12 +690,61 @@ function get_correct_timeformat_user($user) { * @return array of user records */ function get_active_role_users($activityroleids, $context) { - return get_role_users($activityroleids, $context, true, 'ra.id, u.*', + return get_role_users($activityroleids, $context, true, 'ra.id as ra_id, u.*', null, false, '', '', '', 'ue.status = :userenrolstatus', array('userenrolstatus' => ENROL_USER_ACTIVE)); } +/** + * Filter and return eligible set of users after excluding users who belongs + * in overridden extensions. + * + * @param object $event source event object. + * @param array $sendusers all users for this activity instance. + * @param bool $showtrace to print logs or not. + * @return array filtered out users. + */ +function filter_user_group_overrides($event, $sendusers, $showtrace) { + global $DB; + + if (!in_array($event->modulename, REMINDERS_SUPPORTED_OVERRIDES)) { + return $sendusers; + } + + $showtrace && mtrace(" [Local Reminder] Event supports overrides for key "); + $idcolumn = REMINDERS_SUPPORTED_OVERRIDES_REF_IDS[$event->modulename]; + $overridesrecords = $DB->get_records($event->modulename.'_overrides', array($idcolumn => $event->instance)); + if (empty($overridesrecords)) { + $showtrace && mtrace(" [Local Reminder] No overrides for activity ".$event->instance."!"); + return $sendusers; + } + + $extendedusers = []; + foreach ($overridesrecords as $record) { + if ($record->userid > 0) { + $showtrace && mtrace(" Overrides for user id: ".$record->userid); + $extendedusers[] = $record->userid; + } else if ($record->groupid > 0) { + $showtrace && mtrace(" Overrides for group id: ".$record->groupid); + $groupmemberroles = groups_get_members_by_role($record->groupid, $event->courseid, 'u.id'); + if (!empty($groupmemberroles)) { + foreach ($groupmemberroles as $roleid => $roledata) { + foreach ($roledata->users as $member) { + $extendedusers[] = $member->id; + } + } + } + } + } + + $finalarray = array_filter($sendusers, function($it) use ($extendedusers) { + return !in_array($it->id, $extendedusers); + }); + return $finalarray; +} + + /** * Returns all users belong to the given group. * diff --git a/reminder.class.php b/reminder.class.php index f4eb9d4..c60cdf6 100644 --- a/reminder.class.php +++ b/reminder.class.php @@ -90,6 +90,17 @@ abstract class local_reminder { * @var string */ protected $footerstyle = 'background-color:#f6f6f6;'. + 'color:#888;'. + 'border-top:1px solid #ccc;'. + 'font-family:Arial,Sans-serif;'. + 'font-size:11px;'. + 'padding: 0px;'; + /** + * CSS styles for default footer content. + * + * @var string + */ + protected $footerdefstyle = 'background-color:#f6f6f6;'. 'color:#888;'. 'border-top:1px solid #ccc;'. 'font-family:Arial,Sans-serif;'. @@ -221,6 +232,22 @@ protected function get_html_header() { return html_writer::tag('head', ''); } + /** + * Returns the header content of the reminder email. This part can be use to brand + * all of these email messages, such as with logo etc. + * + */ + protected function get_reminder_header() { + global $CFG; + + if (isset($CFG->local_reminders_emailheadercustom) && trim($CFG->local_reminders_emailheadercustom) !== '') { + $htmltext = html_writer::start_tag('div'); + $htmltext .= text_to_html($CFG->local_reminders_emailheadercustom, false, false, true); + return $htmltext.html_writer::end_tag('div'); + } + return ''; + } + /** * Returns time zone info for a user in plain text format. * @@ -251,14 +278,24 @@ protected function pluralize($number, $text) { protected function get_html_footer() { global $CFG; + $footer = html_writer::start_tag('tr'); $moodlecalendarname = get_string('moodlecalendarname', 'local_reminders'); $calendarlink = html_writer::link($CFG->wwwroot.'/calendar/index.php', $moodlecalendarname, array('target' => '_blank')); - $footer = html_writer::start_tag('tr'); - $footer .= html_writer::start_tag('td', array('style' => $this->footerstyle, 'colspan' => 2)); - $footer .= get_string('reminderfrom', 'local_reminders').' '; - $footer .= $calendarlink; - $footer .= html_writer::end_tag('td').html_writer::end_tag('tr'); + if (isset($CFG->local_reminders_emailfooterdefaultenabled) && $CFG->local_reminders_emailfooterdefaultenabled) { + $footer .= html_writer::start_tag('td', array('style' => $this->footerdefstyle, 'colspan' => 2)); + $footer .= get_string('reminderfrom', 'local_reminders').' '; + $footer .= $calendarlink; + + } else if (isset($CFG->local_reminders_emailfootercustom) && trim($CFG->local_reminders_emailfootercustom) !== '') { + $footer .= html_writer::start_tag('td', array('style' => $this->footerstyle, 'colspan' => 2)); + $footer .= text_to_html($CFG->local_reminders_emailfootercustom, false, false, true); + + } else { + return ''; + } + + $footer .= html_writer::end_tag('td').html_writer::end_tag('tr'); return $footer; } diff --git a/settings.php b/settings.php index 8ead85f..fa85269 100644 --- a/settings.php +++ b/settings.php @@ -92,6 +92,25 @@ array(), $excludedoptions)); + // REMINDER EMAIL CONFIGURATIONS. + $settings->add(new admin_setting_heading('local_reminders_heading_emailcutomizations', + get_string('emailconfigsheading', 'local_reminders'), '')); + + $settings->add(new admin_setting_confightmleditor('local_reminders_emailheadercustom', + get_string('emailheadercustomname', 'local_reminders'), + get_string('emailheadercustomnamedesc', 'local_reminders'), '')); + + $settings->add(new admin_setting_configcheckbox('local_reminders_emailfooterdefaultenabled', + get_string('emailfooterdefaultname', 'local_reminders'), + get_string('emailfooterdefaultnamedesc', 'local_reminders'), 1)); + + $settings->add(new admin_setting_confightmleditor('local_reminders_emailfootercustom', + get_string('emailfootercustomname', 'local_reminders'), + get_string('emailfootercustomnamedesc', 'local_reminders'), '')); + + // END OF EMAIL CONFIGURATIONS. + + $daysarray = array('days7' => ' '.get_string('days7', 'local_reminders'), 'days3' => ' '.get_string('days3', 'local_reminders'), 'days1' => ' '.get_string('days1', 'local_reminders')); @@ -305,4 +324,4 @@ $settings->add(new admin_setting_configcheckbox('local_reminders_enable_categoryforcalevents', get_string('enabledforcalevents', 'local_reminders'), get_string('enabledforcaleventsdescription', 'local_reminders'), 0)); -} \ No newline at end of file +} diff --git a/version.php b/version.php index 30b0651..0f4802d 100644 --- a/version.php +++ b/version.php @@ -25,8 +25,8 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2021062000; +$plugin->version = 2021092600; $plugin->requires = 2018051700; // Require moodle 3.5 or higher. -$plugin->release = '2.4'; -$plugin->maturity = MATURITY_RC; +$plugin->release = '2.5'; +$plugin->maturity = MATURITY_STABLE; $plugin->component = 'local_reminders';