Skip to content

Commit

Permalink
Merge pull request #49 from waleedhassan5/aws_suppression_list
Browse files Browse the repository at this point in the history
WR #439133: read-only access to AWS suppression list
  • Loading branch information
marxjohnson authored Oct 18, 2024
2 parents 015e4f2 + 5385d3e commit 8b566eb
Show file tree
Hide file tree
Showing 11 changed files with 585 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ jobs:
disable_behat: true
disable_grunt: true
disable_mustache: true
extra_plugin_runners: |
moodle-plugin-ci add-plugin catalyst/moodle-local_aws
60 changes: 60 additions & 0 deletions classes/suppression_list.php
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);
}
}
175 changes: 175 additions & 0 deletions classes/task/update_suppression_list.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<?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/>.

/**
* Scheduled task for updating the email suppression list.
*
* @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
* @author Waleed ul hassan <[email protected]>
*/

namespace tool_emailutils\task;

defined('MOODLE_INTERNAL') || die();

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.');
}
}

/**
* Scheduled task class for updating the email suppression list.
*
* This task fetches the latest suppression list from AWS SES and updates
* 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(): string {
return get_string('task_update_suppression_list', 'tool_emailutils');
}

/**
* Execute the task.
*
* This method fetches the suppression list from AWS SES and updates
* the local database with the fetched information.
*
* @return void
*/
public function execute(): void {
global $DB;

$suppressionlist = $this->fetch_aws_ses_suppression_list();

$DB->delete_records('tool_emailutils_suppression');

foreach ($suppressionlist as $item) {
$record = new \stdClass();
$record->email = $item['email'];
$record->reason = $item['reason'];
$record->created_at = $item['created_at'];
$record->timecreated = time();
$record->timemodified = time();

$DB->insert_record('tool_emailutils_suppression', $record);
}
}

/**
* Fetch the suppression list from AWS SES.
*
* This method connects to AWS SES, retrieves the suppression list,
* and formats it for local storage. It includes error handling and
* retries for rate limiting.
*
* @return array The fetched suppression list.
*/
protected function fetch_aws_ses_suppression_list(): array {
if (!$this->sesclient) {
$this->sesclient = $this->create_ses_client();
}

try {
$suppressionlist = [];
$params = ['MaxItems' => 100];

do {
$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('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;

$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.
*
* This method logs error messages, ensuring they are visible both in
* the Moodle error log and on the console when run via CLI.
*
* @param string $message The error message to log.
* @return void
*/
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;
}
}
16 changes: 15 additions & 1 deletion db/install.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="admin/tool/emailutils/db" VERSION="2017060100" COMMENT="XMLDB file for plugin admin/tool/emailutils"
<XMLDB PATH="admin/tool/emailutils/db" VERSION="2024100101" COMMENT="XMLDB file for plugin admin/tool/emailutils"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
>
Expand Down Expand Up @@ -32,5 +32,19 @@
<KEY NAME="updatedid" TYPE="foreign" FIELDS="updatedid" REFTABLE="user" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="tool_emailutils_suppression" COMMENT="Stores the email suppression list">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="email" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="reason" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="created_at" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false"
COMMENT="Timestamp from AWS SES API, different from timecreated. Represents when the email was added to the suppression list."/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
38 changes: 38 additions & 0 deletions db/tasks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?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/>.

/**
* Definition of Email utils scheduled tasks.
*
* @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
* @author Waleed ul hassan <[email protected]>
*/

defined('MOODLE_INTERNAL') || die();

$tasks = [
[
'classname' => 'tool_emailutils\task\update_suppression_list',
'blocking' => 0,
'minute' => 'R',
'hour' => '3',
'day' => '*',
'month' => '*',
'dayofweek' => '*',
],
];
67 changes: 67 additions & 0 deletions db/upgrade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?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 utils plugin upgrade code.
*
* @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
* @author Waleed ul hassan <[email protected]>
*/

/**
* 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();

if ($oldversion < 2024100101) {

// Define table tool_emailutils_suppression to be created.
$table = new xmldb_table('tool_emailutils_suppression');

// Adding fields to table tool_emailutils_suppression.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('email', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
$table->add_field('reason', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null);
$table->add_field('created_at', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');

// Adding keys to table tool_emailutils_suppression.
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);

// Conditionally launch create table for tool_emailutils_suppression.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}

// Emailutils savepoint reached.
upgrade_plugin_savepoint(true, 2024100101, 'tool', 'emailutils');
}

return true;
}
Loading

0 comments on commit 8b566eb

Please sign in to comment.