MDL-81924 smsgateway_aws: Add AWS sms gateway plugin

Originally implemented as MDL-80961.
This commit is contained in:
Safat 2024-04-17 12:50:24 +10:00 committed by Huong Nguyen
parent 10c3e4b770
commit a5f100e6dd
No known key found for this signature in database
GPG key ID: 40D88AB693A3E72A
11 changed files with 511 additions and 1 deletions

View file

@ -315,4 +315,33 @@ class manager {
timecreated: $record->timecreated,
);
}
/**
* This function internationalises a number to E.164 standard.
* https://46elks.com/kb/e164
*
* @param string $phonenumber the phone number to format.
* @param ?string $countrycode The country code of the phone number.
* @return string the formatted phone number.
*/
public static function format_number(
string $phonenumber,
?string $countrycode = null,
): string {
// Remove all whitespace, dashes, and brackets in one step.
$phonenumber = preg_replace('/[ ()-]/', '', $phonenumber);
// Check if the number is already in international format or if it starts with a 0.
if (!str_starts_with($phonenumber, '+')) {
// Strip leading 0.
if (str_starts_with($phonenumber, '0')) {
$phonenumber = substr($phonenumber, 1);
}
// Prepend country code if not already in international format.
$phonenumber = !empty($countrycode) ? '+' . $countrycode . $phonenumber : $phonenumber;
}
return $phonenumber;
}
}

View file

@ -1 +0,0 @@
This file should be removed when a gateway is added to core.

View file

@ -0,0 +1,71 @@
<?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 smsgateway_aws;
use core_sms\manager;
use core_sms\message;
use MoodleQuickForm;
/**
* AWS SMS gateway.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class gateway extends \core_sms\gateway {
#[\Override]
public function send(
message $message,
): message {
global $DB;
// Get the config from the message record.
$awsconfig = $DB->get_field(
table: 'sms_gateways',
return: 'config',
conditions: ['id' => $message->gatewayid, 'enabled' => 1, 'gateway' => 'smsgateway_aws\gateway',],
);
$status = \core_sms\message_status::GATEWAY_NOT_AVAILABLE;
if ($awsconfig) {
$config = (object)json_decode($awsconfig, true, 512, JSON_THROW_ON_ERROR);
$class = '\smsgateway_aws\local\service\\' . $config->gateway;
$recipientnumber = manager::format_number(
phonenumber: $message->recipientnumber,
countrycode: isset($config->countrycode) ?? null,
);
if (class_exists($class)) {
$status = call_user_func(
$class . '::send_sms_message',
$message->content,
$recipientnumber,
$config,
);
}
}
return $message->with(
status: $status,
);
}
#[\Override]
public function get_send_priority(message $message): int {
return 50;
}
}

View file

@ -0,0 +1,28 @@
<?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 smsgateway_aws;
/**
* AWS SMS gateway helpers.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
}

View file

@ -0,0 +1,43 @@
<?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 smsgateway_aws\local;
use core_sms\message_status;
use stdClass;
/**
* AWS SMS service provider interface to provide a standard interface for different aws service providers like sns, sqs etc.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface aws_sms_service_provider {
/**
* Sends an SMS message using the selected aws service provider.
*
* @param string $messagecontent the content to send in the SMS message.
* @param string $phonenumber the destination for the message.
* @return message_status Status of the message.
*/
public static function send_sms_message(
string $messagecontent,
string $phonenumber,
stdclass $config,
): message_status;
}

View file

@ -0,0 +1,90 @@
<?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 smsgateway_aws\local\service;
use core\aws\aws_helper;
use core_sms\message_status;
use smsgateway_aws\local\aws_sms_service_provider;
use stdClass;
/**
* AWS SNS service provider.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class aws_sns implements aws_sms_service_provider {
/**
* Include the required calls.
*/
private static function require(): void {
global $CFG;
require_once($CFG->libdir . '/aws-sdk/src/functions.php');
}
#[\Override]
public static function send_sms_message(
string $messagecontent,
string $phonenumber,
stdclass $config,
): message_status {
global $SITE;
self::require();
// Setup client params and instantiate client.
$params = [
'version' => 'latest',
'region' => $config->api_region,
'http' => ['proxy' => aws_helper::get_proxy_string()],
];
if (!property_exists($config, 'usecredchain') || !$config->usecredchain) {
$params['credentials'] = [
'key' => $config->api_key,
'secret' => $config->api_secret,
];
}
$client = new \Aws\Sns\SnsClient($params);
// Set up the sender information.
$senderid = $SITE->shortname;
// Remove spaces and non-alphanumeric characters from ID.
$senderid = preg_replace("/[^A-Za-z0-9]/", '', trim($senderid));
// We have to truncate the senderID to 11 chars.
$senderid = substr($senderid, 0, 11);
try {
// These messages need to be transactional.
$client->SetSMSAttributes([
'attributes' => [
'DefaultSMSType' => 'Transactional',
'DefaultSenderID' => $senderid,
],
]);
// Actually send the message.
$client->publish([
'Message' => $messagecontent,
'PhoneNumber' => $phonenumber,
]);
return \core_sms\message_status::GATEWAY_SENT;
} catch (\Aws\Exception\AwsException $e) {
return \core_sms\message_status::GATEWAY_NOT_AVAILABLE;
}
}
}

