Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial improvements for bounce handling reporting #63

Merged
merged 5 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions bounces.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Email bounces report.
*
* @package tool_emailutils
* @author Benjamin Walker <[email protected]>
* @copyright Catalyst IT 2024
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
*/

use core_reportbuilder\system_report_factory;
use tool_emailutils\helper;
use tool_emailutils\reportbuilder\local\systemreports\email_bounces;

require(__DIR__.'/../../../config.php');
require_once($CFG->libdir.'/adminlib.php');

admin_externalpage_setup('tool_emailutils_bounces', '', [], '', ['pagelayout' => 'report']);

echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('reportbounces', 'tool_emailutils'));

// Render config used for calculating bounce threshold.
[$handlebounces, $minbounces, $bounceratio] = helper::get_bounce_config();
if (empty($handlebounces)) {
echo $OUTPUT->notification(get_string('configmissing', 'tool_emailutils'));
} else {
echo $OUTPUT->notification(get_string('bounceconfig', 'tool_emailutils', [
'minbounces' => $minbounces,
'bounceratio' => $bounceratio,
]), 'info');
}

$report = system_report_factory::create(email_bounces::class, context_system::instance());

echo $report->output();

echo $OUTPUT->footer();
128 changes: 128 additions & 0 deletions classes/check/bounces.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* User bounces check.
*
* @package tool_emailutils
* @author Benjamin Walker <[email protected]>
* @copyright Catalyst IT 2024
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
*/

namespace tool_emailutils\check;
use \tool_emailutils\helper;
use core\check\check;
use core\check\result;

/**
* User bounces check.
*
* @package tool_emailutils
* @author Benjamin Walker <[email protected]>
* @copyright Catalyst IT 2024
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class bounces extends check {

/**
* A link to a place to action this
*
* @return \action_link|null
*/
public function get_action_link(): ?\action_link {
return new \action_link(
new \moodle_url('/admin/tool/emailutils/bounces.php'),
get_string('reportbounces', 'tool_emailutils'));
}

/**
* Get Result.
*
* @return result
*/
public function get_result() : result {
global $DB, $CFG, $OUTPUT;

$details = '';

[$handlebounces, $minbounces, $bounceratio] = helper::get_bounce_config();
if (empty($handlebounces)) {
$status = result::OK;
$summary = "Moodle is not configured to handle bounces.";
$details = $summary;
} else {
$sql = "SELECT up.userid, up.value AS bouncecount, up2.value AS sendcount
FROM {user_preferences} up
LEFT JOIN {user_preferences} up2 ON up2.name = 'email_send_count' AND up.userid = up2.userid
WHERE up.name = 'email_bounce_count' AND CAST(up.value AS INTEGER) > :threshold";
// Start with a threshold of 1 as that is the default for manually created users.
// TODO: Update when core is fixed.
$bounces = $DB->get_records_sql($sql, ['threshold' => 1]);
$userswithbounces = count($bounces);

// Split bounces into 3 groups based on whether they meet bounce threshold criteria.
$overthreshold = 0;
$overbouncereq = 0;
$underbouncereq = 0;
foreach ($bounces as $bounce) {
$bouncereq = $bounce->bouncecount >= $minbounces;
$ratioreq = !empty($bounce->sendcount) && ($bounce->bouncecount / $bounce->sendcount >= $bounceratio);
if ($bouncereq && $ratioreq) {
$overthreshold++;
} else if (!$ratioreq) {
$overbouncereq++;
} else {
$underbouncereq++;
}
}

$messages = [];
if (!$userswithbounces) {
$status = result::OK;
$summary = "No users have had emails rejected.";
} else if (!$overthreshold) {
$status = result::OK;
$summary = "No users are over the Moodle bounce threshold, but $userswithbounces have had emails rejected";
} else {
$status = result::WARNING;
$summary = "Found $overthreshold users over the Moodle bounce threshold";
$messages[] = "$overthreshold user(s) have at least $minbounces email rejections with a bounce ratio over $bounceratio";
}

if ($overbouncereq) {
$messages[] = "$overbouncereq user(s) have at least $minbounces email rejections with a bounce ratio under $bounceratio";
}

if ($underbouncereq) {
$allowedbounces = $minbounces - 1;
$messages[] = "$underbouncereq user(s) have between 1 and $allowedbounces email rejections";
}

// Render config used for calculating threshold.
$details = $OUTPUT->render_from_template('tool_emailutils/bounce_config', [
'handlebounces' => $handlebounces,
'minbounces' => $minbounces,
'bounceratio' => $bounceratio,
'breakdown' => true,
'messages' => $messages,
]);
}

return new result($status, $summary, $details);
}

}
111 changes: 0 additions & 111 deletions classes/complaints_list.php

This file was deleted.

39 changes: 39 additions & 0 deletions classes/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
*/
class helper {

/** Default bounce ratio from over_bounce_threshold() */
const DEFAULT_BOUNCE_RATIO = 0.2;

/** Default minimum bounces from over_bounce_threshold() */
const DEFAULT_MIN_BOUNCES = 10;


/**
* Gets the username fields for the fullname function. Contains legacy support for 3.9.
* @param string $tablealias
Expand All @@ -52,4 +59,36 @@ public static function get_username_fields(string $tablealias = ''): string {
return get_all_user_name_fields(true, $tablealias);
}
}

/**
*
* Gets the min bounces, otherwise return the default.
* @return int
*/
public static function get_min_bounces(): int {
global $CFG;
return $CFG->minbounce ?? self::DEFAULT_MIN_BOUNCES;
}

/**
* Gets the bounce rate config, otherwise return the default.
* @return float
*/
public static function get_bounce_ratio(): float {
global $CFG;
return $CFG->bounceratio ?? self::DEFAULT_BOUNCE_RATIO;
}

/**
* Gets the bounce config, or the defaults.
* @return array [handlebounces, minbounces, bounceratio]
*/
public static function get_bounce_config(): array {
global $CFG;
return [
$CFG->handlebounces,
self::get_min_bounces(),
self::get_bounce_ratio(),
];
}
}
Loading
Loading