-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WR #439133: PR changes and updated the tests to be more meaningful
Added changes asked by Mark on PR and also made some changes to the code to have more meaningful unit tests
- Loading branch information
1 parent
4b3bfa0
commit 62bac8a
Showing
9 changed files
with
247 additions
and
260 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<?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/>. | ||
|
||
namespace tool_emailutils; | ||
|
||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
require_once($CFG->libdir . '/csvlib.class.php'); | ||
|
||
/** | ||
* Class for handling suppression list operations. | ||
* | ||
* @package tool_emailutils | ||
* @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class suppression_list { | ||
|
||
/** | ||
* Generate CSV content for the suppression list. | ||
* | ||
* @return string The CSV content. | ||
* @throws \dml_exception | ||
*/ | ||
public static function generate_csv(): string { | ||
global $DB; | ||
|
||
$csvexport = new \csv_export_writer('comma'); | ||
|
||
// Add CSV headers. | ||
$csvexport->add_data(['Email', 'Reason', 'Created At']); | ||
|
||
// Fetch suppression list from database. | ||
$suppressionlist = $DB->get_records('tool_emailutils_suppression'); | ||
|
||
// Add suppression list data to CSV. | ||
foreach ($suppressionlist as $item) { | ||
$csvexport->add_data([ | ||
$item->email, | ||
$item->reason, | ||
$item->created_at, | ||
]); | ||
} | ||
|
||
return $csvexport->print_csv_data(true); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,14 +18,13 @@ | |
* Scheduled task for updating the email suppression list. | ||
* | ||
* @package tool_emailutils | ||
* @copyright 2019 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
* @author Waleed ul hassan <[email protected]> | ||
*/ | ||
|
||
namespace tool_emailutils\task; | ||
|
||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
/** | ||
* Scheduled task class for updating the email suppression list. | ||
|
@@ -34,12 +33,15 @@ | |
* the local database with this information. | ||
*/ | ||
class update_suppression_list extends \core\task\scheduled_task { | ||
/** @var \Aws\SesV2\SesV2Client|null */ | ||
protected $sesclient = null; | ||
|
||
/** | ||
* Return the task's name as shown in admin screens. | ||
* | ||
* @return string The name of the task. | ||
*/ | ||
public function get_name() { | ||
public function get_name(): string { | ||
return get_string('task_update_suppression_list', 'tool_emailutils'); | ||
} | ||
|
||
|
@@ -51,7 +53,7 @@ public function get_name() { | |
* | ||
* @return void | ||
*/ | ||
public function execute() { | ||
public function execute(): void { | ||
global $DB; | ||
|
||
$suppressionlist = $this->fetch_aws_ses_suppression_list(); | ||
|
@@ -79,80 +81,72 @@ public function execute() { | |
* | ||
* @return array The fetched suppression list. | ||
*/ | ||
protected function fetch_aws_ses_suppression_list() { | ||
global $CFG; | ||
require_once($CFG->dirroot . '/local/aws/sdk/aws-autoloader.php'); | ||
require_once($CFG->dirroot . '/local/aws/sdk/Aws/SesV2/SesV2Client.php'); | ||
|
||
$awsregion = get_config('tool_emailutils', 'aws_region'); | ||
$awskey = get_config('tool_emailutils', 'aws_key'); | ||
$awssecret = get_config('tool_emailutils', 'aws_secret'); | ||
|
||
if (empty($awsregion) || empty($awskey) || empty($awssecret)) { | ||
$this->log_error('AWS credentials are not configured. Please set them in the plugin settings.'); | ||
return []; | ||
protected function fetch_aws_ses_suppression_list(): array { | ||
if (!$this->sesclient) { | ||
$this->sesclient = $this->create_ses_client(); | ||
} | ||
|
||
try { | ||
$sesv2 = new \Aws\SesV2\SesV2Client([ | ||
'version' => 'latest', | ||
'region' => $awsregion, | ||
'credentials' => [ | ||
'key' => $awskey, | ||
'secret' => $awssecret, | ||
], | ||
'retries' => [ | ||
'mode' => 'adaptive', | ||
'max_attempts' => 10, | ||
], | ||
]); | ||
|
||
$suppressionlist = []; | ||
$params = ['MaxItems' => 100]; // Reduced from 1000 to 100 to lower the chance of rate limiting. | ||
$params = ['MaxItems' => 100]; | ||
|
||
do { | ||
$retries = 0; | ||
$maxretries = 5; | ||
$delay = 1; | ||
|
||
while ($retries < $maxretries) { | ||
try { | ||
$result = $sesv2->listSuppressedDestinations($params); | ||
break; // If successful, exit the retry loop. | ||
} catch (\Aws\Exception\AwsException $e) { | ||
if ($e->getAwsErrorCode() === 'TooManyRequestsException') { | ||
$retries++; | ||
if ($retries >= $maxretries) { | ||
$this->log_error('Max retries reached for AWS SES API call: ' . $e->getMessage()); | ||
return []; // Return empty array after max retries. | ||
} | ||
$this->log_error("Rate limit hit, retrying in {$delay} seconds..."); | ||
sleep($delay); // Wait before retrying. | ||
$delay *= 2; // Exponential backoff. | ||
} else { | ||
$this->log_error('AWS SES Error: ' . $e->getMessage()); | ||
return []; // Return empty array for other AWS exceptions. | ||
} | ||
} | ||
} | ||
$result = $this->sesclient->listSuppressedDestinations($params); | ||
foreach ($result['SuppressedDestinationSummaries'] as $item) { | ||
$suppressionlist[] = [ | ||
'email' => $item['EmailAddress'], | ||
'reason' => $item['Reason'], | ||
'created_at' => $item['LastUpdateTime']->format('Y-m-d H:i:s'), | ||
]; | ||
} | ||
|
||
$params['NextToken'] = $result['NextToken'] ?? null; | ||
} while ($params['NextToken']); | ||
|
||
return $suppressionlist; | ||
} catch (\Exception $e) { | ||
$this->log_error('Unexpected error: ' . $e->getMessage()); | ||
$this->log_error('Error fetching suppression list: ' . $e->getMessage()); | ||
return []; | ||
} | ||
} | ||
|
||
/** | ||
* Create an SES client instance. | ||
* | ||
* @return \Aws\SesV2\SesV2Client | ||
*/ | ||
protected function create_ses_client(): \Aws\SesV2\SesV2Client { | ||
global $CFG; | ||
|
||
if (!class_exists('\Aws\SesV2\SesV2Client')) { | ||
if (file_exists($CFG->dirroot . '/local/aws/sdk/aws-autoloader.php')) { | ||
require_once($CFG->dirroot . '/local/aws/sdk/aws-autoloader.php'); | ||
} else { | ||
throw new \Exception('AWS SDK not found.'); | ||
} | ||
} | ||
|
||
$awsregion = get_config('tool_emailutils', 'aws_region'); | ||
$awskey = get_config('tool_emailutils', 'aws_key'); | ||
$awssecret = get_config('tool_emailutils', 'aws_secret'); | ||
|
||
if (empty($awsregion) || empty($awskey) || empty($awssecret)) { | ||
throw new \Exception('AWS credentials are not configured.'); | ||
} | ||
|
||
return new \Aws\SesV2\SesV2Client([ | ||
'version' => 'latest', | ||
'region' => $awsregion, | ||
'credentials' => [ | ||
'key' => $awskey, | ||
'secret' => $awssecret, | ||
], | ||
'retries' => [ | ||
'mode' => 'adaptive', | ||
'max_attempts' => 10, | ||
], | ||
]); | ||
} | ||
|
||
/** | ||
* Log an error message, printing to console if running via CLI. | ||
* | ||
|
@@ -162,10 +156,19 @@ protected function fetch_aws_ses_suppression_list() { | |
* @param string $message The error message to log. | ||
* @return void | ||
*/ | ||
private function log_error($message) { | ||
private function log_error(string $message): void { | ||
if (CLI_SCRIPT) { | ||
mtrace($message); | ||
} | ||
debugging($message); | ||
} | ||
} | ||
|
||
/** | ||
* Set the SES client (for testing purposes). | ||
* | ||
* @param \Aws\SesV2\SesV2Client $client | ||
*/ | ||
public function set_ses_client(\Aws\SesV2\SesV2Client $client): void { | ||
$this->sesclient = $client; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ | |
* Definition of Email utils scheduled tasks. | ||
* | ||
* @package tool_emailutils | ||
* @copyright 2019 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
* @author Waleed ul hassan <[email protected]> | ||
*/ | ||
|
@@ -29,7 +29,7 @@ | |
[ | ||
'classname' => 'tool_emailutils\task\update_suppression_list', | ||
'blocking' => 0, | ||
'minute' => '0', | ||
'minute' => 'R', | ||
'hour' => '3', | ||
'day' => '*', | ||
'month' => '*', | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,13 +18,22 @@ | |
* Email utils plugin upgrade code. | ||
* | ||
* @package tool_emailutils | ||
* @copyright 2019 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/} | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
* @author Waleed ul hassan <[email protected]> | ||
*/ | ||
|
||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
/** | ||
* Upgrade script for the email utilities tool plugin. | ||
* | ||
* This function is executed during the plugin upgrade process. | ||
* It checks the current version of the plugin and applies | ||
* necessary upgrades, such as creating new database tables | ||
* or modifying existing structures. | ||
* | ||
* @param int $oldversion The version we are upgrading from. | ||
* @return bool Always returns true. | ||
*/ | ||
function xmldb_tool_emailutils_upgrade($oldversion) { | ||
global $DB; | ||
$dbman = $DB->get_manager(); | ||
|
@@ -45,9 +54,6 @@ function xmldb_tool_emailutils_upgrade($oldversion) { | |
// Adding keys to table tool_emailutils_suppression. | ||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); | ||
|
||
// Adding indexes to table tool_emailutils_suppression. | ||
$table->add_index('email', XMLDB_INDEX_UNIQUE, ['email']); | ||
|
||
// Conditionally launch create table for tool_emailutils_suppression. | ||
if (!$dbman->table_exists($table)) { | ||
$dbman->create_table($table); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.