View file

@ -0,0 +1,35 @@
<?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 smsgateway_aws\privacy;
use core_privacy\local\metadata\null_provider;
/**
* Privacy Subsystem for smsgateway_aws implementing null_provider.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @codeCoverageIgnore
*/
class provider implements null_provider {
#[\Override]
public static function get_reason(): string {
return 'privacy:metadata';
}
}

View file

@ -0,0 +1,42 @@
<?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/>.
/**
* Strings for component smsgateway_aws, language 'en'.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['api_key'] = 'Key';
$string['api_key_help'] = 'Amazon API key credential.';
$string['api_region'] = 'Region';
$string['api_region_help'] = 'Amazon API gateway region.';
$string['api_secret'] = 'Secret';
$string['api_secret_help'] = 'Amazon API secret credential.';
$string['aws_sns'] = 'AWS SNS';
$string['countrycode'] = 'Country number code';
$string['countrycode_help'] = 'The calling code without the leading + as a default if users do not enter an international number with a + prefix.
See this link for a list of calling codes: {$a}';
$string['gateway'] = 'SMS Gateway';
$string['gateway_help'] = 'The SMS provider you wish to send messages via';
$string['pluginname'] = 'AWS';
$string['privacy:metadata'] = 'The AWS SMS gateway plugin does not store any personal data.';
$string['usecredchain'] = 'Find AWS credentials using the default credential provider chain';

View file

@ -0,0 +1,64 @@
<?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 smsgateway_aws;
use core_sms\message;
/**
* AWS SMS gateway tests.
*
* @package smsgateway_aws
* @category test
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \smsgateway_aws\gateway
*/
class gateway_test extends \advanced_testcase {
public function test_update_message_status(): void {
$this->resetAfterTest();
$manager = \core\di::get(\core_sms\manager::class);
$gw = $manager->create_gateway_instance(gateway::class, true);
$othergw = $manager->create_gateway_instance(gateway::class, true);
$message = new message(
recipientnumber: '1234567890',
content: 'Hello, world!',
component: 'smsgateway_aws',
messagetype: 'test',
recipientuserid: null,
sensitive: false,
gatewayid: $gw->id,
);
$message2 = new message(
recipientnumber: '1234567890',
content: 'Hello, world!',
component: 'smsgateway_aws',
messagetype: 'test',
recipientuserid: null,
sensitive: false,
gatewayid: $gw->id,
);
$updatedmessages = $gw->update_message_statuses([$message, $message2]);
$this->assertEquals([$message, $message2], $updatedmessages);
$this->expectException(\coding_exception::class);
$othergw->update_message_status($message);
}
}

View file

@ -0,0 +1,79 @@
<?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 smsgateway_aws;
/**
* AWS SMS gateway helper tests.
*
* @package smsgateway_aws
* @category test
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \smsgateway_aws\helper
*/
class helper_test extends \advanced_testcase {
/**
* Data provider for test_format_number().
*
* @return array of different country codes and phone numbers.
*/
public function format_number_provider(): array {
return [
'Phone number with local format' => [
'phonenumber' => '0123456789',
'expected' => '+34123456789',
'countrycode' => '34',
],
'Phone number with international format' => [
'phonenumber' => '+39123456789',
'expected' => '+39123456789',
],
'Phone number with spaces using international format' => [
'phonenumber' => '+34 123 456 789',
'expected' => '+34123456789',
],
'Phone number with spaces using local format with country code' => [
'phonenumber' => '0 123 456 789',
'expected' => '+34123456789',
'countrycode' => '34',
],
'Phone number with spaces using local format without country code' => [
'phonenumber' => '0 123 456 789',
'expected' => '123456789',
],
];
}
/**
* Test format number with different phones and different country codes.
*
* @dataProvider format_number_provider
* @param string $phonenumber Phone number.
* @param string $expected Expected value.
* @param string|null $countrycode Country code.
*/
public function test_format_number(
string $phonenumber,
string $expected,
?string $countrycode = null,
): void {
$this->resetAfterTest();
$this->assertEquals($expected, \core_sms\manager::format_number($phonenumber, $countrycode));
}
}

View file

@ -0,0 +1,30 @@
<?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/>.
/**
* Version information for smsgateway_aws.
*
* @package smsgateway_aws
* @copyright 2024 Safat Shahin <safat.shahin@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'smsgateway_aws';
$plugin->version = 2024042200;
$plugin->requires = 2024041600;
$plugin->maturity = MATURITY_STABLE;