From 4a17116a6bbc427968eb5b7d1afedad23429a22f Mon Sep 17 00:00:00 2001 From: Michael Hawkins Date: Sat, 14 Sep 2024 02:15:46 +0800 Subject: [PATCH] fixup! MDL-81924 core_sms: Add SMS gateway management UI --- lang/en/moodle.php | 2 - lang/en/sms.php | 2 +- sms/amd/build/smsgatewaychooser.min.js | 2 +- sms/amd/build/smsgatewaychooser.min.js.map | 2 +- sms/amd/build/smsgatewaytoggle.min.js | 10 -- sms/amd/build/smsgatewaytoggle.min.js.map | 1 - sms/amd/src/smsgatewaychooser.js | 2 +- sms/amd/src/smsgatewaytoggle.js | 154 ------------------ sms/classes/external/sms_gateway_status.php | 38 ++++- sms/classes/table/sms_gateway_table.php | 74 +++------ sms/gateway/aws/classes/gateway.php | 105 ++++++++++++ sms/sms_gateways.php | 2 +- sms/templates/sms_action_icons.mustache | 29 ++-- sms/templates/sms_gateway_toggle.mustache | 53 ------ sms/templates/sms_gateways.mustache | 24 +-- .../external/sms_gateway_status_test.php | 8 +- 16 files changed, 191 insertions(+), 317 deletions(-) delete mode 100644 sms/amd/build/smsgatewaytoggle.min.js delete mode 100644 sms/amd/build/smsgatewaytoggle.min.js.map delete mode 100644 sms/amd/src/smsgatewaytoggle.js delete mode 100644 sms/templates/sms_gateway_toggle.mustache diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 2dbc94b841dc2..7dda4eadbc964 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -560,7 +560,6 @@ $string['digitalminor_desc'] = 'Please ask your parent/guardian to contact:'; $string['directory'] = 'Directory'; $string['disable'] = 'Disable'; -$string['disabled'] = 'Disabled'; $string['disabledcomments'] = 'Comments are disabled'; $string['dismissnotification'] = 'Dismiss this notification'; $string['displayingfirst'] = 'Only the first {$a->count} {$a->things} are displayed'; @@ -793,7 +792,6 @@ $string['emptydragdropregion'] = 'empty region'; $string['emptysectionids'] = 'Empty section IDs'; $string['enable'] = 'Enable'; -$string['enabled'] = 'Enabled'; $string['encryptedcode'] = 'Encrypted code'; $string['enddate'] = 'Course end date'; $string['enddate_help'] = 'The end date doesn’t restrict student access to the course. It determines whether a course is listed as Past in My courses.'; diff --git a/lang/en/sms.php b/lang/en/sms.php index 1a5f6fad02c84..3a11332facf5c 100644 --- a/lang/en/sms.php +++ b/lang/en/sms.php @@ -28,7 +28,7 @@ $string['countrycode_help'] = 'Set the default phone number format to exclude the "+" symbol if user does not enter an international number with it.'; $string['createnewgateway'] = 'Create a new SMS gateway'; $string['delete_sms_gateway'] = 'Delete SMS gateway'; -$string['delete_sms_gateway_confirmation'] = 'Are you sure you want to delete the SMS gateway?'; +$string['delete_sms_gateway_confirmation'] = 'Are you sure you want to delete the {$a->gateway} SMS gateway?'; $string['gateway'] = 'Gateway'; $string['gateway_name'] = 'Gateway name'; $string['manage_sms_gateways'] = 'Manage SMS gateways'; diff --git a/sms/amd/build/smsgatewaychooser.min.js b/sms/amd/build/smsgatewaychooser.min.js index affce94db7e4d..38c9f679af4af 100644 --- a/sms/amd/build/smsgatewaychooser.min.js +++ b/sms/amd/build/smsgatewaychooser.min.js @@ -6,6 +6,6 @@ define("core_sms/smsgatewaychooser",["exports"],(function(_exports){Object.defin * @copyright 2024 Safat Shahin * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -const Selectors_fields={selector:'[data-smsgatewaychooser-field="selector"]',updateButton:'[data-smsgatewaychooser-field="updateButton"]'};_exports.init=()=>{document.querySelector(Selectors_fields.selector).addEventListener("change",(e=>{const form=e.target.closest("form"),updateButton=form.querySelector(Selectors_fields.updateButton),url=new URL(form.action);form.action=url.toString(),updateButton.click()}))}})); +const Selectors_fields={selector:'[data-smsgatewaychooser-field="selector"]',updateButton:'[data-smsgatewaychooser-field="updateButton"]'};_exports.init=()=>{var _document$querySelect;null===(_document$querySelect=document.querySelector(Selectors_fields.selector))||void 0===_document$querySelect||_document$querySelect.addEventListener("change",(e=>{const form=e.target.closest("form"),updateButton=form.querySelector(Selectors_fields.updateButton),url=new URL(form.action);form.action=url.toString(),updateButton.click()}))}})); //# sourceMappingURL=smsgatewaychooser.min.js.map \ No newline at end of file diff --git a/sms/amd/build/smsgatewaychooser.min.js.map b/sms/amd/build/smsgatewaychooser.min.js.map index a7afc97368ecb..4761ccee7d787 100644 --- a/sms/amd/build/smsgatewaychooser.min.js.map +++ b/sms/amd/build/smsgatewaychooser.min.js.map @@ -1 +1 @@ -{"version":3,"file":"smsgatewaychooser.min.js","sources":["../src/smsgatewaychooser.js"],"sourcesContent":["\n// This file is part of Moodle - http://moodle.org/ //\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * SMS gateway selection handler.\n *\n * @module core_sms/smsgatewaychooser\n * @copyright 2024 Safat Shahin \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst Selectors = {\n fields: {\n selector: '[data-smsgatewaychooser-field=\"selector\"]',\n updateButton: '[data-smsgatewaychooser-field=\"updateButton\"]',\n },\n};\n\n/**\n * Initialise the sms gateway chooser.\n */\nexport const init = () => {\n document.querySelector(Selectors.fields.selector).addEventListener('change', e => {\n const form = e.target.closest('form');\n const updateButton = form.querySelector(Selectors.fields.updateButton);\n const url = new URL(form.action);\n\n form.action = url.toString();\n updateButton.click();\n });\n};\n"],"names":["Selectors","selector","updateButton","document","querySelector","addEventListener","e","form","target","closest","url","URL","action","toString","click"],"mappings":";;;;;;;;MAuBMA,iBACM,CACJC,SAAU,4CACVC,aAAc,+DAOF,KAChBC,SAASC,cAAcJ,iBAAiBC,UAAUI,iBAAiB,UAAUC,UACnEC,KAAOD,EAAEE,OAAOC,QAAQ,QACxBP,aAAeK,KAAKH,cAAcJ,iBAAiBE,cACnDQ,IAAM,IAAIC,IAAIJ,KAAKK,QAEzBL,KAAKK,OAASF,IAAIG,WAClBX,aAAaY"} \ No newline at end of file +{"version":3,"file":"smsgatewaychooser.min.js","sources":["../src/smsgatewaychooser.js"],"sourcesContent":["\n// This file is part of Moodle - http://moodle.org/ //\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * SMS gateway selection handler.\n *\n * @module core_sms/smsgatewaychooser\n * @copyright 2024 Safat Shahin \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst Selectors = {\n fields: {\n selector: '[data-smsgatewaychooser-field=\"selector\"]',\n updateButton: '[data-smsgatewaychooser-field=\"updateButton\"]',\n },\n};\n\n/**\n * Initialise the sms gateway chooser.\n */\nexport const init = () => {\n document.querySelector(Selectors.fields.selector)?.addEventListener('change', e => {\n const form = e.target.closest('form');\n const updateButton = form.querySelector(Selectors.fields.updateButton);\n const url = new URL(form.action);\n\n form.action = url.toString();\n updateButton.click();\n });\n};\n"],"names":["Selectors","selector","updateButton","document","querySelector","addEventListener","e","form","target","closest","url","URL","action","toString","click"],"mappings":";;;;;;;;MAuBMA,iBACM,CACJC,SAAU,4CACVC,aAAc,+DAOF,6DAChBC,SAASC,cAAcJ,iBAAiBC,kEAAWI,iBAAiB,UAAUC,UACpEC,KAAOD,EAAEE,OAAOC,QAAQ,QACxBP,aAAeK,KAAKH,cAAcJ,iBAAiBE,cACnDQ,IAAM,IAAIC,IAAIJ,KAAKK,QAEzBL,KAAKK,OAASF,IAAIG,WAClBX,aAAaY"} \ No newline at end of file diff --git a/sms/amd/build/smsgatewaytoggle.min.js b/sms/amd/build/smsgatewaytoggle.min.js deleted file mode 100644 index b2a22e90bc8ea..0000000000000 --- a/sms/amd/build/smsgatewaytoggle.min.js +++ /dev/null @@ -1,10 +0,0 @@ -define("core_sms/smsgatewaytoggle",["exports","core_table/dynamic","core_table/local/dynamic/selectors","core/ajax","core/notification","core/pending","core/str"],(function(_exports,_dynamic,Selectors,_ajax,_notification,_pending,_str){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Selectors=_interopRequireWildcard(Selectors),_notification=_interopRequireWildcard(_notification),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};let watching=!1; -/** - * SMS gateway status handler. - * - * @module core_sms/smsgatewaytoggle - * @copyright 2024 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */return _exports.default=class{constructor(){!function(obj,key,value){key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}(this,"clickHandlers",[]),this.addClickHandler(this.handleStateToggle),this.registerEventListeners()}static init(){watching||(watching=!0,new this)}addClickHandler(handler){this.clickHandlers.push(handler.bind(this))}registerEventListeners(){document.addEventListener("click",function(e){const tableRoot=this.getTableRoot(e);tableRoot&&this.clickHandlers.forEach((handler=>handler(tableRoot,e)))}.bind(this))}getTableRoot(e){const tableRoot=e.target.closest(Selectors.main.region);return tableRoot||!1}setGatewayState(methodname,gatewayid,enabled){return(0,_ajax.call)([{methodname:methodname,args:{gatewayid:gatewayid,enabled:enabled}}])[0]}async handleStateToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="togglestate"][data-toggle-method]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:togglestate"),response=await this.setGatewayState(stateToggle.dataset.toggleMethod,parseInt(stateToggle.dataset.gatewayid),"1"!==stateToggle.dataset.state);response.result||(0,_str.getStrings)([{key:response.message,component:"sms"}]).then((_ref=>{let[message]=_ref;return _notification.default.addNotification({message:message,type:response.messageType})})).catch(_notification.default.exception);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="togglestate"][data-gatewayid="'.concat(stateToggle.dataset.gatewayid,'"]')).focus(),pendingPromise.resolve()}}},_exports.default})); - -//# sourceMappingURL=smsgatewaytoggle.min.js.map \ No newline at end of file diff --git a/sms/amd/build/smsgatewaytoggle.min.js.map b/sms/amd/build/smsgatewaytoggle.min.js.map deleted file mode 100644 index 43636774e87e7..0000000000000 --- a/sms/amd/build/smsgatewaytoggle.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"smsgatewaytoggle.min.js","sources":["../src/smsgatewaytoggle.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\nimport {refreshTableContent} from 'core_table/dynamic';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\nimport {call as fetchMany} from 'core/ajax';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport {getStrings} from 'core/str';\nimport {fetchNotifications} from 'core/notification';\n\nlet watching = false;\n\n/**\n * SMS gateway status handler.\n *\n * @module core_sms/smsgatewaytoggle\n * @copyright 2024 Safat Shahin \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n /**\n * @property {function[]} clickHandlers a list of handlers to call on click.\n */\n clickHandlers = [];\n\n constructor() {\n this.addClickHandler(this.handleStateToggle);\n this.registerEventListeners();\n }\n\n /**\n * Initialise an instance of the class.\n *\n * This is just a way of making it easier to initialise an instance of the class from PHP.\n */\n static init() {\n if (watching) {\n return;\n }\n watching = true;\n new this();\n }\n\n /**\n * Add a click handler to the list of handlers.\n *\n * @param {Function} handler A handler to call on a click event\n */\n addClickHandler(handler) {\n this.clickHandlers.push(handler.bind(this));\n }\n\n /**\n * Register the event listeners for this instance.\n */\n registerEventListeners() {\n document.addEventListener('click', function(e) {\n const tableRoot = this.getTableRoot(e);\n\n if (!tableRoot) {\n return;\n }\n\n this.clickHandlers.forEach((handler) => handler(tableRoot, e));\n }.bind(this));\n }\n\n /**\n * Get the table root from an event.\n *\n * @param {Event} e\n * @returns {HTMLElement|bool}\n */\n getTableRoot(e) {\n const tableRoot = e.target.closest(Selectors.main.region);\n if (!tableRoot) {\n return false;\n }\n\n return tableRoot;\n }\n\n /**\n * Set the plugin state (enabled or disabled)\n *\n * @param {string} methodname The web service to call\n * @param {int} gatewayid The gateway id\n * @param {boolean} enabled The state to set\n * @returns {Promise}\n */\n setGatewayState(methodname, gatewayid, enabled) {\n return fetchMany([{\n methodname,\n args: {\n gatewayid,\n enabled,\n },\n }])[0];\n }\n\n /**\n * Handle state toggling.\n *\n * @param {HTMLElement} tableRoot\n * @param {Event} e\n */\n async handleStateToggle(tableRoot, e) {\n const stateToggle = e.target.closest('[data-action=\"togglestate\"][data-toggle-method]');\n if (stateToggle) {\n e.preventDefault();\n const pendingPromise = new Pending('core_table/dynamic:togglestate');\n\n const response = await this.setGatewayState(\n stateToggle.dataset.toggleMethod,\n parseInt(stateToggle.dataset.gatewayid),\n stateToggle.dataset.state !== '1'\n );\n\n if (!response.result) {\n getStrings([\n {key: response.message, component: 'sms'},\n ]).then(([message]) =>\n // Reset form dirty state on confirmation, re-trigger the event.\n Notification.addNotification({\n message: message,\n type: response.messageType\n })\n ).catch(Notification.exception);\n }\n\n const [updatedRoot] = await Promise.all([\n refreshTableContent(tableRoot),\n fetchNotifications(),\n ]);\n\n // Refocus on the link that was pressed in the first place.\n updatedRoot.querySelector(`[data-action=\"togglestate\"][data-gatewayid=\"${stateToggle.dataset.gatewayid}\"]`).focus();\n pendingPromise.resolve();\n }\n }\n}\n"],"names":["watching","constructor","addClickHandler","this","handleStateToggle","registerEventListeners","handler","clickHandlers","push","bind","document","addEventListener","e","tableRoot","getTableRoot","forEach","target","closest","Selectors","main","region","setGatewayState","methodname","gatewayid","enabled","args","stateToggle","preventDefault","pendingPromise","Pending","response","dataset","toggleMethod","parseInt","state","result","key","message","component","then","_ref","Notification","addNotification","type","messageType","catch","exception","updatedRoot","Promise","all","querySelector","focus","resolve"],"mappings":"25CAuBIA,UAAW;;;;;;;mCAeXC,8KAFgB,SAGPC,gBAAgBC,KAAKC,wBACrBC,uCASDL,WAGJA,UAAW,MACPG,MAQRD,gBAAgBI,cACPC,cAAcC,KAAKF,QAAQG,KAAKN,OAMzCE,yBACIK,SAASC,iBAAiB,QAAS,SAASC,SAClCC,UAAYV,KAAKW,aAAaF,GAE/BC,gBAIAN,cAAcQ,SAAST,SAAYA,QAAQO,UAAWD,MAC7DH,KAAKN,OASXW,aAAaF,SACHC,UAAYD,EAAEI,OAAOC,QAAQC,UAAUC,KAAKC,eAC7CP,YACM,EAcfQ,gBAAgBC,WAAYC,UAAWC,gBAC5B,cAAU,CAAC,CACdF,WAAAA,WACAG,KAAM,CACFF,UAAAA,UACAC,QAAAA,YAEJ,2BASgBX,UAAWD,SACzBc,YAAcd,EAAEI,OAAOC,QAAQ,sDACjCS,YAAa,CACbd,EAAEe,uBACIC,eAAiB,IAAIC,iBAAQ,kCAE7BC,eAAiB3B,KAAKkB,gBACxBK,YAAYK,QAAQC,aACpBC,SAASP,YAAYK,QAAQR,WACC,MAA9BG,YAAYK,QAAQG,OAGnBJ,SAASK,4BACC,CACP,CAACC,IAAKN,SAASO,QAASC,UAAW,SACpCC,MAAKC,WAAEH,qBAENI,sBAAaC,gBAAgB,CACzBL,QAASA,QACTM,KAAMb,SAASc,iBAErBC,MAAMJ,sBAAaK,iBAGlBC,mBAAqBC,QAAQC,IAAI,EACpC,gCAAoBpC,YACpB,wCAIJkC,YAAYG,oEAA6DxB,YAAYK,QAAQR,iBAAe4B,QAC5GvB,eAAewB"} \ No newline at end of file diff --git a/sms/amd/src/smsgatewaychooser.js b/sms/amd/src/smsgatewaychooser.js index c49ae21a42e6d..a0be29a8ebeae 100644 --- a/sms/amd/src/smsgatewaychooser.js +++ b/sms/amd/src/smsgatewaychooser.js @@ -32,7 +32,7 @@ const Selectors = { * Initialise the sms gateway chooser. */ export const init = () => { - document.querySelector(Selectors.fields.selector).addEventListener('change', e => { + document.querySelector(Selectors.fields.selector)?.addEventListener('change', e => { const form = e.target.closest('form'); const updateButton = form.querySelector(Selectors.fields.updateButton); const url = new URL(form.action); diff --git a/sms/amd/src/smsgatewaytoggle.js b/sms/amd/src/smsgatewaytoggle.js deleted file mode 100644 index 651ccae6b63c6..0000000000000 --- a/sms/amd/src/smsgatewaytoggle.js +++ /dev/null @@ -1,154 +0,0 @@ -// 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 . - -import {refreshTableContent} from 'core_table/dynamic'; -import * as Selectors from 'core_table/local/dynamic/selectors'; -import {call as fetchMany} from 'core/ajax'; -import Notification from 'core/notification'; -import Pending from 'core/pending'; -import {getStrings} from 'core/str'; -import {fetchNotifications} from 'core/notification'; - -let watching = false; - -/** - * SMS gateway status handler. - * - * @module core_sms/smsgatewaytoggle - * @copyright 2024 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -export default class { - /** - * @property {function[]} clickHandlers a list of handlers to call on click. - */ - clickHandlers = []; - - constructor() { - this.addClickHandler(this.handleStateToggle); - this.registerEventListeners(); - } - - /** - * Initialise an instance of the class. - * - * This is just a way of making it easier to initialise an instance of the class from PHP. - */ - static init() { - if (watching) { - return; - } - watching = true; - new this(); - } - - /** - * Add a click handler to the list of handlers. - * - * @param {Function} handler A handler to call on a click event - */ - addClickHandler(handler) { - this.clickHandlers.push(handler.bind(this)); - } - - /** - * Register the event listeners for this instance. - */ - registerEventListeners() { - document.addEventListener('click', function(e) { - const tableRoot = this.getTableRoot(e); - - if (!tableRoot) { - return; - } - - this.clickHandlers.forEach((handler) => handler(tableRoot, e)); - }.bind(this)); - } - - /** - * Get the table root from an event. - * - * @param {Event} e - * @returns {HTMLElement|bool} - */ - getTableRoot(e) { - const tableRoot = e.target.closest(Selectors.main.region); - if (!tableRoot) { - return false; - } - - return tableRoot; - } - - /** - * Set the plugin state (enabled or disabled) - * - * @param {string} methodname The web service to call - * @param {int} gatewayid The gateway id - * @param {boolean} enabled The state to set - * @returns {Promise} - */ - setGatewayState(methodname, gatewayid, enabled) { - return fetchMany([{ - methodname, - args: { - gatewayid, - enabled, - }, - }])[0]; - } - - /** - * Handle state toggling. - * - * @param {HTMLElement} tableRoot - * @param {Event} e - */ - async handleStateToggle(tableRoot, e) { - const stateToggle = e.target.closest('[data-action="togglestate"][data-toggle-method]'); - if (stateToggle) { - e.preventDefault(); - const pendingPromise = new Pending('core_table/dynamic:togglestate'); - - const response = await this.setGatewayState( - stateToggle.dataset.toggleMethod, - parseInt(stateToggle.dataset.gatewayid), - stateToggle.dataset.state !== '1' - ); - - if (!response.result) { - getStrings([ - {key: response.message, component: 'sms'}, - ]).then(([message]) => - // Reset form dirty state on confirmation, re-trigger the event. - Notification.addNotification({ - message: message, - type: response.messageType - }) - ).catch(Notification.exception); - } - - const [updatedRoot] = await Promise.all([ - refreshTableContent(tableRoot), - fetchNotifications(), - ]); - - // Refocus on the link that was pressed in the first place. - updatedRoot.querySelector(`[data-action="togglestate"][data-gatewayid="${stateToggle.dataset.gatewayid}"]`).focus(); - pendingPromise.resolve(); - } - } -} diff --git a/sms/classes/external/sms_gateway_status.php b/sms/classes/external/sms_gateway_status.php index f670513f3d86e..5272eae2143c8 100644 --- a/sms/classes/external/sms_gateway_status.php +++ b/sms/classes/external/sms_gateway_status.php @@ -33,15 +33,19 @@ class sms_gateway_status extends external_api { public static function execute_parameters(): external_function_parameters { return new external_function_parameters([ - 'gatewayid' => new external_value(PARAM_INT, 'Gateway ID', VALUE_REQUIRED), - 'enabled' => new external_value(PARAM_BOOL, 'Enabled or disabled', VALUE_REQUIRED), + 'plugin' => new external_value(PARAM_INT, 'Gateway ID', VALUE_REQUIRED), + 'state' => new external_value(PARAM_INT, 'Enabled or disabled', VALUE_REQUIRED), ]); } - public static function execute(int $gatewayid, bool $enabled): array { - $params = self::validate_parameters(self::execute_parameters(), [ - 'gatewayid' => $gatewayid, - 'enabled' => $enabled, + public static function execute(int $plugin, int $state): array { + // Parameter validation. + [ + 'plugin' => $gatewayid, + 'state' => $state, + ] = self::validate_parameters(self::execute_parameters(), [ + 'plugin' => $plugin, + 'state' => $state, ]); $context = context_system::instance(); @@ -54,11 +58,22 @@ public static function execute(int $gatewayid, bool $enabled): array { 'messagetype' => '', ]; $manager = \core\di::get(\core_sms\manager::class); - $gatewaymanagers = $manager->get_gateway_instances(['id' => $params['gatewayid']]); + $gatewaymanagers = $manager->get_gateway_instances(['id' => $gatewayid]); $gatewaymanager = reset($gatewaymanagers); - if ($params['enabled']) { + if (!$gatewaymanager) { + $result = [ + 'result' => false, + 'message' => 'sms_gateway_not_found', + 'messagetype' => 'error' + ]; + return $result; + } + + if (!empty($state)) { $manager->enable_gateway(gateway: $gatewaymanager); + $message = get_string('plugin_enabled', 'core_admin', $gatewaymanager->name); + $messagetype = \core\notification::SUCCESS; } else { $gatewayresult = $manager->disable_gateway(gateway: $gatewaymanager); if ($gatewayresult->enabled) { @@ -67,9 +82,16 @@ public static function execute(int $gatewayid, bool $enabled): array { 'message' => 'sms_gateway_disable_failed', 'messagetype' => 'error' ]; + $message = get_string('sms_gateway_disable_failed', 'core_sms'); + $messagetype = \core\notification::ERROR; + } else { + $message = get_string('plugin_disabled', 'core_admin', $gatewaymanager->name); + $messagetype = \core\notification::SUCCESS; } } + \core\notification::add($message, $messagetype); + return $result; } diff --git a/sms/classes/table/sms_gateway_table.php b/sms/classes/table/sms_gateway_table.php index 50c0a1df6db8e..d3f94340cca54 100644 --- a/sms/classes/table/sms_gateway_table.php +++ b/sms/classes/table/sms_gateway_table.php @@ -51,11 +51,7 @@ public function __construct() { $this->setup(); } - /** - * Get the context. - * - * @return context_system - */ + #[\Override] public function get_context(): context_system { return context_system::instance(); } @@ -68,9 +64,10 @@ public function get_context(): context_system { * @return string */ protected function get_table_js_module(): string { - return 'core_sms/smsgatewaytoggle'; + return 'core_admin/plugin_management_table'; } + #[\Override] protected function get_dynamic_table_html_end(): string { global $PAGE; @@ -85,23 +82,6 @@ protected function setup_column_configuration(): void { $columnlist = $this->get_column_list(); $this->define_columns(array_keys($columnlist)); $this->define_headers(array_values($columnlist)); - - $columnswithhelp = $this->get_columns_with_help(); - $columnhelp = array_map(function (string $column) use ($columnswithhelp): ?\renderable { - if (array_key_exists($column, $columnswithhelp)) { - return $columnswithhelp[$column]; - } - - return null; - }, array_keys($columnlist)); - $this->define_help_for_headers($columnhelp); - } - - /** - * Get the columns with help icons. - */ - protected function get_columns_with_help(): array { - return []; } /** @@ -127,6 +107,7 @@ protected function get_table_id(): string { return 'sms_gateways_table'; } + #[\Override] public function guess_base_url(): void { $this->define_baseurl(new moodle_url('/sms/sms_gateways.php')); } @@ -149,7 +130,7 @@ public function get_content(): string { * * @return array */ - public function get_sms_gateways(): array { + protected function get_sms_gateways(): array { $gateways = \core\di::get(\core_sms\manager::class)->get_gateway_records(); if (!empty($gateways)) { \core_collator::asort_objects_by_property($gateways, 'id'); @@ -227,7 +208,7 @@ public function get_gateway_name(string $gateway): string { * * @return string */ - public function get_toggle_service(): string { + protected function get_toggle_service(): string { return 'core_sms_set_gateway_status'; } @@ -242,9 +223,9 @@ public function col_enabled(stdClass $row): string { $enabled = $row->enabled; if ($enabled) { - $labelstr = get_string('enabled'); + $labelstr = get_string('disableplugin', 'core_admin', $row->name); } else { - $labelstr = get_string('disabled'); + $labelstr = get_string('enableplugin', 'core_admin', $row->name); } $params = [ @@ -255,13 +236,15 @@ public function col_enabled(stdClass $row): string { 'value' => $this->get_gateway_name($row->gateway), 'toggle-method' => $this->get_toggle_service(), 'action' => 'togglestate', - 'gatewayid' => $row->id, + 'plugin' => $row->id, // Set plugin attribute to gateway ID. 'state' => $enabled ? 1 : 0, ], + 'title' => $labelstr, 'label' => $labelstr, + 'labelclasses' => 'sr-only', ]; - return $OUTPUT->render_from_template('core_sms/sms_gateway_toggle', $params); + return $OUTPUT->render_from_template('core_admin/setting_configtoggle', $params); } /** @@ -273,28 +256,19 @@ public function col_enabled(stdClass $row): string { public function col_actions(stdClass $row): string { global $OUTPUT; - $urlparams = [ - 'id' => $row->id, - ]; - $editurl = new moodle_url('/sms/configure.php', $urlparams); - $deleteurl = new moodle_url( - '/sms/sms_gateways.php', - $urlparams + ['action' => 'delete', 'sesskey' => sesskey()]); - - $template = new stdClass(); - $template->buttons = [ - [ - 'name' => get_string('edit'), - 'icon' => 'fa fa-edit', - 'url' => $editurl, - ], - [ - 'name' => get_string('delete'), - 'icon' => 'fa fa-trash', - 'url' => $deleteurl, - ], + $editurl = new moodle_url('/sms/configure.php', ['id' => $row->id]); + $deleteurl = new moodle_url('/sms/sms_gateways.php', ['id' => $row->id, 'action' => 'delete']); + + $templatecontext = [ + 'editurl' => $editurl->out(false), + 'deleteurl' => $deleteurl->out(false), ]; - return $OUTPUT->render_from_template('core_sms/sms_action_icons', $template); + return $OUTPUT->render_from_template('core_sms/sms_action_icons', $templatecontext); + } + + #[\Override] + public function has_capability(): bool { + return has_capability('moodle/site:config', $this->get_context()); } } diff --git a/sms/gateway/aws/classes/gateway.php b/sms/gateway/aws/classes/gateway.php index 9bfdbfec07700..4157cc980d111 100644 --- a/sms/gateway/aws/classes/gateway.php +++ b/sms/gateway/aws/classes/gateway.php @@ -68,4 +68,109 @@ public function send( public function get_send_priority(message $message): int { return 50; } + + /** + * Set form definition. + * + * @param MoodleQuickForm $mform Moodle form element. + * @return void + */ + public static function set_form_definition( + MoodleQuickForm $mform, + ): void { + $codeslink = 'https://en.wikipedia.org/wiki/List_of_country_calling_codes'; + $link = \html_writer::link($codeslink, $codeslink); + $mform->addElement( + 'text', + 'countrycode', + get_string('countrycode', 'smsgateway_aws'), + 'maxlength="255" size="20"', + ); + $mform->addHelpButton( + elementname: 'countrycode', + identifier: 'countrycode', + component: 'smsgateway_aws', + a: $link, + ); + $mform->setDefault( + elementName: 'countrycode', + defaultValue: 0, + ); + + $gateways = [ + 'aws_sns' => get_string('aws_sns', 'smsgateway_aws'), + ]; + $mform->addElement( + 'select', + 'gateway', + get_string('gateway', 'smsgateway_aws'), + $gateways, + ); + $mform->addHelpButton( + elementname: 'gateway', + identifier: 'gateway', + component: 'smsgateway_aws', + ); + $mform->setDefault( + elementName: 'gateway', + defaultValue: 'aws_sns', + ); + + $mform->addElement( + 'checkbox', + 'usecredchain', + get_string('usecredchain', 'smsgateway_aws'), + ); + $mform->setDefault( + elementName: 'usecredchain', + defaultValue: 0, + ); + + $mform->addElement( + 'text', + 'api_key', + get_string('api_key', 'smsgateway_aws'), + 'maxlength="255" size="20"', + ); + $mform->addHelpButton( + elementname: 'api_key', + identifier: 'api_key', + component: 'smsgateway_aws', + ); + $mform->setDefault( + elementName: 'api_key', + defaultValue: '', + ); + + $mform->addElement( + 'text', + 'api_secret', + get_string('api_secret', 'smsgateway_aws'), + 'maxlength="255" size="20"', + ); + $mform->addHelpButton( + elementname: 'api_secret', + identifier: 'api_secret', + component: 'smsgateway_aws', + ); + $mform->setDefault( + elementName: 'api_secret', + defaultValue: '', + ); + $mform->addElement( + 'text', + 'api_region', + get_string('api_region', 'smsgateway_aws'), + 'maxlength="255" size="20"', + ); + $mform->addHelpButton( + elementname: 'api_region', + identifier: 'api_region', + component: 'smsgateway_aws', + ); + $mform->setDefault( + elementName: 'api_region', + defaultValue: 'ap-southeast-2', + ); + } } diff --git a/sms/sms_gateways.php b/sms/sms_gateways.php index 51d5840f345d4..881d72d6296f3 100644 --- a/sms/sms_gateways.php +++ b/sms/sms_gateways.php @@ -77,7 +77,7 @@ $PAGE->set_heading($strheading); echo $OUTPUT->header(); - $yesurl = new moodle_url($returnurl, ['id' => $id, 'action' => 'delete', 'confirm' => 1, 'sesskey' => sesskey()]); + $yesurl = new moodle_url($returnurl, ['id' => $id, 'action' => 'delete', 'confirm' => 1]); $message = get_string('delete_sms_gateway_confirmation', 'sms', $a); echo $OUTPUT->confirm($message, $yesurl, $returnurl); echo $OUTPUT->footer(); diff --git a/sms/templates/sms_action_icons.mustache b/sms/templates/sms_action_icons.mustache index b32edb8a63488..5a2b90d62912a 100644 --- a/sms/templates/sms_action_icons.mustache +++ b/sms/templates/sms_action_icons.mustache @@ -18,23 +18,26 @@ @template core_sms/sms_action_icons Template for sms gateway actions icons. Context variables required for this template: - * url - URL of the button - * icon - Bootstrap icon class for the button - * name - Text of the button + * editurl - URL for the edit button + * deleteurl - URL for the delete button Example context (json): { - "buttons": [{ - "url": "www.example.com", - "icon": "fa fa-edit", - "name": "Edit" - }] + "editurl": "http://example.com/edit", + "deleteurl": "http://example.com/delete" } }} diff --git a/sms/templates/sms_gateway_toggle.mustache b/sms/templates/sms_gateway_toggle.mustache deleted file mode 100644 index d1bfbc47ba98f..0000000000000 --- a/sms/templates/sms_gateway_toggle.mustache +++ /dev/null @@ -1,53 +0,0 @@ -{{! - 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 . -}} -{{! - @template core_sms/sms_gateway_toggle - Template for toggle element in sms gateway table. - Context variables required for this template: - * id - element id - * checked - bool, true if the toggle is enabled - * name - form element name - * value - form for name field - * action - action to be performed when the toggle is clicked - * toggle-method - the method of the tooggle to be used - * gatewayid - the gateway id - * state - state of the toggle - * title - title of the toggle tooltip - * label - label of the toggle - * labelclasses - classes for the label (sr-only for screen readers) - Example context (json): - { - "id": "reality-toggle-3", - "checked": true, - "dataattributes": [{ - "name": "id", - "value": "toggle-reality", - "action": "togglestate", - "state": 1, - "toggle-method": "change", - "gatewayid": "11" - }], - "title": "Title example", - "label": "Enable/disable reality", - "labelclasses": "sr-only" - } -}} - -
- {{> core/toggle }} -
diff --git a/sms/templates/sms_gateways.mustache b/sms/templates/sms_gateways.mustache index c58f180c9a77c..d0081046fa542 100644 --- a/sms/templates/sms_gateways.mustache +++ b/sms/templates/sms_gateways.mustache @@ -27,21 +27,11 @@ } }} -
- -
- {{{tablehtml}}} -
+ +
+ {{{tablehtml}}}
diff --git a/sms/tests/external/sms_gateway_status_test.php b/sms/tests/external/sms_gateway_status_test.php index 216ecb1529cb6..ff4f2384122aa 100644 --- a/sms/tests/external/sms_gateway_status_test.php +++ b/sms/tests/external/sms_gateway_status_test.php @@ -60,8 +60,8 @@ classname: $dummygw, // Now let's disable the gateway. sms_gateway_status::execute( - gatewayid: $gateway->id, - enabled: false, + plugin: $gateway->id, + state: 0, ); $gatewaymanagers = $manager->get_gateway_instances( filter: ['id' => $gateway->id], @@ -71,8 +71,8 @@ classname: $dummygw, // Let's enable again. sms_gateway_status::execute( - gatewayid: $gateway->id, - enabled: true, + plugin: $gateway->id, + state: 1, ); $gatewaymanagers = $manager->get_gateway_instances( filter: ['id' => $gateway->id],