├── README.md ├── version.php ├── db ├── hooks.php └── services.php ├── lang └── en │ └── tool_bulkactiondemo.php ├── classes ├── local │ └── hooks │ │ └── extend_bulk_user_actions.php └── external │ └── action.php ├── amd ├── build │ ├── actions.min.js │ └── actions.min.js.map └── src │ └── actions.js ├── action.php └── .github └── workflows └── gha.yml /README.md: -------------------------------------------------------------------------------- 1 | # Bulk user action example 2 | 3 | This plugin is an example of how to add bulk user actions to Moodle 4.4 4 | 5 | Commit 1: Implement hook and add actions "Suspend" and "Unsuspend" that work from 6 | both "Bulk user actions" and "Browse user list" pages and work without any Javascript. 7 | 8 | Commit 2: Add web service and JS module to listen to form submit event, intercept it 9 | and perform action using AJAX requests (only for "Browse user list" page). 10 | -------------------------------------------------------------------------------- /version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Version information for Bulk user action demo 19 | * 20 | * @package tool_bulkactiondemo 21 | * @copyright 2024 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $plugin->component = 'tool_bulkactiondemo'; 28 | $plugin->release = '1.1'; 29 | $plugin->version = 2024011801; 30 | $plugin->requires = 2024011200.00; 31 | $plugin->maturity = MATURITY_STABLE; 32 | -------------------------------------------------------------------------------- /db/hooks.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Hook callbacks for Bulk user action demo 19 | * 20 | * @package tool_bulkactiondemo 21 | * @copyright 2024 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $callbacks = [ 28 | [ 29 | 'hook' => core_user\hook\extend_bulk_user_actions::class, 30 | 'callback' => 'tool_bulkactiondemo\local\hooks\extend_bulk_user_actions::callback', 31 | 'priority' => 0, 32 | ], 33 | ]; 34 | -------------------------------------------------------------------------------- /lang/en/tool_bulkactiondemo.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * English language pack for Bulk user action demo 19 | * 20 | * @package tool_bulkactiondemo 21 | * @category string 22 | * @copyright 2024 Marina Glancy 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $string['confirmsuspend'] = 'Are you absolutely sure you want to suspend {$a}'; 29 | $string['confirmunsuspend'] = 'Are you absolutely sure you want to unsuspend {$a}'; 30 | $string['pluginname'] = 'Bulk user action demo'; 31 | $string['suspend'] = 'Suspend'; 32 | $string['unrecognisedaction'] = 'Unrecognised action'; 33 | $string['unsuspend'] = 'Unsuspend'; 34 | -------------------------------------------------------------------------------- /db/services.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * External functions and service declaration for Bulk user action demo 19 | * 20 | * Documentation: {@link https://moodledev.io/docs/apis/subsystems/external/description} 21 | * 22 | * @package tool_bulkactiondemo 23 | * @category webservice 24 | * @copyright 2024 Marina Glancy 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | $functions = [ 31 | 32 | 'tool_bulkactiondemo_action' => [ 33 | 'classname' => tool_bulkactiondemo\external\action::class, 34 | 'description' => 'Perform bulk user action', 35 | 'type' => 'write', 36 | 'ajax' => true, 37 | ], 38 | ]; 39 | 40 | $services = [ 41 | ]; 42 | -------------------------------------------------------------------------------- /classes/local/hooks/extend_bulk_user_actions.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace tool_bulkactiondemo\local\hooks; 18 | 19 | use action_link; 20 | use moodle_url; 21 | 22 | /** 23 | * Hook callbacks for tool_bulkactiondemo 24 | * 25 | * @package tool_bulkactiondemo 26 | * @copyright 2024 Marina Glancy 27 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 | */ 29 | class extend_bulk_user_actions { 30 | 31 | /** 32 | * Extend bulk user actions menu 33 | * 34 | * @param \core_user\hook\extend_bulk_user_actions $hook 35 | */ 36 | public static function callback(\core_user\hook\extend_bulk_user_actions $hook): void { 37 | global $PAGE; 38 | $category = 'Added by plugin'; 39 | 40 | $syscontext = \context_system::instance(); 41 | if (has_capability('moodle/user:update', $syscontext)) { 42 | $hook->add_action('tool_bulkactiondemo_suspend', new action_link( 43 | new moodle_url('/admin/tool/bulkactiondemo/action.php', ['action' => 'suspend']), 44 | get_string('suspend', 'tool_bulkactiondemo')), 45 | $category); 46 | $hook->add_action('tool_bulkactiondemo_unsuspend', new action_link( 47 | new moodle_url('/admin/tool/bulkactiondemo/action.php', ['action' => 'unsuspend']), 48 | get_string('unsuspend', 'tool_bulkactiondemo')), 49 | $category); 50 | $PAGE->requires->js_call_amd('tool_bulkactiondemo/actions', 'init'); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /amd/build/actions.min.js: -------------------------------------------------------------------------------- 1 | define("tool_bulkactiondemo/actions",["exports","core/notification","core/str","core/ajax","core_reportbuilder/local/events","core/event_dispatcher","core_reportbuilder/local/selectors","core/toast","core_form/changechecker"],(function(_exports,_notification,_str,_ajax,reportEvents,_event_dispatcher,reportSelectors,_toast,FormChangeChecker){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}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} 2 | /** 3 | * Perform bulk user action in AJAX request 4 | * 5 | * @module tool_bulkactiondemo/actions 6 | * @copyright 2024 Marina Glancy 7 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8 | */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_ajax=_interopRequireDefault(_ajax),reportEvents=_interopRequireWildcard(reportEvents),reportSelectors=_interopRequireWildcard(reportSelectors),FormChangeChecker=_interopRequireWildcard(FormChangeChecker);const SELECTORS_bulkActionForm="body#page-admin-user form#user-bulk-action-form";_exports.init=()=>{const form=document.querySelector(SELECTORS_bulkActionForm);form&&form.addEventListener("submit",(e=>{var _form$querySelector;let action=null===(_form$querySelector=form.querySelector('select[name="action"]'))||void 0===_form$querySelector?void 0:_form$querySelector.value;if(!action.startsWith("tool_bulkactiondemo_"))return;e.preventDefault(),FormChangeChecker.markFormSubmitted(e.target),action=action.replace("tool_bulkactiondemo_","");const userlist=e.target.data.usernames.join(", "),userids=e.target.data.userids;let key;if("suspend"===action)key="confirmsuspend";else{if("unsuspend"!==action)return;key="confirmunsuspend"}(0,_str.getStrings)([{key:"confirm"},{key:key,component:"tool_bulkactiondemo",param:userlist},{key:"yes"},{key:"no"},{key:"changessaved",component:"moodle"}]).then((strings=>(form.querySelector('select[name="action"]').value="0",_notification.default.confirm(strings[0],strings[1],strings[2],strings[3],(()=>function(action,userids,successMessage){const reportElement=document.querySelector('[data-region="report-user-list-wrapper"] '+reportSelectors.regions.report);_ajax.default.call([{methodname:"tool_bulkactiondemo_action",args:{action:action,userids:userids},done:()=>{(0,_toast.add)(successMessage,{}),reportElement&&(0,_event_dispatcher.dispatchEvent)(reportEvents.tableReload,{preservePagination:!0},reportElement)},fail:error=>_notification.default.exception(error)}])}(action,userids,strings[4])))))).catch(_notification.default.exception)}))}})); 9 | 10 | //# sourceMappingURL=actions.min.js.map -------------------------------------------------------------------------------- /classes/external/action.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace tool_bulkactiondemo\external; 18 | 19 | use core_external\external_function_parameters; 20 | use core_external\external_single_structure; 21 | use core_external\external_api; 22 | use core_external\external_value; 23 | use core_external\external_multiple_structure; 24 | use moodle_exception; 25 | 26 | /** 27 | * Implementation of web service tool_bulkactiondemo_action 28 | * 29 | * @package tool_bulkactiondemo 30 | * @copyright 2024 Marina Glancy 31 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 | */ 33 | class action extends external_api { 34 | 35 | /** 36 | * Describes the parameters for tool_bulkactiondemo_action 37 | * 38 | * @return external_function_parameters 39 | */ 40 | public static function execute_parameters(): external_function_parameters { 41 | return new external_function_parameters([ 42 | 'action' => new external_value(PARAM_ALPHANUMEXT, 'Action'), 43 | 'userids' => new external_multiple_structure( 44 | new external_value(PARAM_INT, 'user id'), 'Array of user ids' 45 | ), 46 | ]); 47 | } 48 | 49 | /** 50 | * Implementation of web service tool_bulkactiondemo_action 51 | * 52 | * @param string $action 53 | * @param array $userids 54 | */ 55 | public static function execute($action, $userids) { 56 | global $DB, $USER, $CFG; 57 | require_once($CFG->dirroot . '/user/lib.php'); 58 | 59 | // Parameter validation. 60 | ['action' => $action, 'userids' => $userids] = self::validate_parameters( 61 | self::execute_parameters(), 62 | ['action' => $action, 'userids' => $userids] 63 | ); 64 | 65 | $context = \context_system::instance(); 66 | self::validate_context($context); 67 | require_capability('moodle/user:update', $context); 68 | 69 | list($in, $params) = $DB->get_in_or_equal($userids); 70 | $rs = $DB->get_recordset_select('user', "id $in", $params, '', 'id, suspended'); 71 | foreach ($rs as $user) { 72 | if ($action === 'suspend') { 73 | if (!is_siteadmin($user) && $USER->id != $user->id && $user->suspended != 1) { 74 | $user->suspended = 1; 75 | // Force logout. 76 | \core\session\manager::kill_user_sessions($user->id); 77 | user_update_user($user, false); 78 | } 79 | } else if ($action === 'unsuspend') { 80 | if ($user->suspended != 0) { 81 | $user->suspended = 0; 82 | user_update_user($user, false); 83 | } 84 | } else { 85 | throw new moodle_exception(get_string('unrecognisedaction', 'tool_bulkactiondemo')); 86 | } 87 | } 88 | 89 | return []; 90 | } 91 | 92 | /** 93 | * Describe the return structure for tool_bulkactiondemo_action 94 | * 95 | * @return external_single_structure 96 | */ 97 | public static function execute_returns(): external_single_structure { 98 | return new external_single_structure([]); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /amd/src/actions.js: -------------------------------------------------------------------------------- 1 | // This file is part of Moodle - http://moodle.org/ 2 | // 3 | // Moodle is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Moodle is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Moodle. If not, see . 15 | 16 | /** 17 | * Perform bulk user action in AJAX request 18 | * 19 | * @module tool_bulkactiondemo/actions 20 | * @copyright 2024 Marina Glancy 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | import Notification from 'core/notification'; 25 | import {getStrings} from 'core/str'; 26 | import Ajax from 'core/ajax'; 27 | import * as reportEvents from 'core_reportbuilder/local/events'; 28 | import {dispatchEvent} from 'core/event_dispatcher'; 29 | import * as reportSelectors from 'core_reportbuilder/local/selectors'; 30 | import {add as addToast} from 'core/toast'; 31 | import * as FormChangeChecker from 'core_form/changechecker'; 32 | 33 | const SELECTORS = { 34 | bulkActionForm: 'body#page-admin-user form#user-bulk-action-form', 35 | }; 36 | 37 | /** 38 | * Initialise module 39 | */ 40 | export const init = () => { 41 | const form = document.querySelector(SELECTORS.bulkActionForm); 42 | 43 | if (!form) { 44 | return; 45 | } 46 | 47 | form.addEventListener('submit', (e) => { 48 | let action = form.querySelector('select[name="action"]')?.value; 49 | if (!action.startsWith('tool_bulkactiondemo_')) { 50 | return; 51 | } 52 | 53 | e.preventDefault(); 54 | FormChangeChecker.markFormSubmitted(e.target); 55 | 56 | action = action.replace('tool_bulkactiondemo_', ''); 57 | const userlist = e.target.data.usernames.join(', '); 58 | const userids = e.target.data.userids; 59 | 60 | let key; 61 | if (action === 'suspend') { 62 | key = 'confirmsuspend'; 63 | } else if (action === 'unsuspend') { 64 | key = 'confirmunsuspend'; 65 | } else { 66 | return; 67 | } 68 | 69 | getStrings([ 70 | {'key': 'confirm'}, 71 | {'key': key, component: 'tool_bulkactiondemo', param: userlist}, 72 | {'key': 'yes'}, 73 | {'key': 'no'}, 74 | {'key': 'changessaved', component: 'moodle'} 75 | ]) 76 | .then(strings => { 77 | form.querySelector('select[name="action"]').value = '0'; 78 | return Notification.confirm(strings[0], strings[1], strings[2], strings[3], 79 | () => performAction(action, userids, strings[4])); 80 | }) 81 | .catch(Notification.exception); 82 | }); 83 | }; 84 | 85 | /** 86 | * Perform action 87 | * 88 | * @param {String} action 89 | * @param {Array} userids 90 | * @param {String} successMessage 91 | */ 92 | function performAction(action, userids, successMessage) { 93 | const reportElement = document.querySelector('[data-region="report-user-list-wrapper"] ' + reportSelectors.regions.report); 94 | 95 | Ajax.call([{ 96 | methodname: 'tool_bulkactiondemo_action', 97 | args: { 98 | action: action, 99 | userids: userids, 100 | }, 101 | done: () => { 102 | addToast(successMessage, {}); 103 | if (reportElement) { 104 | dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement); 105 | } 106 | }, 107 | fail: (error) => Notification.exception(error), 108 | }]); 109 | } -------------------------------------------------------------------------------- /action.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Perform a bulk user action 19 | * 20 | * @package tool_bulkactiondemo 21 | * @copyright 2024 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require('../../../config.php'); 26 | 27 | $action = optional_param('action', '', PARAM_ALPHANUMEXT); 28 | $confirm = optional_param('confirm', 0, PARAM_BOOL); 29 | 30 | require_login(); 31 | 32 | $url = new moodle_url('/admin/tool/bulkactiondemo/action.php', []); 33 | $PAGE->set_url($url); 34 | $PAGE->set_context(context_system::instance()); 35 | require_capability('moodle/user:update', context_system::instance()); 36 | 37 | $returnurl = optional_param('returnurl', '', PARAM_LOCALURL); 38 | $return = new moodle_url($returnurl ?: '/admin/user/user_bulk.php'); 39 | 40 | if (empty($SESSION->bulk_users)) { 41 | redirect($return); 42 | } 43 | 44 | $PAGE->set_heading($SITE->fullname); 45 | echo $OUTPUT->header(); 46 | 47 | if ($confirm && confirm_sesskey()) { 48 | $notifications = ''; 49 | list($in, $params) = $DB->get_in_or_equal($SESSION->bulk_users); 50 | $rs = $DB->get_recordset_select('user', "id $in", $params, '', 'id, suspended'); 51 | foreach ($rs as $user) { 52 | if ($action === 'suspend') { 53 | if (!is_siteadmin($user) && $USER->id != $user->id && $user->suspended != 1) { 54 | $user->suspended = 1; 55 | // Force logout. 56 | \core\session\manager::kill_user_sessions($user->id); 57 | user_update_user($user, false); 58 | } 59 | } else if ($action === 'unsuspend') { 60 | if ($user->suspended != 0) { 61 | $user->suspended = 0; 62 | user_update_user($user, false); 63 | } 64 | } else { 65 | throw new moodle_exception(get_string('unrecognisedaction', 'tool_bulkactiondemo')); 66 | } 67 | } 68 | $rs->close(); 69 | echo $OUTPUT->box_start('generalbox', 'notice'); 70 | if (!empty($notifications)) { 71 | echo $notifications; 72 | } else { 73 | echo $OUTPUT->notification(get_string('changessaved'), 'notifysuccess'); 74 | } 75 | $continue = new single_button($return, get_string('continue'), 'post'); 76 | echo $OUTPUT->render($continue); 77 | echo $OUTPUT->box_end(); 78 | } else { 79 | list($in, $params) = $DB->get_in_or_equal($SESSION->bulk_users); 80 | $userlist = $DB->get_records_select_menu('user', "id $in", $params, 'fullname', 'id,'.$DB->sql_fullname().' AS fullname'); 81 | $usernames = implode(', ', $userlist); 82 | echo $OUTPUT->heading(get_string('confirmation', 'admin')); 83 | $formcontinue = new single_button(new moodle_url('/admin/tool/bulkactiondemo/action.php', 84 | ['action' => $action, 'confirm' => 1, 'returnurl' => $returnurl]), get_string('yes')); 85 | $formcancel = new single_button($return, get_string('no'), 'get'); 86 | if ($action === 'suspend') { 87 | echo $OUTPUT->confirm(get_string('confirmsuspend', 'tool_bulkactiondemo', $usernames), $formcontinue, $formcancel); 88 | } else if ($action === 'unsuspend') { 89 | echo $OUTPUT->confirm(get_string('confirmunsuspend', 'tool_bulkactiondemo', $usernames), $formcontinue, $formcancel); 90 | } else if ($action === 'unlock') { 91 | throw new moodle_exception(get_string('unrecognisedaction', 'tool_bulkactiondemo')); 92 | } 93 | } 94 | 95 | echo $OUTPUT->footer(); 96 | -------------------------------------------------------------------------------- /.github/workflows/gha.yml: -------------------------------------------------------------------------------- 1 | name: Moodle Plugin CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-22.04 8 | 9 | services: 10 | postgres: 11 | image: postgres:13 12 | env: 13 | POSTGRES_USER: 'postgres' 14 | POSTGRES_HOST_AUTH_METHOD: 'trust' 15 | ports: 16 | - 5432:5432 17 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 18 | 19 | mariadb: 20 | image: mariadb:10 21 | env: 22 | MYSQL_USER: 'root' 23 | MYSQL_ALLOW_EMPTY_PASSWORD: "true" 24 | MYSQL_CHARACTER_SET_SERVER: "utf8mb4" 25 | MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci" 26 | ports: 27 | - 3306:3306 28 | options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3 29 | 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | include: 34 | - php: '8.2' 35 | # Main job. Run all checks that do not require setup and only need to be run once. 36 | runchecks: 'all' 37 | moodle-branch: 'main' 38 | database: 'pgsql' 39 | - php: '8.1' 40 | moodle-branch: 'main' 41 | database: 'mariadb' 42 | 43 | steps: 44 | - name: Check out repository code 45 | uses: actions/checkout@v4 46 | with: 47 | path: plugin 48 | 49 | - name: Setup PHP ${{ matrix.php }} 50 | uses: shivammathur/setup-php@v2 51 | with: 52 | php-version: ${{ matrix.php }} 53 | extensions: ${{ matrix.extensions }} 54 | ini-values: max_input_vars=5000 55 | # If you are not using code coverage, keep "none". Otherwise, use "pcov" (Moodle 3.10 and up) or "xdebug". 56 | # If you try to use code coverage with "none", it will fallback to phpdbg (which has known problems). 57 | coverage: none 58 | 59 | - name: Initialise moodle-plugin-ci 60 | run: | 61 | composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 62 | echo $(cd ci/bin; pwd) >> $GITHUB_PATH 63 | echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH 64 | sudo locale-gen en_AU.UTF-8 65 | echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV 66 | 67 | - name: Install moodle-plugin-ci 68 | run: moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 69 | env: 70 | DB: ${{ matrix.database }} 71 | MOODLE_BRANCH: ${{ matrix.moodle-branch }} 72 | # Uncomment this to run Behat tests using the Moodle App. 73 | # MOODLE_APP: 'true' 74 | 75 | - name: PHP Lint 76 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 77 | run: moodle-plugin-ci phplint 78 | 79 | - name: PHP Copy/Paste Detector 80 | continue-on-error: true # This step will show errors but will not fail 81 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 82 | run: moodle-plugin-ci phpcpd 83 | 84 | - name: PHP Mess Detector 85 | continue-on-error: true # This step will show errors but will not fail 86 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 87 | run: moodle-plugin-ci phpmd 88 | 89 | - name: Moodle Code Checker 90 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 91 | run: moodle-plugin-ci phpcs --max-warnings 0 92 | 93 | - name: Moodle PHPDoc Checker 94 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 95 | run: moodle-plugin-ci phpdoc --max-warnings 0 96 | 97 | - name: Validating 98 | if: ${{ !cancelled() }} 99 | run: moodle-plugin-ci validate 100 | 101 | - name: Check upgrade savepoints 102 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 103 | run: moodle-plugin-ci savepoints 104 | 105 | - name: Mustache Lint 106 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 107 | run: moodle-plugin-ci mustache 108 | 109 | - name: Grunt 110 | if: ${{ !cancelled() && matrix.runchecks == 'all' }} 111 | run: moodle-plugin-ci grunt --max-lint-warnings 0 112 | 113 | - name: PHPUnit tests 114 | if: ${{ !cancelled() }} 115 | run: moodle-plugin-ci phpunit --fail-on-warning 116 | 117 | - name: Behat features 118 | if: ${{ !cancelled() }} 119 | run: moodle-plugin-ci behat --profile chrome 120 | 121 | - name: Mark cancelled jobs as failed. 122 | if: ${{ cancelled() }} 123 | run: exit 1 124 | -------------------------------------------------------------------------------- /amd/build/actions.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"actions.min.js","sources":["../src/actions.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\n/**\n * Perform bulk user action in AJAX request\n *\n * @module tool_bulkactiondemo/actions\n * @copyright 2024 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Notification from 'core/notification';\nimport {getStrings} from 'core/str';\nimport Ajax from 'core/ajax';\nimport * as reportEvents from 'core_reportbuilder/local/events';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport * as reportSelectors from 'core_reportbuilder/local/selectors';\nimport {add as addToast} from 'core/toast';\nimport * as FormChangeChecker from 'core_form/changechecker';\n\nconst SELECTORS = {\n bulkActionForm: 'body#page-admin-user form#user-bulk-action-form',\n};\n\n/**\n * Initialise module\n */\nexport const init = () => {\n const form = document.querySelector(SELECTORS.bulkActionForm);\n\n if (!form) {\n return;\n }\n\n form.addEventListener('submit', (e) => {\n let action = form.querySelector('select[name=\"action\"]')?.value;\n if (!action.startsWith('tool_bulkactiondemo_')) {\n return;\n }\n\n e.preventDefault();\n FormChangeChecker.markFormSubmitted(e.target);\n\n action = action.replace('tool_bulkactiondemo_', '');\n const userlist = e.target.data.usernames.join(', ');\n const userids = e.target.data.userids;\n\n let key;\n if (action === 'suspend') {\n key = 'confirmsuspend';\n } else if (action === 'unsuspend') {\n key = 'confirmunsuspend';\n } else {\n return;\n }\n\n getStrings([\n {'key': 'confirm'},\n {'key': key, component: 'tool_bulkactiondemo', param: userlist},\n {'key': 'yes'},\n {'key': 'no'},\n {'key': 'changessaved', component: 'moodle'}\n ])\n .then(strings => {\n form.querySelector('select[name=\"action\"]').value = '0';\n return Notification.confirm(strings[0], strings[1], strings[2], strings[3],\n () => performAction(action, userids, strings[4]));\n })\n .catch(Notification.exception);\n });\n};\n\n/**\n * Perform action\n *\n * @param {String} action\n * @param {Array} userids\n * @param {String} successMessage\n */\nfunction performAction(action, userids, successMessage) {\n const reportElement = document.querySelector('[data-region=\"report-user-list-wrapper\"] ' + reportSelectors.regions.report);\n\n Ajax.call([{\n methodname: 'tool_bulkactiondemo_action',\n args: {\n action: action,\n userids: userids,\n },\n done: () => {\n addToast(successMessage, {});\n if (reportElement) {\n dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);\n }\n },\n fail: (error) => Notification.exception(error),\n }]);\n}"],"names":["SELECTORS","form","document","querySelector","addEventListener","e","action","_form$querySelector","value","startsWith","preventDefault","FormChangeChecker","markFormSubmitted","target","replace","userlist","data","usernames","join","userids","key","component","param","then","strings","Notification","confirm","successMessage","reportElement","reportSelectors","regions","report","call","methodname","args","done","reportEvents","tableReload","preservePagination","fail","error","exception","performAction","catch"],"mappings":";;;;;;;yVAgCMA,yBACc,gEAMA,WACVC,KAAOC,SAASC,cAAcH,0BAE/BC,MAILA,KAAKG,iBAAiB,UAAWC,gCACzBC,mCAASL,KAAKE,cAAc,+DAAnBI,oBAA6CC,UACrDF,OAAOG,WAAW,+BAIvBJ,EAAEK,iBACFC,kBAAkBC,kBAAkBP,EAAEQ,QAEtCP,OAASA,OAAOQ,QAAQ,uBAAwB,UAC1CC,SAAWV,EAAEQ,OAAOG,KAAKC,UAAUC,KAAK,MACxCC,QAAUd,EAAEQ,OAAOG,KAAKG,YAE1BC,OACW,YAAXd,OACAc,IAAM,qBACH,CAAA,GAAe,cAAXd,cACPc,IAAM,uCAKC,CACP,KAAQ,WACR,KAAQA,IAAKC,UAAW,sBAAuBC,MAAOP,UACtD,KAAQ,OACR,KAAQ,MACR,KAAQ,eAAgBM,UAAW,YAEtCE,MAAKC,UACFvB,KAAKE,cAAc,yBAAyBK,MAAQ,IAC7CiB,sBAAaC,QAAQF,QAAQ,GAAIA,QAAQ,GAAIA,QAAQ,GAAIA,QAAQ,IACpE,aAaOlB,OAAQa,QAASQ,sBAC9BC,cAAgB1B,SAASC,cAAc,4CAA8C0B,gBAAgBC,QAAQC,sBAE9GC,KAAK,CAAC,CACPC,WAAY,6BACZC,KAAM,CACF5B,OAAQA,OACRa,QAASA,SAEbgB,KAAM,oBACOR,eAAgB,IACrBC,mDACcQ,aAAaC,YAAa,CAACC,oBAAoB,GAAOV,gBAG5EW,KAAOC,OAAUf,sBAAagB,UAAUD,UA5B1BE,CAAcpC,OAAQa,QAASK,QAAQ,SAEpDmB,MAAMlB,sBAAagB"} --------------------------------------------------------------------------------