From ba3282385c019b2472d1f4d8861428bb43d5b82f Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Sat, 23 Nov 2024 13:07:27 +1100 Subject: [PATCH 1/7] WIP --- classes/external/condition_form.php | 12 +- classes/external/matching_users.php | 10 +- classes/external/rule_conditions.php | 14 +-- classes/external/rules.php | 156 ++++++++++++++++++++++++ db/services.php | 16 +++ tests/external/matching_users_test.php | 1 - tests/external/rule_conditions_test.php | 3 +- tests/external/rules_test.php | 109 +++++++++++++++++ 8 files changed, 294 insertions(+), 27 deletions(-) create mode 100644 classes/external/rules.php create mode 100644 tests/external/rules_test.php diff --git a/classes/external/condition_form.php b/classes/external/condition_form.php index aba13dc..0fa3d77 100644 --- a/classes/external/condition_form.php +++ b/classes/external/condition_form.php @@ -18,17 +18,13 @@ use context_system; use moodle_exception; -use external_api; -use external_function_parameters; -use external_single_structure; -use external_value; +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_single_structure; +use core_external\external_value; use tool_dynamic_cohorts\condition_base; use tool_dynamic_cohorts\condition_form as form; -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/lib/externallib.php'); - /** * Condition form AJAX submission. * diff --git a/classes/external/matching_users.php b/classes/external/matching_users.php index 5ffdf49..beec2f2 100644 --- a/classes/external/matching_users.php +++ b/classes/external/matching_users.php @@ -17,17 +17,13 @@ namespace tool_dynamic_cohorts\external; use context_system; -use external_api; -use external_function_parameters; -use external_value; +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_value; use tool_dynamic_cohorts\rule; use invalid_parameter_exception; use tool_dynamic_cohorts\rule_manager; -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/lib/externallib.php'); - /** * Matching users external APIs. * diff --git a/classes/external/rule_conditions.php b/classes/external/rule_conditions.php index b905268..64dea05 100644 --- a/classes/external/rule_conditions.php +++ b/classes/external/rule_conditions.php @@ -17,19 +17,15 @@ namespace tool_dynamic_cohorts\external; use context_system; -use external_api; -use external_function_parameters; -use external_value; -use external_multiple_structure; -use external_single_structure; +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_value; +use core_external\external_multiple_structure; +use core_external\external_single_structure; use tool_dynamic_cohorts\condition_base; use tool_dynamic_cohorts\rule; use invalid_parameter_exception; -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/lib/externallib.php'); - /** * Rule conditions external APIs. * diff --git a/classes/external/rules.php b/classes/external/rules.php new file mode 100644 index 0000000..5b0fa38 --- /dev/null +++ b/classes/external/rules.php @@ -0,0 +1,156 @@ +. + +namespace tool_dynamic_cohorts\external; + +use context_system; +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_multiple_structure; +use core_external\external_value; +use core_external\external_single_structure; +use Throwable; +use tool_dynamic_cohorts\event\rule_updated; +use tool_dynamic_cohorts\rule; +use invalid_parameter_exception; +use tool_dynamic_cohorts\rule_manager; + +/** + * Rules external APIs. + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class rules extends external_api { + + /** + * Describes the parameters for delete_rule webservice. + * + * @return external_function_parameters + */ + public static function delete_rules_parameters(): external_function_parameters { + return new external_function_parameters( + [ + 'ruleids' => new external_multiple_structure(new external_value(PARAM_INT, 'Rule IDs'), + 'List of rule ids to delete.'), + ] + ); + } + + /** + * Deletes provided rules. + * + * @param array $ruleids Rule IDs. + * @return array + */ + public static function delete_rules(array $ruleids): array { + global $DB; + + self::validate_parameters(self::delete_rules_parameters(), ['ruleids' => $ruleids]); + + $context = context_system::instance(); + self::validate_context($context); + require_capability('tool/dynamic_cohorts:manage', $context); + + // We would like to treat deletion for multiple rules as one operation. + // If one failed we would like to fail whole call and roll back. + $transaction = $DB->start_delegated_transaction(); + try { + foreach ($ruleids as $ruleid) { + $rule = rule::get_record(['id' => (int) $ruleid]); + if (empty($rule)) { + throw new invalid_parameter_exception('Rule does not exist. ID: ' . $ruleid); + } + rule_manager::delete_rule($rule); + //$transaction->allow_commit(); + } + } catch (throwable $ex) { + $transaction->rollback($ex); + } + + return []; + } + + /** + * Returns description of method result value. + * + * @return external_single_structure + */ + public static function delete_rules_returns(): external_single_structure { + return new external_single_structure([]); + } + + /** + * Enable or disable rule. + * + * @return external_function_parameters + */ + public static function toggle_status_parameters(): external_function_parameters { + return new external_function_parameters([ + 'ruleid' => new external_value(PARAM_INT, 'The rule ID to toggle'), + ]); + } + + /** + * Toggle rule. + * + * @param int $ruleid Rule ID. + * @return array + */ + public static function toggle_status(int $ruleid): array { + self::validate_parameters(self::delete_rules_parameters(), ['ruleid' => $ruleid]); + + self::validate_context(context_system::instance()); + require_capability('tool/dynamic_cohorts:manage', context_system::instance()); + + $rule = rule::get_record(['id' => $ruleid]); + if (empty($rule)) { + throw new invalid_parameter_exception('Rule does not exist.'); + } + + if ($rule->is_broken()) { + // Disable broken rule + $rule->set('enabled', 0); + $rule->save(); + rule_updated::create(['other' => ['ruleid' => $rule->get('id')]])->trigger(); + + throw new invalid_parameter_exception('A broken rule can\'t be enabled'); + } + + $newvalue = (int) !$rule->is_enabled(); + $rule->set('enabled', $newvalue); + $rule->save(); + rule_updated::create(['other' => ['ruleid' => $rule->get('id')]])->trigger(); + + return [ + 'ruleid' => $rule->get('id'), + 'enabled' => $newvalue, + ]; + } + + /** + * Returns description of method result value. + * + * @return external_single_structure + */ + public static function toggle_status_returns(): external_single_structure { + return new external_single_structure([ + 'ruleid' => new external_value(PARAM_INT, 'The rule ID'), + 'enabled' => new external_value(PARAM_INT, 'New status for the rule'), + ]); + } +} diff --git a/db/services.php b/db/services.php index e0595f3..6f05796 100644 --- a/db/services.php +++ b/db/services.php @@ -49,4 +49,20 @@ 'capabilities' => 'tool/dynamic_cohorts:manage', 'ajax' => true, ], + 'tool_dynamic_cohorts_delete_rules' => [ + 'classname' => 'tool_dynamic_cohorts\external\rules', + 'methodname' => 'delete_rules', + 'description' => 'Delete provided rules', + 'type' => 'write', + 'capabilities' => 'tool/dynamic_cohorts:manage', + 'ajax' => true, + ], + 'tool_dynamic_cohorts_toggle_rule_status' => [ + 'classname' => 'tool_dynamic_cohorts\external\rules', + 'methodname' => 'toggle_status', + 'description' => 'Toggles status for given rule (disable or enable)', + 'type' => 'write', + 'capabilities' => 'tool/dynamic_cohorts:manage', + 'ajax' => true, + ], ]; diff --git a/tests/external/matching_users_test.php b/tests/external/matching_users_test.php index 620fb3d..39ed201 100644 --- a/tests/external/matching_users_test.php +++ b/tests/external/matching_users_test.php @@ -32,7 +32,6 @@ * @copyright 2024 Catalyst IT * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * - * @runTestsInSeparateProcesses * @covers \tool_dynamic_cohorts\external\matching_users */ class matching_users_test extends externallib_advanced_testcase { diff --git a/tests/external/rule_conditions_test.php b/tests/external/rule_conditions_test.php index 1d065da..6909aff 100644 --- a/tests/external/rule_conditions_test.php +++ b/tests/external/rule_conditions_test.php @@ -33,8 +33,7 @@ * @package tool_dynamic_cohorts * @copyright 2024 Catalyst IT * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - - * @runTestsInSeparateProcesses + * * @covers \tool_dynamic_cohorts\external\rule_conditions */ class rule_conditions_test extends externallib_advanced_testcase { diff --git a/tests/external/rules_test.php b/tests/external/rules_test.php new file mode 100644 index 0000000..785f84b --- /dev/null +++ b/tests/external/rules_test.php @@ -0,0 +1,109 @@ +. + +namespace tool_dynamic_cohorts\external; + +use externallib_advanced_testcase; +use tool_dynamic_cohorts\rule; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/webservice/tests/helpers.php'); + +/** + * Tests for matching users external APIs . + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * + * @covers \tool_dynamic_cohorts\external\rules + */ +class rules_test extends externallib_advanced_testcase { + + /** + * Test exception if rule is not exist. + */ + public function test_delete_rules_exception_on_invalid_rule() { + $this->resetAfterTest(); + + $this->setAdminUser(); + $this->expectException(\invalid_parameter_exception::class); + $this->expectExceptionMessage('Rule does not exist. ID: 777'); + + rules::delete_rules([777]); + } + + /** + * Test required permissions. + */ + public function test_delete_rules_permissions() { + $this->resetAfterTest(); + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(\required_capability_exception::class); + $this->expectExceptionMessage('Sorry, but you do not currently have permissions to do that (Manage rules).'); + + rules::delete_rules([777]); + } + + /** + * Test can get total. + */ + public function test_exception_delete_rules_when_one_is_invalid() { + $this->resetAfterTest(); + $this->setAdminUser(); + + $rule = new rule(0, (object)['name' => 'Test rule 1']); + $rule->save(); + + $this->expectException(\invalid_parameter_exception::class); + $this->expectExceptionMessage('Rule does not exist. ID: 777'); + + rules::delete_rules([$rule->get('id'), 777]); + } + + /** + * Test can get total. + */ + public function test_delete_rules_keep_rules_when_one_is_invalid() { + $this->resetAfterTest(); + $this->setAdminUser(); + + $rule1 = new rule(0, (object)['name' => 'Test rule 1']); + $rule1->save(); + + $rule2 = new rule(0, (object)['name' => 'Test rule 2']); + $rule2->save(); + + $this->assertCount(2, rule::get_records()); + + $this->expectException(\required_capability_exception::class); + $this->expectExceptionMessage('Rule does not exist. ID: 777'); + + try { + rules::delete_rules([$rule1->get('id'), $rule2->get('id'), 777]); + } catch (\invalid_parameter_exception $exception) { + $this->assertSame( + 'Invalid parameter value detected (Rule does not exist. ID: 777)', + $exception->getMessage() + ); + $this->assertCount(2, rule::get_records()); + } + } +} From 70e04a5c12b5629c85c1ecd61f0a8b63a0731459 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Wed, 4 Dec 2024 16:34:48 +1100 Subject: [PATCH 2/7] issue #116: add WS to delete and toggle rules --- classes/external/rules.php | 32 ++++++++-------- tests/external/rules_test.php | 72 ++++++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 22 deletions(-) diff --git a/classes/external/rules.php b/classes/external/rules.php index 5b0fa38..6a0fae4 100644 --- a/classes/external/rules.php +++ b/classes/external/rules.php @@ -58,8 +58,6 @@ public static function delete_rules_parameters(): external_function_parameters { * @return array */ public static function delete_rules(array $ruleids): array { - global $DB; - self::validate_parameters(self::delete_rules_parameters(), ['ruleids' => $ruleids]); $context = context_system::instance(); @@ -67,19 +65,19 @@ public static function delete_rules(array $ruleids): array { require_capability('tool/dynamic_cohorts:manage', $context); // We would like to treat deletion for multiple rules as one operation. - // If one failed we would like to fail whole call and roll back. - $transaction = $DB->start_delegated_transaction(); - try { - foreach ($ruleids as $ruleid) { - $rule = rule::get_record(['id' => (int) $ruleid]); - if (empty($rule)) { - throw new invalid_parameter_exception('Rule does not exist. ID: ' . $ruleid); - } - rule_manager::delete_rule($rule); - //$transaction->allow_commit(); + // So let's check that all rules exist and then delete them. + // Otherwise throw an exception and fail whole WS call. + $rulestodelete = []; + foreach ($ruleids as $ruleid) { + $rule = rule::get_record(['id' => (int) $ruleid]); + if (empty($rule)) { + throw new invalid_parameter_exception('Rule does not exist. ID: ' . $ruleid); } - } catch (throwable $ex) { - $transaction->rollback($ex); + $rulestodelete[] = $rule; + } + + foreach ($rulestodelete as $rule) { + rule_manager::delete_rule($rule); } return []; @@ -112,14 +110,14 @@ public static function toggle_status_parameters(): external_function_parameters * @return array */ public static function toggle_status(int $ruleid): array { - self::validate_parameters(self::delete_rules_parameters(), ['ruleid' => $ruleid]); + self::validate_parameters(self::toggle_status_parameters(), ['ruleid' => $ruleid]); self::validate_context(context_system::instance()); require_capability('tool/dynamic_cohorts:manage', context_system::instance()); $rule = rule::get_record(['id' => $ruleid]); if (empty($rule)) { - throw new invalid_parameter_exception('Rule does not exist.'); + throw new invalid_parameter_exception('Rule does not exist. ID: ' . $ruleid); } if ($rule->is_broken()) { @@ -128,7 +126,7 @@ public static function toggle_status(int $ruleid): array { $rule->save(); rule_updated::create(['other' => ['ruleid' => $rule->get('id')]])->trigger(); - throw new invalid_parameter_exception('A broken rule can\'t be enabled'); + throw new invalid_parameter_exception('A broken rule can\'t be enabled ID: ' . $ruleid); } $newvalue = (int) !$rule->is_enabled(); diff --git a/tests/external/rules_test.php b/tests/external/rules_test.php index 785f84b..35e00ce 100644 --- a/tests/external/rules_test.php +++ b/tests/external/rules_test.php @@ -63,7 +63,7 @@ public function test_delete_rules_permissions() { } /** - * Test can get total. + * Test exception thrown on deleting invalid rule. */ public function test_exception_delete_rules_when_one_is_invalid() { $this->resetAfterTest(); @@ -79,7 +79,7 @@ public function test_exception_delete_rules_when_one_is_invalid() { } /** - * Test can get total. + * Test rules are not deleted if one is invalid. */ public function test_delete_rules_keep_rules_when_one_is_invalid() { $this->resetAfterTest(); @@ -93,9 +93,6 @@ public function test_delete_rules_keep_rules_when_one_is_invalid() { $this->assertCount(2, rule::get_records()); - $this->expectException(\required_capability_exception::class); - $this->expectExceptionMessage('Rule does not exist. ID: 777'); - try { rules::delete_rules([$rule1->get('id'), $rule2->get('id'), 777]); } catch (\invalid_parameter_exception $exception) { @@ -106,4 +103,69 @@ public function test_delete_rules_keep_rules_when_one_is_invalid() { $this->assertCount(2, rule::get_records()); } } + + /** + * Test exception if rule is not exist. + */ + public function test_toggle_status_exception_on_invalid_rule() { + $this->resetAfterTest(); + + $this->setAdminUser(); + $this->expectException(\invalid_parameter_exception::class); + $this->expectExceptionMessage('Rule does not exist. ID: 777'); + + rules::toggle_status(777); + } + + /** + * Test required permissions. + */ + public function test_toggle_status_permissions() { + $this->resetAfterTest(); + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(\required_capability_exception::class); + $this->expectExceptionMessage('Sorry, but you do not currently have permissions to do that (Manage rules).'); + + rules::toggle_status(777); + } + + /** + * Test exception is thrown trying to toggle a broken rule + */ + public function test_exception_toggle_status_on_broken_rule() { + $this->resetAfterTest(); + $this->setAdminUser(); + + $rule = new rule(0, (object)['name' => 'Test rule 1']); + $rule->set('broken', 1); + $rule->save(); + + $this->expectException(\invalid_parameter_exception::class); + $this->expectExceptionMessage('A broken rule can\'t be enabled ID: ' . $rule->get('id')); + + rules::toggle_status($rule->get('id')); + } + + /** + * Test toggling status on rule. + */ + public function test_toggle_status_on_rule() { + $this->resetAfterTest(); + $this->setAdminUser(); + + $rule = new rule(0, (object)['name' => 'Test rule 1']); + $rule->save(); + + $this->assertFalse($rule->is_enabled()); + + rules::toggle_status($rule->get('id')); + $rule = rule::get_record(['id' => $rule->get('id')]); + $this->assertTrue($rule->is_enabled()); + + rules::toggle_status($rule->get('id')); + $rule = rule::get_record(['id' => $rule->get('id')]); + $this->assertFalse($rule->is_enabled()); + } } From ab7261d0cc6f697732ffd0fa81ba2511e75d424f Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Sat, 14 Dec 2024 12:15:22 +1100 Subject: [PATCH 3/7] issue #116: display matching users in a modal --- amd/build/manage_rules.min.js | 4 +- amd/build/manage_rules.min.js.map | 2 +- amd/src/manage_rules.js | 81 +++++++++++++++++++++++++++---- lib.php | 30 ++++++++++++ 4 files changed, 104 insertions(+), 13 deletions(-) diff --git a/amd/build/manage_rules.min.js b/amd/build/manage_rules.min.js index 434ab5a..a62f113 100644 --- a/amd/build/manage_rules.min.js +++ b/amd/build/manage_rules.min.js @@ -1,10 +1,10 @@ -define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notification","core/templates","core/modal_events","core/local/modal/alert","core/str","core_table/dynamic"],(function(_exports,_ajax,_notification,_templates,_modal_events,_alert,_str,DynamicTable){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 _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notification","core/templates","core/modal_events","core/str","core_table/dynamic","core/fragment","core/modal_cancel"],(function(_exports,_ajax,_notification,_templates,_modal_events,_str,DynamicTable,_fragment,_modal_cancel){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 _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * Manage rules JS module. * * @module tool_dynamic_cohorts/manage_rules * @copyright 2024 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),_alert=_interopRequireDefault(_alert),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view";_exports.init=()=>{loadMatchingUsers(),initRuleConditionsModals(),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(()=>loadMatchingUsers())),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(()=>initRuleConditionsModals()))};const loadMatchingUsers=()=>{Array.from(document.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=()=>{document.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_alert.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view";_exports.init=()=>{loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))}})); //# sourceMappingURL=manage_rules.min.js.map \ No newline at end of file diff --git a/amd/build/manage_rules.min.js.map b/amd/build/manage_rules.min.js.map index 07c1076..9a550d4 100644 --- a/amd/build/manage_rules.min.js.map +++ b/amd/build/manage_rules.min.js.map @@ -1 +1 @@ -{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport ModalAlert from \"core/local/modal/alert\";\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n loadMatchingUsers();\n initRuleConditionsModals();\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, () => loadMatchingUsers());\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, () => initRuleConditionsModals());\n};\n\n/**\n * Load matching users for each rule.\n */\nconst loadMatchingUsers = () => {\n Array.from(document.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n */\nconst initRuleConditionsModals = () => {\n document.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalAlert.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n"],"names":["SELECTORS","loadMatchingUsers","initRuleConditionsModals","document","addEventListener","DynamicTable","Events","tableContentRefreshed","Array","from","getElementsByClassName","forEach","collection","ruleid","dataset","loader","children","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","then","html","create","title","body","large","modal","getRoot","on","ModalEvents","hidden","destroy","show"],"mappings":";;;;;;;g+BAkCMA,8BACmB,sCADnBA,0BAEe,qDAMD,KAChBC,oBACAC,2BAEAC,SAASC,iBAAiBC,aAAaC,OAAOC,uBAAuB,IAAMN,sBAC3EE,SAASC,iBAAiBC,aAAaC,OAAOC,uBAAuB,IAAML,oCAMzED,kBAAoB,KACtBO,MAAMC,KAAKN,SAASO,uBAAuBV,gCAAgCW,SAASC,mBAC1EC,OAASD,WAAWE,QAAQD,OAC5BE,OAASH,WAAWI,SAAS,GAC7BC,KAAOL,WAAWI,SAAS,iBAE5BE,KAAK,CAAC,CACPC,WAAY,yDACZC,KAAM,CAACP,OAAQA,QACfQ,KAAM,SAAUC,QACZL,KAAKD,SAAS,GAAGO,OAAOD,OAAOE,iBAAiBC,QAAQ,KAAM,MAC9DV,OAAOW,UAAUC,IAAI,UACrBV,KAAKS,UAAUE,OAAO,WAE1BC,KAAM,SAAUC,gCACCC,UAAUD,kBASjC5B,yBAA2B,KAC7BC,SAAS6B,iBAAiBhC,2BAA2BW,SAAQM,WACrDJ,OAASI,KAAKH,QAAQD,OAC1BI,KAAKb,iBAAiB,SAAS,yBACtBc,KAAK,CAAC,CACPC,WAAY,sCACZC,KAAM,CAACP,OAAQA,QACfQ,KAAM,SAAUY,+BACFC,OACN,kCACA,YAAgBD,yBAA4B,IAC9CE,MAAK,SAASC,qBACDC,OAAO,CACdC,OAAO,mBAAU,sBAAuB,wBACxCC,KAAMH,KACNI,OAAO,IACRL,MAAK,SAAUM,OACdA,MAAMC,UAAUC,GAAGC,sBAAYC,QAAQ,WACnCJ,MAAMK,aAEVL,MAAMM,aAEXlB,MAAK,SAASC,gCACAC,UAAUD,cAG/BD,KAAM,SAAUC,gCACCC,UAAUD"} \ No newline at end of file +{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n"],"names":["SELECTORS","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html"],"mappings":";;;;;;;0hCAmCMA,8BACmB,sCADnBA,0BAEe,qDAMD,KAChBC,kBAAkBC,UAClBC,wBAAwBD,UACxBE,yBAAyBF,UAEzBA,SAASG,iBAAiBC,aAAaC,OAAOC,uBAAuBC,UAC3DC,UAAYJ,aAAaK,eAAeF,EAAEG,OAAOC,QAAQC,eAE/DX,wBAAwBO,WACxBT,kBAAkBS,WAClBN,yBAAyBM,qBAS3BP,wBAA2BY,OAC7BC,MAAMC,KAAKF,KAAKG,uBAAuBlB,gCAAgCmB,SAASC,mBACtEC,OAASD,WAAWP,QAAQQ,OACrBD,WAAWE,SAAS,GAC5BjB,iBAAiB,SAAS,SAASI,GACpCA,EAAEc,iBACFC,qBAAqBH,eAU3BG,qBAAwBH,+BAEdI,OAAO,CACfC,OAAO,mBAAU,gBAAiB,wBAClCC,KAAMC,0BAA0BP,QAChCQ,OAAO,IACRC,MAAK,SAAUC,OACdA,MAAMC,UAAUC,GAAGC,sBAAYC,QAAQ,WACnCJ,MAAMK,aAGVL,MAAMM,WAURT,0BAA6BP,eACzBiB,OAAS,CACXjB,OAAQA,eAGLkB,kBAASC,aAAa,uBAAwB,iBAAkB,EAAGF,SAQxErC,kBAAqBc,OACvBC,MAAMC,KAAKF,KAAKG,uBAAuBlB,gCAAgCmB,SAASC,mBACtEC,OAASD,WAAWP,QAAQQ,OAC5BoB,OAASrB,WAAWE,SAAS,GAC7BoB,KAAOtB,WAAWE,SAAS,iBAE5BqB,KAAK,CAAC,CACPC,WAAY,yDACZC,KAAM,CAACxB,OAAQA,QACfyB,KAAM,SAAUC,QACZL,KAAKpB,SAAS,GAAG0B,OAAOD,OAAOE,iBAAiBC,QAAQ,KAAM,MAC9DT,OAAOU,UAAUC,IAAI,UACrBV,KAAKS,UAAUE,OAAO,WAE1BC,KAAM,SAAUC,gCACCC,UAAUD,kBAWjCnD,yBAA4BW,OAC9BA,KAAK0C,iBAAiBzD,2BAA2BmB,SAAQuB,WACjDrB,OAASqB,KAAK7B,QAAQQ,OAC1BqB,KAAKrC,iBAAiB,SAAS,yBACtBsC,KAAK,CAAC,CACPC,WAAY,sCACZC,KAAM,CAACxB,OAAQA,QACfyB,KAAM,SAAUY,+BACFC,OACN,kCACA,YAAgBD,yBAA4B,IAC9C5B,MAAK,SAAS8B,4BACAnC,OAAO,CACfC,OAAO,mBAAU,sBAAuB,wBACxCC,KAAMiC,KACN/B,OAAO,IACRC,MAAK,SAAUC,OACdA,MAAMC,UAAUC,GAAGC,sBAAYC,QAAQ,WACnCJ,MAAMK,aAEVL,MAAMM,aAEXiB,MAAK,SAASC,gCACAC,UAAUD,cAG/BD,KAAM,SAAUC,gCACCC,UAAUD"} \ No newline at end of file diff --git a/amd/src/manage_rules.js b/amd/src/manage_rules.js index 93cfe8a..b3a2d9d 100644 --- a/amd/src/manage_rules.js +++ b/amd/src/manage_rules.js @@ -25,9 +25,10 @@ import Ajax from 'core/ajax'; import Notification from 'core/notification'; import Templates from 'core/templates'; import ModalEvents from 'core/modal_events'; -import ModalAlert from "core/local/modal/alert"; import {get_string as getString} from 'core/str'; import * as DynamicTable from 'core_table/dynamic'; +import Fragment from 'core/fragment'; +import ModalCancel from 'core/modal_cancel'; /** * A list of used selectors. @@ -41,18 +42,76 @@ const SELECTORS = { * Init of the module. */ export const init = () => { - loadMatchingUsers(); - initRuleConditionsModals(); + loadMatchingUsers(document); + initMatchingUsersModals(document); + initRuleConditionsModals(document); - document.addEventListener(DynamicTable.Events.tableContentRefreshed, () => loadMatchingUsers()); - document.addEventListener(DynamicTable.Events.tableContentRefreshed, () => initRuleConditionsModals()); + document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => { + const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid); + + initMatchingUsersModals(tableRoot); + loadMatchingUsers(tableRoot); + initRuleConditionsModals(tableRoot); + }); +}; + +/** + * Initialise modals for matching users. + * + * @param {Element} root + */ +const initMatchingUsersModals = (root) => { + Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => { + const ruleid = collection.dataset.ruleid; + const link = collection.children[1]; + link.addEventListener('click', function(e) { + e.preventDefault(); + displayMatchingUsers(ruleid); + }); + }); +}; + +/** + * Display matching users in the modal form. + * + * @param {string} ruleid + */ +const displayMatchingUsers = (ruleid) => { + + ModalCancel.create({ + title: getString('matchingusers', 'tool_dynamic_cohorts'), + body: getMatchingUsersModalBody(ruleid), + large: true, + }).then(function (modal) { + modal.getRoot().on(ModalEvents.hidden, function() { + modal.destroy(); + }); + + modal.show(); + }); +}; + +/** + * Get modal html body for matching users using fragment API. + * + * @param {string} ruleid + * @returns {Promise} + */ +const getMatchingUsersModalBody = (ruleid) => { + const params = { + ruleid: ruleid, + }; + + return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params); }; /** * Load matching users for each rule. + * + * @param {Element} root */ -const loadMatchingUsers = () => { - Array.from(document.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => { +const loadMatchingUsers = (root) => { + Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => { const ruleid = collection.dataset.ruleid; const loader = collection.children[0]; const link = collection.children[1]; @@ -74,9 +133,11 @@ const loadMatchingUsers = () => { /** * Initialise displaying each rule conditions in a modal. + * + * @param {Element} root */ -const initRuleConditionsModals = () => { - document.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => { +const initRuleConditionsModals = (root) => { + root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => { let ruleid = link.dataset.ruleid; link.addEventListener('click', function() { Ajax.call([{ @@ -87,7 +148,7 @@ const initRuleConditionsModals = () => { 'tool_dynamic_cohorts/conditions', {'conditions' : conditions, 'hidecontrols': true} ).then(function(html) { - ModalAlert.create({ + ModalCancel.create({ title: getString('conditionsformtitle', 'tool_dynamic_cohorts'), body: html, large: true, diff --git a/lib.php b/lib.php index 6445add..08862c6 100644 --- a/lib.php +++ b/lib.php @@ -22,7 +22,10 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use core_reportbuilder\system_report_factory; use tool_dynamic_cohorts\condition_form; +use tool_dynamic_cohorts\rule; +use tool_dynamic_cohorts\reportbuilder\local\systemreports\matching_users; /** * A new condition form as a fragment. @@ -60,3 +63,30 @@ function tool_dynamic_cohorts_output_fragment_condition_form(array $args): strin return $mform->render(); } + +/** + * A matching users table as a fragment. + * + * @param array $args List of named arguments for the fragment loader. + * @return string + */ +function tool_dynamic_cohorts_output_fragment_matching_users(array $args): string { + $args = (object) $args; + $ruleid = clean_param($args->ruleid, PARAM_INT); + + $rule = rule::get_record(['id' => $ruleid]); + if (empty($rule)) { + throw new dml_missing_record_exception(null); + } + + $report = system_report_factory::create( + matching_users::class, + context_system::instance(), + 'tool_dynamic_cohorts', + '', + 0, + ['ruleid' => $ruleid] + ); + + return $report->output(); +} From a4425df2d58c10a9dbcded2018148eb2fae30c29 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Mon, 17 Feb 2025 20:32:54 +1100 Subject: [PATCH 4/7] WIP --- amd/build/manage_rules.min.js | 4 +- amd/build/manage_rules.min.js.map | 2 +- amd/src/manage_rules.js | 99 +++++++++++++++++++ .../local/systemreports/matching_users.php | 7 +- .../local/systemreports/rules.php | 6 +- classes/rule_manager.php | 3 + lang/en/tool_dynamic_cohorts.php | 3 + version.php | 2 +- 8 files changed, 116 insertions(+), 10 deletions(-) diff --git a/amd/build/manage_rules.min.js b/amd/build/manage_rules.min.js index a62f113..9887826 100644 --- a/amd/build/manage_rules.min.js +++ b/amd/build/manage_rules.min.js @@ -1,10 +1,10 @@ -define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notification","core/templates","core/modal_events","core/str","core_table/dynamic","core/fragment","core/modal_cancel"],(function(_exports,_ajax,_notification,_templates,_modal_events,_str,DynamicTable,_fragment,_modal_cancel){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 _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notification","core/templates","core/modal_events","core/str","core_table/dynamic","core/fragment","core/modal_cancel","core_table/local/dynamic/selectors","core/toast"],(function(_exports,_ajax,_notification,_templates,_modal_events,_str,DynamicTable,_fragment,_modal_cancel,_selectors,_toast){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 _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * Manage rules JS module. * * @module tool_dynamic_cohorts/manage_rules * @copyright 2024 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view";_exports.init=()=>{loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel),_selectors=_interopRequireDefault(_selectors);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view",SELECTORS_RULE_TOGGLE=".tool-dynamic-cohorts-rule-toggle",SELECTORS_RULE_DELETE=".tool-dynamic-cohorts-rule-delete";_exports.init=()=>{loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),initRuleToggle(document),initRuleDelete(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot),initRuleToggle(tableRoot),initRuleDelete(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))},sendFeedback=action=>{(0,_str.get_string)("completed:"+action,"tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message)})).catch(_notification.default.exception)},getDynamicTableFromLink=link=>link.closest(_selectors.default.main.region),initRuleToggle=root=>{root.querySelectorAll(SELECTORS_RULE_TOGGLE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_toggle_rule_status",args:{ruleid:ruleid},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getDynamicTableFromLink(link)).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleDelete=root=>{root.querySelectorAll(SELECTORS_RULE_DELETE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_delete_rules`",args:{ruleids:{ruleid:ruleid}},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getDynamicTableFromLink(link)).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))}})); //# sourceMappingURL=manage_rules.min.js.map \ No newline at end of file diff --git a/amd/build/manage_rules.min.js.map b/amd/build/manage_rules.min.js.map index 9a550d4..ef8d21f 100644 --- a/amd/build/manage_rules.min.js.map +++ b/amd/build/manage_rules.min.js.map @@ -1 +1 @@ -{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n"],"names":["SELECTORS","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html"],"mappings":";;;;;;;0hCAmCMA,8BACmB,sCADnBA,0BAEe,qDAMD,KAChBC,kBAAkBC,UAClBC,wBAAwBD,UACxBE,yBAAyBF,UAEzBA,SAASG,iBAAiBC,aAAaC,OAAOC,uBAAuBC,UAC3DC,UAAYJ,aAAaK,eAAeF,EAAEG,OAAOC,QAAQC,eAE/DX,wBAAwBO,WACxBT,kBAAkBS,WAClBN,yBAAyBM,qBAS3BP,wBAA2BY,OAC7BC,MAAMC,KAAKF,KAAKG,uBAAuBlB,gCAAgCmB,SAASC,mBACtEC,OAASD,WAAWP,QAAQQ,OACrBD,WAAWE,SAAS,GAC5BjB,iBAAiB,SAAS,SAASI,GACpCA,EAAEc,iBACFC,qBAAqBH,eAU3BG,qBAAwBH,+BAEdI,OAAO,CACfC,OAAO,mBAAU,gBAAiB,wBAClCC,KAAMC,0BAA0BP,QAChCQ,OAAO,IACRC,MAAK,SAAUC,OACdA,MAAMC,UAAUC,GAAGC,sBAAYC,QAAQ,WACnCJ,MAAMK,aAGVL,MAAMM,WAURT,0BAA6BP,eACzBiB,OAAS,CACXjB,OAAQA,eAGLkB,kBAASC,aAAa,uBAAwB,iBAAkB,EAAGF,SAQxErC,kBAAqBc,OACvBC,MAAMC,KAAKF,KAAKG,uBAAuBlB,gCAAgCmB,SAASC,mBACtEC,OAASD,WAAWP,QAAQQ,OAC5BoB,OAASrB,WAAWE,SAAS,GAC7BoB,KAAOtB,WAAWE,SAAS,iBAE5BqB,KAAK,CAAC,CACPC,WAAY,yDACZC,KAAM,CAACxB,OAAQA,QACfyB,KAAM,SAAUC,QACZL,KAAKpB,SAAS,GAAG0B,OAAOD,OAAOE,iBAAiBC,QAAQ,KAAM,MAC9DT,OAAOU,UAAUC,IAAI,UACrBV,KAAKS,UAAUE,OAAO,WAE1BC,KAAM,SAAUC,gCACCC,UAAUD,kBAWjCnD,yBAA4BW,OAC9BA,KAAK0C,iBAAiBzD,2BAA2BmB,SAAQuB,WACjDrB,OAASqB,KAAK7B,QAAQQ,OAC1BqB,KAAKrC,iBAAiB,SAAS,yBACtBsC,KAAK,CAAC,CACPC,WAAY,sCACZC,KAAM,CAACxB,OAAQA,QACfyB,KAAM,SAAUY,+BACFC,OACN,kCACA,YAAgBD,yBAA4B,IAC9C5B,MAAK,SAAS8B,4BACAnC,OAAO,CACfC,OAAO,mBAAU,sBAAuB,wBACxCC,KAAMiC,KACN/B,OAAO,IACRC,MAAK,SAAUC,OACdA,MAAMC,UAAUC,GAAGC,sBAAYC,QAAQ,WACnCJ,MAAMK,aAEVL,MAAMM,aAEXiB,MAAK,SAASC,gCACAC,UAAUD,cAG/BD,KAAM,SAAUC,gCACCC,UAAUD"} \ No newline at end of file +{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\nimport {add as notifyUser} from 'core/toast';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle',\n RULE_DELETE: '.tool-dynamic-cohorts-rule-delete',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n initRuleToggle(document);\n initRuleDelete(document);\n\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n initRuleToggle(tableRoot);\n initRuleDelete(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n\n/**\n * Send feedback to a user.\n *\n * @param {string} action Action to send feedback about.\n */\nconst sendFeedback = (action) => {\n getString('completed:' + action, 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message);\n }).catch(Notification.exception);\n};\n\n/**\n *\n * @param link\n * @returns {*}\n */\nconst getDynamicTableFromLink = (link) => {\n return link.closest(DynamicTableSelectors.main.region);\n};\n\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleToggle = (root) => {\n root.querySelectorAll(SELECTORS.RULE_TOGGLE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_toggle_rule_status',\n args: {ruleid: ruleid},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getDynamicTableFromLink(link))\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleDelete = (root) => {\n root.querySelectorAll(SELECTORS.RULE_DELETE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_delete_rules`',\n args: {ruleids: {ruleid}},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getDynamicTableFromLink(link))\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n"],"names":["SELECTORS","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","initRuleToggle","initRuleDelete","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html","sendFeedback","action","message","catch","Notification","getDynamicTableFromLink","closest","DynamicTableSelectors","main","region","confirm","refreshTableContent","ruleids"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/manage_rules.js b/amd/src/manage_rules.js index b3a2d9d..6dc21fb 100644 --- a/amd/src/manage_rules.js +++ b/amd/src/manage_rules.js @@ -29,6 +29,8 @@ import {get_string as getString} from 'core/str'; import * as DynamicTable from 'core_table/dynamic'; import Fragment from 'core/fragment'; import ModalCancel from 'core/modal_cancel'; +import DynamicTableSelectors from 'core_table/local/dynamic/selectors'; +import {add as notifyUser} from 'core/toast'; /** * A list of used selectors. @@ -36,6 +38,8 @@ import ModalCancel from 'core/modal_cancel'; const SELECTORS = { RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users', RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view', + RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle', + RULE_DELETE: '.tool-dynamic-cohorts-rule-delete', }; /** @@ -45,6 +49,9 @@ export const init = () => { loadMatchingUsers(document); initMatchingUsersModals(document); initRuleConditionsModals(document); + initRuleToggle(document); + initRuleDelete(document); + document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => { const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid); @@ -52,6 +59,8 @@ export const init = () => { initMatchingUsersModals(tableRoot); loadMatchingUsers(tableRoot); initRuleConditionsModals(tableRoot); + initRuleToggle(tableRoot); + initRuleDelete(tableRoot); }); }; @@ -169,3 +178,93 @@ const initRuleConditionsModals = (root) => { }); }); }; + +/** + * Send feedback to a user. + * + * @param {string} action Action to send feedback about. + */ +const sendFeedback = (action) => { + getString('completed:' + action, 'tool_dynamic_cohorts') + .then(message => { + notifyUser(message); + }).catch(Notification.exception); +}; + +/** + * + * @param link + * @returns {*} + */ +const getDynamicTableFromLink = (link) => { + return link.closest(DynamicTableSelectors.main.region); +}; + + +/** + * Initialise displaying each rule conditions in a modal. + * + * @param {Element} root + */ +const initRuleToggle = (root) => { + root.querySelectorAll(SELECTORS.RULE_TOGGLE).forEach(link => { + let ruleid = link.dataset.ruleid; + let action = link.dataset.action; + link.addEventListener('click', function(e) { + e.preventDefault(); + Notification.confirm( + getString('confirm', 'moodle'), + getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid), + getString('yes', 'moodle'), + getString('no', 'moodle'), + function () { + Ajax.call([{ + methodname: 'tool_dynamic_cohorts_toggle_rule_status', + args: {ruleid: ruleid}, + done: function () { + sendFeedback(action); + DynamicTable.refreshTableContent(getDynamicTableFromLink(link)) + .catch(Notification.exception); + }, + fail: function (response) { + Notification.exception(response); + } + }]); + }); + }); + }); +}; + +/** + * Initialise displaying each rule conditions in a modal. + * + * @param {Element} root + */ +const initRuleDelete = (root) => { + root.querySelectorAll(SELECTORS.RULE_DELETE).forEach(link => { + let ruleid = link.dataset.ruleid; + let action = link.dataset.action; + link.addEventListener('click', function(e) { + e.preventDefault(); + Notification.confirm( + getString('confirm', 'moodle'), + getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid), + getString('yes', 'moodle'), + getString('no', 'moodle'), + function () { + Ajax.call([{ + methodname: 'tool_dynamic_cohorts_delete_rules`', + args: {ruleids: {ruleid}}, + done: function () { + sendFeedback(action); + DynamicTable.refreshTableContent(getDynamicTableFromLink(link)) + .catch(Notification.exception); + }, + fail: function (response) { + Notification.exception(response); + } + }]); + }); + }); + }); +}; diff --git a/classes/reportbuilder/local/systemreports/matching_users.php b/classes/reportbuilder/local/systemreports/matching_users.php index 47716c5..eb45813 100644 --- a/classes/reportbuilder/local/systemreports/matching_users.php +++ b/classes/reportbuilder/local/systemreports/matching_users.php @@ -48,16 +48,17 @@ protected function initialise(): void { $this->add_entity($userentity); $conditions = $rule->get_condition_records(); + $sql = condition_manager::build_sql_data($conditions, $rule->get('operator')); + if (empty($conditions) || $rule->is_broken()) { // No conditions. Filter out all users. $this->add_base_condition_sql(' true = false'); + } else { + $this->add_base_condition_sql($sql->get_where(), $sql->get_params()); } - $sql = condition_manager::build_sql_data($conditions, $rule->get('operator')); - $this->add_base_fields('DISTINCT u.id'); $this->add_join($sql->get_join()); - $this->add_base_condition_sql($sql->get_where(), $sql->get_params()); $this->add_column_from_entity('user:fullnamewithlink'); $this->add_column_from_entity('user:username'); diff --git a/classes/reportbuilder/local/systemreports/rules.php b/classes/reportbuilder/local/systemreports/rules.php index 295fa09..3d6517e 100644 --- a/classes/reportbuilder/local/systemreports/rules.php +++ b/classes/reportbuilder/local/systemreports/rules.php @@ -149,7 +149,7 @@ protected function add_actions(): void { $this->add_action((new action( new moodle_url('/admin/tool/dynamic_cohorts/toggle.php', ['ruleid' => ':id', 'sesskey' => sesskey()]), new pix_icon('t/hide', '', 'core'), - [], + ['class' => 'tool-dynamic-cohorts-rule-toggle', 'data-ruleid' => ':id', 'data-action' => 'enable'], false, new lang_string('enable') ))->add_callback(function(\stdClass $row): bool { @@ -159,7 +159,7 @@ protected function add_actions(): void { $this->add_action((new action( new moodle_url('/admin/tool/dynamic_cohorts/toggle.php', ['ruleid' => ':id', 'sesskey' => sesskey()]), new pix_icon('t/show', '', 'core'), - [], + ['class' => 'tool-dynamic-cohorts-rule-toggle', 'data-ruleid' => ':id', 'data-action' => 'disable'], false, new lang_string('disable') ))->add_callback(function(\stdClass $row): bool { @@ -177,7 +177,7 @@ protected function add_actions(): void { $this->add_action((new action( new moodle_url('/admin/tool/dynamic_cohorts/delete.php', ['ruleid' => ':id', 'sesskey' => sesskey()]), new pix_icon('t/delete', '', 'core'), - [], + ['class' => 'tool-dynamic-cohorts-rule-delete', 'data-ruleid' => ':id', 'data-action' => 'delete'], false, new lang_string('delete') ))); diff --git a/classes/rule_manager.php b/classes/rule_manager.php index 8e41bd7..cc6609f 100644 --- a/classes/rule_manager.php +++ b/classes/rule_manager.php @@ -264,6 +264,9 @@ public static function get_matching_users(rule $rule, ?int $userid = null): arra public static function get_matching_users_count(rule $rule, ?int $userid = null): int { global $DB; + // TODO: add caching as we would need to return users count on each page refresh. + // Cache should be rebuilt on every rule change for a specific rule. + $conditions = $rule->get_condition_records(); if (empty($conditions)) { diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index 9ad2c1b..766a03b 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -42,6 +42,9 @@ $string['cohortid'] = 'Cohort'; $string['cohortswith'] = 'Cohort(s) with field'; $string['cohortid_help'] = 'A cohort to manage as part of this rule. Only cohorts that are not managed by other plugins are displayed in this list.'; +$string['completed:delete'] = 'Rule has been deleted'; +$string['completed:enable'] = 'Rule has been enabled'; +$string['completed:disable'] = 'Rule has been disabled'; $string['completiondate'] = 'Completion date'; $string['completionisdisabled'] = 'Completion is disabled for configured course'; $string['condition'] = 'Condition'; diff --git a/version.php b/version.php index 5e3aa8e..1865255 100644 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ $plugin->component = 'tool_dynamic_cohorts'; $plugin->release = 2024112100; -$plugin->version = 2024112100; +$plugin->version = 2024112101; $plugin->requires = 2022112800; $plugin->supported = [404, 405]; $plugin->maturity = MATURITY_STABLE; From 94e7a8e109f668f0c2693ddb44a288466524cfc5 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Fri, 21 Feb 2025 23:43:06 +1100 Subject: [PATCH 5/7] issue #116: move edit form to modal --- amd/build/manage_rules.min.js | 4 +- amd/build/manage_rules.min.js.map | 2 +- amd/src/manage_rules.js | 87 +++++++++++-- classes/external/rules.php | 3 +- .../local/systemreports/rules.php | 12 +- classes/rule_form.php | 114 ++++++++++++++++-- classes/rule_manager.php | 4 - delete.php | 55 --------- edit.php | 75 ------------ lang/en/tool_dynamic_cohorts.php | 2 + templates/button.mustache | 2 +- toggle.php | 74 ------------ users.php | 67 ---------- 13 files changed, 196 insertions(+), 305 deletions(-) delete mode 100644 delete.php delete mode 100644 edit.php delete mode 100644 toggle.php delete mode 100644 users.php diff --git a/amd/build/manage_rules.min.js b/amd/build/manage_rules.min.js index 9887826..6b8f469 100644 --- a/amd/build/manage_rules.min.js +++ b/amd/build/manage_rules.min.js @@ -1,10 +1,10 @@ -define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notification","core/templates","core/modal_events","core/str","core_table/dynamic","core/fragment","core/modal_cancel","core_table/local/dynamic/selectors","core/toast"],(function(_exports,_ajax,_notification,_templates,_modal_events,_str,DynamicTable,_fragment,_modal_cancel,_selectors,_toast){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 _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notification","core/templates","core/modal_events","core/str","core_table/dynamic","core/fragment","core/modal_cancel","core_table/local/dynamic/selectors","core/toast","core_form/modalform"],(function(_exports,_ajax,_notification,_templates,_modal_events,_str,DynamicTable,_fragment,_modal_cancel,_selectors,_toast,_modalform){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 _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * Manage rules JS module. * * @module tool_dynamic_cohorts/manage_rules * @copyright 2024 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel),_selectors=_interopRequireDefault(_selectors);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view",SELECTORS_RULE_TOGGLE=".tool-dynamic-cohorts-rule-toggle",SELECTORS_RULE_DELETE=".tool-dynamic-cohorts-rule-delete";_exports.init=()=>{loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),initRuleToggle(document),initRuleDelete(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot),initRuleToggle(tableRoot),initRuleDelete(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))},sendFeedback=action=>{(0,_str.get_string)("completed:"+action,"tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message)})).catch(_notification.default.exception)},getDynamicTableFromLink=link=>link.closest(_selectors.default.main.region),initRuleToggle=root=>{root.querySelectorAll(SELECTORS_RULE_TOGGLE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_toggle_rule_status",args:{ruleid:ruleid},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getDynamicTableFromLink(link)).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleDelete=root=>{root.querySelectorAll(SELECTORS_RULE_DELETE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_delete_rules`",args:{ruleids:{ruleid:ruleid}},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getDynamicTableFromLink(link)).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel),_selectors=_interopRequireDefault(_selectors),_modalform=_interopRequireDefault(_modalform);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view",SELECTORS_RULE_TOGGLE=".tool-dynamic-cohorts-rule-toggle",SELECTORS_RULE_DELETE=".tool-dynamic-cohorts-rule-delete",SELECTORS_RULE_EDIT=".tool-dynamic-cohorts-rule-edit",SELECTORS_RULE_ADD="[data-action=addrule]";_exports.init=()=>{initRuleAdd(),loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),initRuleToggle(document),initRuleDelete(document),initRuleEdit(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot),initRuleToggle(tableRoot),initRuleDelete(tableRoot),initRuleEdit(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))},sendFeedback=action=>{(0,_str.get_string)("completed:"+action,"tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message)})).catch(_notification.default.exception)},sendWarning=()=>{(0,_str.get_string)("ruledisabledpleasereview","tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message,{type:"warning",closeButton:!0,delay:1e4})})).catch(_notification.default.exception)},getTableRoot=()=>document.querySelector(_selectors.default.main.region),initRuleToggle=root=>{root.querySelectorAll(SELECTORS_RULE_TOGGLE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_toggle_rule_status",args:{ruleid:ruleid},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleDelete=root=>{root.querySelectorAll(SELECTORS_RULE_DELETE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_delete_rules`",args:{ruleids:{ruleid:ruleid}},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleAdd=()=>{document.querySelector(SELECTORS_RULE_ADD).addEventListener("click",(e=>{e.preventDefault();const modalForm=getRuleForm(0,"add");modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{sendFeedback("add"),sendWarning(),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)})),modalForm.show()}))},initRuleEdit=root=>{root.querySelectorAll(SELECTORS_RULE_EDIT).forEach((link=>{link.addEventListener("click",(function(e){e.preventDefault();let ruleid=link.dataset.ruleid;const modalForm=getRuleForm(ruleid,"edit");modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{sendFeedback("update"),sendWarning(),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)})),modalForm.show()}))}))},getRuleForm=(ruleid,action)=>new _modalform.default({formClass:"tool_dynamic_cohorts\\rule_form",args:{id:ruleid},modalConfig:{title:(0,_str.get_string)(action+"_rule","tool_dynamic_cohorts")}})})); //# sourceMappingURL=manage_rules.min.js.map \ No newline at end of file diff --git a/amd/build/manage_rules.min.js.map b/amd/build/manage_rules.min.js.map index ef8d21f..e9e87d6 100644 --- a/amd/build/manage_rules.min.js.map +++ b/amd/build/manage_rules.min.js.map @@ -1 +1 @@ -{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\nimport {add as notifyUser} from 'core/toast';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle',\n RULE_DELETE: '.tool-dynamic-cohorts-rule-delete',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n initRuleToggle(document);\n initRuleDelete(document);\n\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n initRuleToggle(tableRoot);\n initRuleDelete(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n\n/**\n * Send feedback to a user.\n *\n * @param {string} action Action to send feedback about.\n */\nconst sendFeedback = (action) => {\n getString('completed:' + action, 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message);\n }).catch(Notification.exception);\n};\n\n/**\n *\n * @param link\n * @returns {*}\n */\nconst getDynamicTableFromLink = (link) => {\n return link.closest(DynamicTableSelectors.main.region);\n};\n\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleToggle = (root) => {\n root.querySelectorAll(SELECTORS.RULE_TOGGLE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_toggle_rule_status',\n args: {ruleid: ruleid},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getDynamicTableFromLink(link))\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleDelete = (root) => {\n root.querySelectorAll(SELECTORS.RULE_DELETE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_delete_rules`',\n args: {ruleids: {ruleid}},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getDynamicTableFromLink(link))\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n"],"names":["SELECTORS","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","initRuleToggle","initRuleDelete","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html","sendFeedback","action","message","catch","Notification","getDynamicTableFromLink","closest","DynamicTableSelectors","main","region","confirm","refreshTableContent","ruleids"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\nimport {add as notifyUser} from 'core/toast';\nimport ModalForm from 'core_form/modalform';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle',\n RULE_DELETE: '.tool-dynamic-cohorts-rule-delete',\n RULE_EDIT: '.tool-dynamic-cohorts-rule-edit',\n RULE_ADD: '[data-action=addrule]',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n initRuleAdd();\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n initRuleToggle(document);\n initRuleDelete(document);\n initRuleEdit(document);\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n initRuleToggle(tableRoot);\n initRuleDelete(tableRoot);\n initRuleEdit(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n\n/**\n * Send feedback to a user.\n *\n * @param {string} action Action to send feedback about.\n */\nconst sendFeedback = (action) => {\n getString('completed:' + action, 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message);\n }).catch(Notification.exception);\n};\n\n/**\n * Send warning to a user.\n */\nconst sendWarning = () => {\n getString('ruledisabledpleasereview', 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message, {type: 'warning', closeButton: true, delay: 10000});\n }).catch(Notification.exception);\n};\n\n/**\n * Get dynamic table root.\n * @returns {*}\n */\nconst getTableRoot = () => {\n return document.querySelector(DynamicTableSelectors.main.region);\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleToggle = (root) => {\n root.querySelectorAll(SELECTORS.RULE_TOGGLE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_toggle_rule_status',\n args: {ruleid: ruleid},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleDelete = (root) => {\n root.querySelectorAll(SELECTORS.RULE_DELETE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_delete_rules`',\n args: {ruleids: {ruleid}},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise action to add a new rule.\n */\nconst initRuleAdd = () => {\n // Add listener to the click event that will load the form.\n document.querySelector(SELECTORS.RULE_ADD).addEventListener('click', (e) => {\n e.preventDefault();\n const modalForm= getRuleForm(0, 'add');\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n sendFeedback('add');\n sendWarning();\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n });\n\n modalForm.show();\n });\n};\n\n/**\n * Initialise action to edit rule in modal form.\n *\n * @param {Element} root\n */\nconst initRuleEdit = (root) => {\n root.querySelectorAll(SELECTORS.RULE_EDIT).forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n let ruleid = link.dataset.ruleid;\n\n const modalForm= getRuleForm(ruleid, 'edit');\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n sendFeedback('update');\n sendWarning();\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n });\n\n modalForm.show();\n });\n });\n};\n\n/**\n * Get rule modal form.\n *\n * @param {string} ruleid\n * @param {string} action\n * @returns {ModalForm}\n */\nconst getRuleForm = (ruleid, action) => {\n return new ModalForm({\n formClass: \"tool_dynamic_cohorts\\\\rule_form\",\n args: {id: ruleid},\n modalConfig: {title: getString(action + '_rule', 'tool_dynamic_cohorts')},\n });\n};\n"],"names":["SELECTORS","initRuleAdd","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","initRuleToggle","initRuleDelete","initRuleEdit","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html","sendFeedback","action","message","catch","Notification","sendWarning","type","closeButton","delay","getTableRoot","querySelector","DynamicTableSelectors","main","region","confirm","refreshTableContent","ruleids","modalForm","getRuleForm","events","FORM_SUBMITTED","ModalForm","formClass","id","modalConfig"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/manage_rules.js b/amd/src/manage_rules.js index 6dc21fb..d206f10 100644 --- a/amd/src/manage_rules.js +++ b/amd/src/manage_rules.js @@ -31,6 +31,7 @@ import Fragment from 'core/fragment'; import ModalCancel from 'core/modal_cancel'; import DynamicTableSelectors from 'core_table/local/dynamic/selectors'; import {add as notifyUser} from 'core/toast'; +import ModalForm from 'core_form/modalform'; /** * A list of used selectors. @@ -40,18 +41,21 @@ const SELECTORS = { RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view', RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle', RULE_DELETE: '.tool-dynamic-cohorts-rule-delete', + RULE_EDIT: '.tool-dynamic-cohorts-rule-edit', + RULE_ADD: '[data-action=addrule]', }; /** * Init of the module. */ export const init = () => { + initRuleAdd(); loadMatchingUsers(document); initMatchingUsersModals(document); initRuleConditionsModals(document); initRuleToggle(document); initRuleDelete(document); - + initRuleEdit(document); document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => { const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid); @@ -61,6 +65,7 @@ export const init = () => { initRuleConditionsModals(tableRoot); initRuleToggle(tableRoot); initRuleDelete(tableRoot); + initRuleEdit(tableRoot); }); }; @@ -192,14 +197,22 @@ const sendFeedback = (action) => { }; /** - * - * @param link - * @returns {*} + * Send warning to a user. */ -const getDynamicTableFromLink = (link) => { - return link.closest(DynamicTableSelectors.main.region); +const sendWarning = () => { + getString('ruledisabledpleasereview', 'tool_dynamic_cohorts') + .then(message => { + notifyUser(message, {type: 'warning', closeButton: true, delay: 10000}); + }).catch(Notification.exception); }; +/** + * Get dynamic table root. + * @returns {*} + */ +const getTableRoot = () => { + return document.querySelector(DynamicTableSelectors.main.region); +}; /** * Initialise displaying each rule conditions in a modal. @@ -223,7 +236,7 @@ const initRuleToggle = (root) => { args: {ruleid: ruleid}, done: function () { sendFeedback(action); - DynamicTable.refreshTableContent(getDynamicTableFromLink(link)) + DynamicTable.refreshTableContent(getTableRoot()) .catch(Notification.exception); }, fail: function (response) { @@ -257,7 +270,7 @@ const initRuleDelete = (root) => { args: {ruleids: {ruleid}}, done: function () { sendFeedback(action); - DynamicTable.refreshTableContent(getDynamicTableFromLink(link)) + DynamicTable.refreshTableContent(getTableRoot()) .catch(Notification.exception); }, fail: function (response) { @@ -268,3 +281,61 @@ const initRuleDelete = (root) => { }); }); }; + +/** + * Initialise action to add a new rule. + */ +const initRuleAdd = () => { + // Add listener to the click event that will load the form. + document.querySelector(SELECTORS.RULE_ADD).addEventListener('click', (e) => { + e.preventDefault(); + const modalForm= getRuleForm(0, 'add'); + modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => { + sendFeedback('add'); + sendWarning(); + DynamicTable.refreshTableContent(getTableRoot()) + .catch(Notification.exception); + }); + + modalForm.show(); + }); +}; + +/** + * Initialise action to edit rule in modal form. + * + * @param {Element} root + */ +const initRuleEdit = (root) => { + root.querySelectorAll(SELECTORS.RULE_EDIT).forEach(link => { + link.addEventListener('click', function(e) { + e.preventDefault(); + let ruleid = link.dataset.ruleid; + + const modalForm= getRuleForm(ruleid, 'edit'); + modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => { + sendFeedback('update'); + sendWarning(); + DynamicTable.refreshTableContent(getTableRoot()) + .catch(Notification.exception); + }); + + modalForm.show(); + }); + }); +}; + +/** + * Get rule modal form. + * + * @param {string} ruleid + * @param {string} action + * @returns {ModalForm} + */ +const getRuleForm = (ruleid, action) => { + return new ModalForm({ + formClass: "tool_dynamic_cohorts\\rule_form", + args: {id: ruleid}, + modalConfig: {title: getString(action + '_rule', 'tool_dynamic_cohorts')}, + }); +}; diff --git a/classes/external/rules.php b/classes/external/rules.php index 6a0fae4..b13a2ca 100644 --- a/classes/external/rules.php +++ b/classes/external/rules.php @@ -22,7 +22,6 @@ use core_external\external_multiple_structure; use core_external\external_value; use core_external\external_single_structure; -use Throwable; use tool_dynamic_cohorts\event\rule_updated; use tool_dynamic_cohorts\rule; use invalid_parameter_exception; @@ -121,7 +120,7 @@ public static function toggle_status(int $ruleid): array { } if ($rule->is_broken()) { - // Disable broken rule + // Disable broken rule. $rule->set('enabled', 0); $rule->save(); rule_updated::create(['other' => ['ruleid' => $rule->get('id')]])->trigger(); diff --git a/classes/reportbuilder/local/systemreports/rules.php b/classes/reportbuilder/local/systemreports/rules.php index 3d6517e..37dd926 100644 --- a/classes/reportbuilder/local/systemreports/rules.php +++ b/classes/reportbuilder/local/systemreports/rules.php @@ -73,7 +73,7 @@ protected function initialise(): void { ->add_callback(static function($id): string { global $OUTPUT; - $url = new moodle_url('/admin/tool/dynamic_cohorts/users.php', ['ruleid' => $id]); + $url = new moodle_url('/admin/tool/dynamic_cohorts/index.php'); return $OUTPUT->render_from_template('tool_dynamic_cohorts/matching_users', [ 'ruleid' => $id, 'url' => $url->out(), @@ -147,7 +147,7 @@ protected function can_view(): bool { */ protected function add_actions(): void { $this->add_action((new action( - new moodle_url('/admin/tool/dynamic_cohorts/toggle.php', ['ruleid' => ':id', 'sesskey' => sesskey()]), + new moodle_url('/admin/tool/dynamic_cohorts/index.php'), new pix_icon('t/hide', '', 'core'), ['class' => 'tool-dynamic-cohorts-rule-toggle', 'data-ruleid' => ':id', 'data-action' => 'enable'], false, @@ -157,7 +157,7 @@ protected function add_actions(): void { })); $this->add_action((new action( - new moodle_url('/admin/tool/dynamic_cohorts/toggle.php', ['ruleid' => ':id', 'sesskey' => sesskey()]), + new moodle_url('/admin/tool/dynamic_cohorts/index.php'), new pix_icon('t/show', '', 'core'), ['class' => 'tool-dynamic-cohorts-rule-toggle', 'data-ruleid' => ':id', 'data-action' => 'disable'], false, @@ -167,15 +167,15 @@ protected function add_actions(): void { })); $this->add_action((new action( - new moodle_url('/admin/tool/dynamic_cohorts/edit.php', ['ruleid' => ':id']), + new moodle_url('/admin/tool/dynamic_cohorts/index.php'), new pix_icon('t/edit', '', 'core'), - [], + ['class' => 'tool-dynamic-cohorts-rule-edit', 'data-ruleid' => ':id'], false, new lang_string('edit') ))); $this->add_action((new action( - new moodle_url('/admin/tool/dynamic_cohorts/delete.php', ['ruleid' => ':id', 'sesskey' => sesskey()]), + new moodle_url('/admin/tool/dynamic_cohorts/index.php'), new pix_icon('t/delete', '', 'core'), ['class' => 'tool-dynamic-cohorts-rule-delete', 'data-ruleid' => ':id', 'data-action' => 'delete'], false, diff --git a/classes/rule_form.php b/classes/rule_form.php index aedbdf1..04b6430 100644 --- a/classes/rule_form.php +++ b/classes/rule_form.php @@ -16,8 +16,13 @@ namespace tool_dynamic_cohorts; +use core_form\dynamic_form; use html_writer; use moodle_url; +use context; +use context_system; +use dml_missing_record_exception; +use stdClass; defined('MOODLE_INTERNAL') || die(); @@ -31,7 +36,7 @@ * @copyright 2024 Catalyst IT * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class rule_form extends \moodleform { +class rule_form extends dynamic_form { /** * Form definition. @@ -47,7 +52,7 @@ protected function definition() { $mform->addElement('text', 'name', get_string('name', 'tool_dynamic_cohorts'), 'size="50"'); $mform->setType('name', PARAM_TEXT); - $mform->addRule('name', get_string('required'), 'required'); + $mform->addRule('name', get_string('required'), 'required', null, 'client'); $mform->addHelpButton('name', 'name', 'tool_dynamic_cohorts'); $mform->addElement( @@ -67,7 +72,7 @@ protected function definition() { ['noselectionstring' => get_string('choosedots')] ); $mform->addHelpButton('cohortid', 'cohortid', 'tool_dynamic_cohorts'); - $mform->addRule('cohortid', get_string('required'), 'required'); + $mform->addRule('cohortid', get_string('required'), 'required', null, 'client'); $link = html_writer::link(new moodle_url('/cohort/index.php'), get_string('managecohorts', 'tool_dynamic_cohorts')); $mform->addElement('static', '', '', $link); @@ -87,8 +92,13 @@ protected function definition() { } $group = []; - $group[] = $mform->createElement('select', 'condition', '', $conditions); - $group[] = $mform->createElement('button', 'conditionmodalbutton', get_string('addcondition', 'tool_dynamic_cohorts')); + $group[] = $mform->createElement('select', 'condition', '', $conditions, ['id' => 'id_condition']); + $group[] = $mform->createElement( + 'button', + 'conditionmodalbutton', + get_string('addcondition', 'tool_dynamic_cohorts'), + ['id' => 'id_conditionmodalbutton'] + ); $mform->addGroup($group, 'conditiongroup', get_string('condition', 'tool_dynamic_cohorts'), ' ', false); $mform->addElement( @@ -128,7 +138,8 @@ protected function definition() { $mform->addHelpButton('operator', 'logical_operator', 'tool_dynamic_cohorts'); $mform->setType('operator', PARAM_INT); - $this->add_action_buttons(); + // Dummy element to be able to add conditions table in definition_after_data. + $mform->addElement('static', 'afterconditions', '', ''); } /** @@ -145,19 +156,102 @@ protected function get_cohort_options(): array { } // Add the currently selected cohort as it won't be in the list. - if (isset($this->_customdata['defaultcohort'])) { - $cohort = $this->_customdata['defaultcohort']; + $cohort = $this->get_default_cohort(); + if (!empty($cohort)) { $options[$cohort->id] = $cohort->name; } return $options; } + /** + * Gets default cohort to be set into the form. + * + * @return stdClass|null + */ + protected function get_default_cohort(): ?stdClass { + global $DB; + + $rule = $this->get_rule(); + + if (!empty($rule->get('cohortid'))) { + return $DB->get_record('cohort', ['id' => $rule->get('cohortid')]); + } else { + return null; + } + } + + /** + * Gets rule based on form data. + * + * @return rule + */ + protected function get_rule(): rule { + $ruleid = isset($this->_ajaxformdata['id']) ? (int)$this->_ajaxformdata['id'] : 0; + + if (!empty($ruleid)) { + $rule = rule::get_record(['id' => $ruleid]); + if (empty($rule)) { + throw new dml_missing_record_exception(null); + } + return $rule; + } else { + return new rule(); + } + } + + /** + * Form context. + * + * @return context + */ + protected function get_context_for_dynamic_submission(): context { + return context_system::instance(); + } + + /** + * Access control. + * + * @return void + */ + protected function check_access_for_dynamic_submission(): void { + require_capability('tool/dynamic_cohorts:manage', $this->get_context_for_dynamic_submission()); + } + + /** + * Process form submission. + * + * @return void + */ + public function process_dynamic_submission() { + rule_manager::process_form($this->get_data()); + } + + /** + * Set data. + * + * @return void + */ + public function set_data_for_dynamic_submission(): void { + $this->set_data(rule_manager::build_data_for_form($this->get_rule())); + } + + /** + * Form URL + * + * @return moodle_url + */ + protected function get_page_url_for_dynamic_submission(): moodle_url { + return new moodle_url('/admin/tool/dynamic_cohorts/index.php'); + } + /** * Definition after data is set. */ public function definition_after_data() { - global $OUTPUT; + global $OUTPUT, $PAGE; + + $PAGE->requires->js_call_amd('tool_dynamic_cohorts/condition_form', 'init'); $mform = $this->_form; $conditionjson = $mform->getElementValue('conditionjson'); @@ -170,7 +264,7 @@ public function definition_after_data() { 'html', '
' . $conditions . '
' ), - 'buttonar' + 'afterconditions' ); } } diff --git a/classes/rule_manager.php b/classes/rule_manager.php index cc6609f..470d487 100644 --- a/classes/rule_manager.php +++ b/classes/rule_manager.php @@ -103,7 +103,6 @@ public static function build_data_for_form(rule $rule): array { ['description' => $description] + ['name' => $name] + ['broken' => $broken]; - ; } if (!empty($conditions)) { @@ -264,9 +263,6 @@ public static function get_matching_users(rule $rule, ?int $userid = null): arra public static function get_matching_users_count(rule $rule, ?int $userid = null): int { global $DB; - // TODO: add caching as we would need to return users count on each page refresh. - // Cache should be rebuilt on every rule change for a specific rule. - $conditions = $rule->get_condition_records(); if (empty($conditions)) { diff --git a/delete.php b/delete.php deleted file mode 100644 index caf1fc7..0000000 --- a/delete.php +++ /dev/null @@ -1,55 +0,0 @@ -. - -/** - * Delete action page. - * - * @package tool_dynamic_cohorts - * @copyright 2024 Catalyst IT - * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use tool_dynamic_cohorts\rule; -use tool_dynamic_cohorts\rule_manager; -use core\output\notification; - -require_once(__DIR__ . '/../../../config.php'); -require_once($CFG->libdir . '/adminlib.php'); -require_once($CFG->libdir . '/formslib.php'); - -admin_externalpage_setup('tool_dynamic_cohorts_rules'); - -$ruleid = required_param('ruleid', PARAM_INT); -$confirm = optional_param('confirm', '', PARAM_ALPHANUM); - -$rule = rule::get_record(['id' => $ruleid], MUST_EXIST); -$manageurl = new moodle_url('/admin/tool/dynamic_cohorts/index.php'); - -if ($confirm != md5($ruleid)) { - $confirmstring = get_string('delete_confirm', 'tool_dynamic_cohorts', $rule->get('name')); - $cinfirmoptions = ['ruleid' => $ruleid, 'confirm' => md5($ruleid), 'sesskey' => sesskey()]; - $deleteurl = new moodle_url('/admin/tool/dynamic_cohorts/delete.php', $cinfirmoptions); - - $PAGE->navbar->add(get_string('delete_rule', 'tool_dynamic_cohorts')); - - echo $OUTPUT->header(); - echo $OUTPUT->confirm($confirmstring, $deleteurl, $manageurl); - echo $OUTPUT->footer(); - -} else if (data_submitted() && confirm_sesskey()) { - rule_manager::delete_rule($rule); - redirect($manageurl, get_string('ruledeleted', 'tool_dynamic_cohorts'), null, notification::NOTIFY_SUCCESS); -} diff --git a/edit.php b/edit.php deleted file mode 100644 index 901f5bc..0000000 --- a/edit.php +++ /dev/null @@ -1,75 +0,0 @@ -. - -/** - * Rules edit page. - * - * @package tool_dynamic_cohorts - * @copyright 2024 Catalyst IT - * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use core\notification; -use tool_dynamic_cohorts\rule; -use tool_dynamic_cohorts\rule_form; -use tool_dynamic_cohorts\rule_manager; - -require_once(__DIR__ . '/../../../config.php'); -require_once($CFG->libdir . '/adminlib.php'); - -$ruleid = optional_param('ruleid', 0, PARAM_INT); -$action = !empty($ruleid) ? 'edit' : 'add'; - -admin_externalpage_setup('tool_dynamic_cohorts_rules'); - -$manageurl = new moodle_url('/admin/tool/dynamic_cohorts/index.php'); -$editurl = new moodle_url('/admin/tool/dynamic_cohorts/edit.php'); -$header = get_string($action . '_rule', 'tool_dynamic_cohorts'); -$PAGE->navbar->add($header); - - -if (!empty($ruleid)) { - $rule = rule::get_record(['id' => $ruleid]); - if (empty($rule)) { - throw new dml_missing_record_exception(null); - } else { - $defaultcohort = $DB->get_record('cohort', ['id' => $rule->get('cohortid')]); - $mform = new rule_form(rule_manager::build_edit_url($rule)->out(), ['defaultcohort' => $defaultcohort ?: null]); - $mform->set_data(rule_manager::build_data_for_form($rule)); - } -} else { - $mform = new rule_form(); -} - -if ($mform->is_cancelled()) { - redirect($manageurl); -} else if ($formdata = $mform->get_data()) { - try { - rule_manager::process_form($formdata); - notification::success(get_string('changessaved')); - notification::warning(get_string('ruledisabledpleasereview', 'tool_dynamic_cohorts')); - } catch (Exception $e) { - notification::error($e->getMessage()); - } - redirect($manageurl); -} - -$PAGE->requires->js_call_amd('tool_dynamic_cohorts/condition_form', 'init'); - -echo $OUTPUT->header(); -echo $OUTPUT->heading($header); -$mform->display(); -echo $OUTPUT->footer(); diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index 766a03b..99ec4ae 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -42,9 +42,11 @@ $string['cohortid'] = 'Cohort'; $string['cohortswith'] = 'Cohort(s) with field'; $string['cohortid_help'] = 'A cohort to manage as part of this rule. Only cohorts that are not managed by other plugins are displayed in this list.'; +$string['completed:add'] = 'Rule has been added'; $string['completed:delete'] = 'Rule has been deleted'; $string['completed:enable'] = 'Rule has been enabled'; $string['completed:disable'] = 'Rule has been disabled'; +$string['completed:update'] = 'Rule has been updated'; $string['completiondate'] = 'Completion date'; $string['completionisdisabled'] = 'Completion is disabled for configured course'; $string['condition'] = 'Condition'; diff --git a/templates/button.mustache b/templates/button.mustache index 170e480..02bcafb 100644 --- a/templates/button.mustache +++ b/templates/button.mustache @@ -36,6 +36,6 @@ } }} - + {{text}} diff --git a/toggle.php b/toggle.php deleted file mode 100644 index c02025d..0000000 --- a/toggle.php +++ /dev/null @@ -1,74 +0,0 @@ -. - -/** - * Toggle action page. - * - * @package tool_dynamic_cohorts - * @copyright 2024 Catalyst IT - * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use core\output\notification; -use tool_dynamic_cohorts\rule; -use tool_dynamic_cohorts\event\rule_updated; - -require_once(__DIR__ . '/../../../config.php'); -require_once($CFG->libdir . '/adminlib.php'); -require_once($CFG->libdir . '/formslib.php'); - -admin_externalpage_setup('tool_dynamic_cohorts_rules'); - -$ruleid = required_param('ruleid', PARAM_INT); -$confirm = optional_param('confirm', '', PARAM_ALPHANUM); - -$rule = rule::get_record(['id' => $ruleid], MUST_EXIST); -$manageurl = new moodle_url('/admin/tool/dynamic_cohorts/index.php'); - -if (!$rule->is_broken()) { - $identificator = $rule->is_enabled() ? 'ruledisabled' : 'ruleenabled'; - $action = $rule->is_enabled() ? 'disable' : 'enable'; - $message = get_string($identificator, 'tool_dynamic_cohorts'); - $newvalue = (int) !$rule->is_enabled(); - $messagetype = notification::NOTIFY_SUCCESS; - - if ($confirm != md5($ruleid)) { - $confirmstring = get_string($action . '_confirm', 'tool_dynamic_cohorts', $rule->get('name')); - $cinfirmoptions = ['ruleid' => $ruleid, 'confirm' => md5($ruleid), 'sesskey' => sesskey()]; - $deleteurl = new moodle_url('/admin/tool/dynamic_cohorts/toggle.php', $cinfirmoptions); - - $PAGE->navbar->add(get_string('delete_rule', 'tool_dynamic_cohorts')); - - echo $OUTPUT->header(); - echo $OUTPUT->confirm($confirmstring, $deleteurl, $manageurl); - echo $OUTPUT->footer(); - - } else if (data_submitted() && confirm_sesskey()) { - $rule->set('enabled', $newvalue); - $rule->save(); - rule_updated::create(['other' => ['ruleid' => $rule->get('id')]])->trigger(); - redirect($manageurl, $message, null, $messagetype); - } -} else { - $newvalue = 0; - $message = get_string('cannotenablebrokenrule', 'tool_dynamic_cohorts'); - $messagetype = notification::NOTIFY_ERROR; - - $rule->set('enabled', $newvalue); - $rule->save(); - rule_updated::create(['other' => ['ruleid' => $rule->get('id')]])->trigger(); - redirect($manageurl, $message, null, $messagetype); -} diff --git a/users.php b/users.php deleted file mode 100644 index 85d8df2..0000000 --- a/users.php +++ /dev/null @@ -1,67 +0,0 @@ -. - -/** - * List of users matching a rule. - * - * @package tool_dynamic_cohorts - * @copyright 2024 Catalyst IT - * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use tool_dynamic_cohorts\rule; -use tool_dynamic_cohorts\cohort_manager; -use core_reportbuilder\system_report_factory; -use tool_dynamic_cohorts\reportbuilder\local\systemreports\matching_users; - -require_once(__DIR__.'/../../../config.php'); -require_once($CFG->libdir.'/adminlib.php'); - -$ruleid = required_param('ruleid', PARAM_INT); -$download = optional_param('download', '', PARAM_ALPHA); - -admin_externalpage_setup('tool_dynamic_cohorts_rules'); - -$rule = rule::get_record(['id' => $ruleid]); -if (empty($rule)) { - throw new dml_missing_record_exception(null); -} - -$report = system_report_factory::create( - matching_users::class, - context_system::instance(), - 'tool_dynamic_cohorts', - '', - 0, - ['ruleid' => $ruleid] -); - -$heading = get_string('usersforrule', 'tool_dynamic_cohorts', [ - 'rule' => $rule->get('name'), - 'cohort' => cohort_manager::get_cohorts()[$rule->get('cohortid')]->name, -]); -$PAGE->navbar->add($heading); - -$indexurl = new moodle_url('/admin/tool/dynamic_cohorts/index.php'); - -echo $OUTPUT->header(); -echo $OUTPUT->heading($heading); -echo $OUTPUT->render_from_template('tool_dynamic_cohorts/button', [ - 'url' => $indexurl->out(), - 'text' => get_string('backtolistofrules', 'tool_dynamic_cohorts'), -]); -echo $report->output(); -echo $OUTPUT->footer(); From b7f4845bbb23e8c76e4ceb9aff46d87e553474ef Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Sat, 22 Feb 2025 09:49:14 +1100 Subject: [PATCH 6/7] issue #116: clean up strings --- amd/build/manage_rules.min.js | 2 +- amd/build/manage_rules.min.js.map | 2 +- amd/src/manage_rules.js | 2 +- lang/en/tool_dynamic_cohorts.php | 7 +++---- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/amd/build/manage_rules.min.js b/amd/build/manage_rules.min.js index 6b8f469..c182da5 100644 --- a/amd/build/manage_rules.min.js +++ b/amd/build/manage_rules.min.js @@ -5,6 +5,6 @@ define("tool_dynamic_cohorts/manage_rules",["exports","core/ajax","core/notifica * @module tool_dynamic_cohorts/manage_rules * @copyright 2024 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel),_selectors=_interopRequireDefault(_selectors),_modalform=_interopRequireDefault(_modalform);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view",SELECTORS_RULE_TOGGLE=".tool-dynamic-cohorts-rule-toggle",SELECTORS_RULE_DELETE=".tool-dynamic-cohorts-rule-delete",SELECTORS_RULE_EDIT=".tool-dynamic-cohorts-rule-edit",SELECTORS_RULE_ADD="[data-action=addrule]";_exports.init=()=>{initRuleAdd(),loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),initRuleToggle(document),initRuleDelete(document),initRuleEdit(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot),initRuleToggle(tableRoot),initRuleDelete(tableRoot),initRuleEdit(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))},sendFeedback=action=>{(0,_str.get_string)("completed:"+action,"tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message)})).catch(_notification.default.exception)},sendWarning=()=>{(0,_str.get_string)("ruledisabledpleasereview","tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message,{type:"warning",closeButton:!0,delay:1e4})})).catch(_notification.default.exception)},getTableRoot=()=>document.querySelector(_selectors.default.main.region),initRuleToggle=root=>{root.querySelectorAll(SELECTORS_RULE_TOGGLE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_toggle_rule_status",args:{ruleid:ruleid},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleDelete=root=>{root.querySelectorAll(SELECTORS_RULE_DELETE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_delete_rules`",args:{ruleids:{ruleid:ruleid}},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleAdd=()=>{document.querySelector(SELECTORS_RULE_ADD).addEventListener("click",(e=>{e.preventDefault();const modalForm=getRuleForm(0,"add");modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{sendFeedback("add"),sendWarning(),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)})),modalForm.show()}))},initRuleEdit=root=>{root.querySelectorAll(SELECTORS_RULE_EDIT).forEach((link=>{link.addEventListener("click",(function(e){e.preventDefault();let ruleid=link.dataset.ruleid;const modalForm=getRuleForm(ruleid,"edit");modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{sendFeedback("update"),sendWarning(),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)})),modalForm.show()}))}))},getRuleForm=(ruleid,action)=>new _modalform.default({formClass:"tool_dynamic_cohorts\\rule_form",args:{id:ruleid},modalConfig:{title:(0,_str.get_string)(action+"_rule","tool_dynamic_cohorts")}})})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),DynamicTable=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(DynamicTable),_fragment=_interopRequireDefault(_fragment),_modal_cancel=_interopRequireDefault(_modal_cancel),_selectors=_interopRequireDefault(_selectors),_modalform=_interopRequireDefault(_modalform);const SELECTORS_RULE_MATCHING_USERS="tool-dynamic-cohorts-matching-users",SELECTORS_RULE_CONDITIONS=".tool-dynamic-cohorts-condition-view",SELECTORS_RULE_TOGGLE=".tool-dynamic-cohorts-rule-toggle",SELECTORS_RULE_DELETE=".tool-dynamic-cohorts-rule-delete",SELECTORS_RULE_EDIT=".tool-dynamic-cohorts-rule-edit",SELECTORS_RULE_ADD="[data-action=addrule]";_exports.init=()=>{initRuleAdd(),loadMatchingUsers(document),initMatchingUsersModals(document),initRuleConditionsModals(document),initRuleToggle(document),initRuleDelete(document),initRuleEdit(document),document.addEventListener(DynamicTable.Events.tableContentRefreshed,(e=>{const tableRoot=DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);initMatchingUsersModals(tableRoot),loadMatchingUsers(tableRoot),initRuleConditionsModals(tableRoot),initRuleToggle(tableRoot),initRuleDelete(tableRoot),initRuleEdit(tableRoot)}))};const initMatchingUsersModals=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid;collection.children[1].addEventListener("click",(function(e){e.preventDefault(),displayMatchingUsers(ruleid)}))}))},displayMatchingUsers=ruleid=>{_modal_cancel.default.create({title:(0,_str.get_string)("matchingusers","tool_dynamic_cohorts"),body:getMatchingUsersModalBody(ruleid),large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))},getMatchingUsersModalBody=ruleid=>{const params={ruleid:ruleid};return _fragment.default.loadFragment("tool_dynamic_cohorts","matching_users",1,params)},loadMatchingUsers=root=>{Array.from(root.getElementsByClassName(SELECTORS_RULE_MATCHING_USERS)).forEach((collection=>{const ruleid=collection.dataset.ruleid,loader=collection.children[0],link=collection.children[1];_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_total_matching_users_for_rule",args:{ruleid:ruleid},done:function(number){link.children[0].append(number.toLocaleString().replace(/,/g," ")),loader.classList.add("hidden"),link.classList.remove("hidden")},fail:function(response){_notification.default.exception(response)}}])}))},initRuleConditionsModals=root=>{root.querySelectorAll(SELECTORS_RULE_CONDITIONS).forEach((link=>{let ruleid=link.dataset.ruleid;link.addEventListener("click",(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_get_conditions",args:{ruleid:ruleid},done:function(conditions){_templates.default.render("tool_dynamic_cohorts/conditions",{conditions:conditions,hidecontrols:!0}).then((function(html){_modal_cancel.default.create({title:(0,_str.get_string)("conditionsformtitle","tool_dynamic_cohorts"),body:html,large:!0}).then((function(modal){modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal.show()}))})).fail((function(response){_notification.default.exception(response)}))},fail:function(response){_notification.default.exception(response)}}])}))}))},sendFeedback=action=>{(0,_str.get_string)("completed:"+action,"tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message)})).catch(_notification.default.exception)},sendWarning=()=>{(0,_str.get_string)("ruledisabledpleasereview","tool_dynamic_cohorts").then((message=>{(0,_toast.add)(message,{type:"warning",closeButton:!0,delay:1e4})})).catch(_notification.default.exception)},getTableRoot=()=>document.querySelector(_selectors.default.main.region),initRuleToggle=root=>{root.querySelectorAll(SELECTORS_RULE_TOGGLE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts"),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_toggle_rule_status",args:{ruleid:ruleid},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleDelete=root=>{root.querySelectorAll(SELECTORS_RULE_DELETE).forEach((link=>{let ruleid=link.dataset.ruleid,action=link.dataset.action;link.addEventListener("click",(function(e){e.preventDefault(),_notification.default.confirm((0,_str.get_string)("confirm","moodle"),(0,_str.get_string)(action+"_confirm","tool_dynamic_cohorts",ruleid),(0,_str.get_string)("yes","moodle"),(0,_str.get_string)("no","moodle"),(function(){_ajax.default.call([{methodname:"tool_dynamic_cohorts_delete_rules`",args:{ruleids:{ruleid:ruleid}},done:function(){sendFeedback(action),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)},fail:function(response){_notification.default.exception(response)}}])}))}))}))},initRuleAdd=()=>{document.querySelector(SELECTORS_RULE_ADD).addEventListener("click",(e=>{e.preventDefault();const modalForm=getRuleForm(0,"add");modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{sendFeedback("add"),sendWarning(),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)})),modalForm.show()}))},initRuleEdit=root=>{root.querySelectorAll(SELECTORS_RULE_EDIT).forEach((link=>{link.addEventListener("click",(function(e){e.preventDefault();let ruleid=link.dataset.ruleid;const modalForm=getRuleForm(ruleid,"edit");modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(()=>{sendFeedback("update"),sendWarning(),DynamicTable.refreshTableContent(getTableRoot()).catch(_notification.default.exception)})),modalForm.show()}))}))},getRuleForm=(ruleid,action)=>new _modalform.default({formClass:"tool_dynamic_cohorts\\rule_form",args:{id:ruleid},modalConfig:{title:(0,_str.get_string)(action+"_rule","tool_dynamic_cohorts")}})})); //# sourceMappingURL=manage_rules.min.js.map \ No newline at end of file diff --git a/amd/build/manage_rules.min.js.map b/amd/build/manage_rules.min.js.map index e9e87d6..ed8ccc6 100644 --- a/amd/build/manage_rules.min.js.map +++ b/amd/build/manage_rules.min.js.map @@ -1 +1 @@ -{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\nimport {add as notifyUser} from 'core/toast';\nimport ModalForm from 'core_form/modalform';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle',\n RULE_DELETE: '.tool-dynamic-cohorts-rule-delete',\n RULE_EDIT: '.tool-dynamic-cohorts-rule-edit',\n RULE_ADD: '[data-action=addrule]',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n initRuleAdd();\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n initRuleToggle(document);\n initRuleDelete(document);\n initRuleEdit(document);\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n initRuleToggle(tableRoot);\n initRuleDelete(tableRoot);\n initRuleEdit(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n\n/**\n * Send feedback to a user.\n *\n * @param {string} action Action to send feedback about.\n */\nconst sendFeedback = (action) => {\n getString('completed:' + action, 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message);\n }).catch(Notification.exception);\n};\n\n/**\n * Send warning to a user.\n */\nconst sendWarning = () => {\n getString('ruledisabledpleasereview', 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message, {type: 'warning', closeButton: true, delay: 10000});\n }).catch(Notification.exception);\n};\n\n/**\n * Get dynamic table root.\n * @returns {*}\n */\nconst getTableRoot = () => {\n return document.querySelector(DynamicTableSelectors.main.region);\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleToggle = (root) => {\n root.querySelectorAll(SELECTORS.RULE_TOGGLE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_toggle_rule_status',\n args: {ruleid: ruleid},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleDelete = (root) => {\n root.querySelectorAll(SELECTORS.RULE_DELETE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_delete_rules`',\n args: {ruleids: {ruleid}},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise action to add a new rule.\n */\nconst initRuleAdd = () => {\n // Add listener to the click event that will load the form.\n document.querySelector(SELECTORS.RULE_ADD).addEventListener('click', (e) => {\n e.preventDefault();\n const modalForm= getRuleForm(0, 'add');\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n sendFeedback('add');\n sendWarning();\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n });\n\n modalForm.show();\n });\n};\n\n/**\n * Initialise action to edit rule in modal form.\n *\n * @param {Element} root\n */\nconst initRuleEdit = (root) => {\n root.querySelectorAll(SELECTORS.RULE_EDIT).forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n let ruleid = link.dataset.ruleid;\n\n const modalForm= getRuleForm(ruleid, 'edit');\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n sendFeedback('update');\n sendWarning();\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n });\n\n modalForm.show();\n });\n });\n};\n\n/**\n * Get rule modal form.\n *\n * @param {string} ruleid\n * @param {string} action\n * @returns {ModalForm}\n */\nconst getRuleForm = (ruleid, action) => {\n return new ModalForm({\n formClass: \"tool_dynamic_cohorts\\\\rule_form\",\n args: {id: ruleid},\n modalConfig: {title: getString(action + '_rule', 'tool_dynamic_cohorts')},\n });\n};\n"],"names":["SELECTORS","initRuleAdd","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","initRuleToggle","initRuleDelete","initRuleEdit","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html","sendFeedback","action","message","catch","Notification","sendWarning","type","closeButton","delay","getTableRoot","querySelector","DynamicTableSelectors","main","region","confirm","refreshTableContent","ruleids","modalForm","getRuleForm","events","FORM_SUBMITTED","ModalForm","formClass","id","modalConfig"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"manage_rules.min.js","sources":["../src/manage_rules.js"],"sourcesContent":["// This file is part of Moodle - https://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 * Manage rules JS module.\n *\n * @module tool_dynamic_cohorts/manage_rules\n * @copyright 2024 Catalyst IT\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport ModalEvents from 'core/modal_events';\nimport {get_string as getString} from 'core/str';\nimport * as DynamicTable from 'core_table/dynamic';\nimport Fragment from 'core/fragment';\nimport ModalCancel from 'core/modal_cancel';\nimport DynamicTableSelectors from 'core_table/local/dynamic/selectors';\nimport {add as notifyUser} from 'core/toast';\nimport ModalForm from 'core_form/modalform';\n\n/**\n * A list of used selectors.\n */\nconst SELECTORS = {\n RULE_MATCHING_USERS: 'tool-dynamic-cohorts-matching-users',\n RULE_CONDITIONS: '.tool-dynamic-cohorts-condition-view',\n RULE_TOGGLE: '.tool-dynamic-cohorts-rule-toggle',\n RULE_DELETE: '.tool-dynamic-cohorts-rule-delete',\n RULE_EDIT: '.tool-dynamic-cohorts-rule-edit',\n RULE_ADD: '[data-action=addrule]',\n};\n\n/**\n * Init of the module.\n */\nexport const init = () => {\n initRuleAdd();\n loadMatchingUsers(document);\n initMatchingUsersModals(document);\n initRuleConditionsModals(document);\n initRuleToggle(document);\n initRuleDelete(document);\n initRuleEdit(document);\n\n document.addEventListener(DynamicTable.Events.tableContentRefreshed, e => {\n const tableRoot = DynamicTable.getTableFromId(e.target.dataset.tableUniqueid);\n\n initMatchingUsersModals(tableRoot);\n loadMatchingUsers(tableRoot);\n initRuleConditionsModals(tableRoot);\n initRuleToggle(tableRoot);\n initRuleDelete(tableRoot);\n initRuleEdit(tableRoot);\n });\n};\n\n/**\n * Initialise modals for matching users.\n *\n * @param {Element} root\n */\nconst initMatchingUsersModals = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const link = collection.children[1];\n link.addEventListener('click', function(e) {\n e.preventDefault();\n displayMatchingUsers(ruleid);\n });\n });\n};\n\n/**\n * Display matching users in the modal form.\n *\n * @param {string} ruleid\n */\nconst displayMatchingUsers = (ruleid) => {\n\n ModalCancel.create({\n title: getString('matchingusers', 'tool_dynamic_cohorts'),\n body: getMatchingUsersModalBody(ruleid),\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n\n modal.show();\n });\n};\n\n/**\n * Get modal html body for matching users using fragment API.\n *\n * @param {string} ruleid\n * @returns {Promise}\n */\nconst getMatchingUsersModalBody = (ruleid) => {\n const params = {\n ruleid: ruleid,\n };\n\n return Fragment.loadFragment('tool_dynamic_cohorts', 'matching_users', 1, params);\n};\n\n/**\n * Load matching users for each rule.\n *\n * @param {Element} root\n */\nconst loadMatchingUsers = (root) => {\n Array.from(root.getElementsByClassName(SELECTORS.RULE_MATCHING_USERS)).forEach((collection) => {\n const ruleid = collection.dataset.ruleid;\n const loader = collection.children[0];\n const link = collection.children[1];\n\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_total_matching_users_for_rule',\n args: {ruleid: ruleid},\n done: function (number) {\n link.children[0].append(number.toLocaleString().replace(/,/g, \" \"));\n loader.classList.add('hidden');\n link.classList.remove('hidden');\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleConditionsModals = (root) => {\n root.querySelectorAll(SELECTORS.RULE_CONDITIONS).forEach(link => {\n let ruleid = link.dataset.ruleid;\n link.addEventListener('click', function() {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_get_conditions',\n args: {ruleid: ruleid},\n done: function (conditions) {\n Templates.render(\n 'tool_dynamic_cohorts/conditions',\n {'conditions' : conditions, 'hidecontrols': true}\n ).then(function(html) {\n ModalCancel.create({\n title: getString('conditionsformtitle', 'tool_dynamic_cohorts'),\n body: html,\n large: true,\n }).then(function (modal) {\n modal.getRoot().on(ModalEvents.hidden, function() {\n modal.destroy();\n });\n modal.show();\n });\n }).fail(function(response) {\n Notification.exception(response);\n });\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n};\n\n/**\n * Send feedback to a user.\n *\n * @param {string} action Action to send feedback about.\n */\nconst sendFeedback = (action) => {\n getString('completed:' + action, 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message);\n }).catch(Notification.exception);\n};\n\n/**\n * Send warning to a user.\n */\nconst sendWarning = () => {\n getString('ruledisabledpleasereview', 'tool_dynamic_cohorts')\n .then(message => {\n notifyUser(message, {type: 'warning', closeButton: true, delay: 10000});\n }).catch(Notification.exception);\n};\n\n/**\n * Get dynamic table root.\n * @returns {*}\n */\nconst getTableRoot = () => {\n return document.querySelector(DynamicTableSelectors.main.region);\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleToggle = (root) => {\n root.querySelectorAll(SELECTORS.RULE_TOGGLE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts'),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_toggle_rule_status',\n args: {ruleid: ruleid},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise displaying each rule conditions in a modal.\n *\n * @param {Element} root\n */\nconst initRuleDelete = (root) => {\n root.querySelectorAll(SELECTORS.RULE_DELETE).forEach(link => {\n let ruleid = link.dataset.ruleid;\n let action = link.dataset.action;\n link.addEventListener('click', function(e) {\n e.preventDefault();\n Notification.confirm(\n getString('confirm', 'moodle'),\n getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid),\n getString('yes', 'moodle'),\n getString('no', 'moodle'),\n function () {\n Ajax.call([{\n methodname: 'tool_dynamic_cohorts_delete_rules`',\n args: {ruleids: {ruleid}},\n done: function () {\n sendFeedback(action);\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n },\n fail: function (response) {\n Notification.exception(response);\n }\n }]);\n });\n });\n });\n};\n\n/**\n * Initialise action to add a new rule.\n */\nconst initRuleAdd = () => {\n // Add listener to the click event that will load the form.\n document.querySelector(SELECTORS.RULE_ADD).addEventListener('click', (e) => {\n e.preventDefault();\n const modalForm= getRuleForm(0, 'add');\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n sendFeedback('add');\n sendWarning();\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n });\n\n modalForm.show();\n });\n};\n\n/**\n * Initialise action to edit rule in modal form.\n *\n * @param {Element} root\n */\nconst initRuleEdit = (root) => {\n root.querySelectorAll(SELECTORS.RULE_EDIT).forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n let ruleid = link.dataset.ruleid;\n\n const modalForm= getRuleForm(ruleid, 'edit');\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, () => {\n sendFeedback('update');\n sendWarning();\n DynamicTable.refreshTableContent(getTableRoot())\n .catch(Notification.exception);\n });\n\n modalForm.show();\n });\n });\n};\n\n/**\n * Get rule modal form.\n *\n * @param {string} ruleid\n * @param {string} action\n * @returns {ModalForm}\n */\nconst getRuleForm = (ruleid, action) => {\n return new ModalForm({\n formClass: \"tool_dynamic_cohorts\\\\rule_form\",\n args: {id: ruleid},\n modalConfig: {title: getString(action + '_rule', 'tool_dynamic_cohorts')},\n });\n};\n"],"names":["SELECTORS","initRuleAdd","loadMatchingUsers","document","initMatchingUsersModals","initRuleConditionsModals","initRuleToggle","initRuleDelete","initRuleEdit","addEventListener","DynamicTable","Events","tableContentRefreshed","e","tableRoot","getTableFromId","target","dataset","tableUniqueid","root","Array","from","getElementsByClassName","forEach","collection","ruleid","children","preventDefault","displayMatchingUsers","create","title","body","getMatchingUsersModalBody","large","then","modal","getRoot","on","ModalEvents","hidden","destroy","show","params","Fragment","loadFragment","loader","link","call","methodname","args","done","number","append","toLocaleString","replace","classList","add","remove","fail","response","exception","querySelectorAll","conditions","render","html","sendFeedback","action","message","catch","Notification","sendWarning","type","closeButton","delay","getTableRoot","querySelector","DynamicTableSelectors","main","region","confirm","refreshTableContent","ruleids","modalForm","getRuleForm","events","FORM_SUBMITTED","ModalForm","formClass","id","modalConfig"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/manage_rules.js b/amd/src/manage_rules.js index d206f10..6342842 100644 --- a/amd/src/manage_rules.js +++ b/amd/src/manage_rules.js @@ -227,7 +227,7 @@ const initRuleToggle = (root) => { e.preventDefault(); Notification.confirm( getString('confirm', 'moodle'), - getString(action + '_confirm', 'tool_dynamic_cohorts', ruleid), + getString(action + '_confirm', 'tool_dynamic_cohorts'), getString('yes', 'moodle'), getString('no', 'moodle'), function () { diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index 99ec4ae..46abb47 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -30,7 +30,6 @@ $string['add_rule'] = 'Add new rule'; $string['after'] = 'After'; $string['any'] = 'Any'; -$string['backtolistofrules'] = 'Back to the list of rules'; $string['before'] = 'Before'; $string['broken'] = 'Broken'; $string['brokenruleswarning'] = 'There are some broken rules require your attention.
To fix a broken rule you should remove all broken conditions.
Sometimes a rule becomes broken when matching users SQL failed. In this case all condition are ok, but the rule is marked as broken. You should check Moodle logs for "Matching users failed" event and related SQL errors.
Please note, that in any case you have to re-save the rule to mark it as unbroken.'; @@ -79,17 +78,17 @@ $string['cf_include_missing_data'] = 'Include cohorts with missing data.'; $string['cf_include_missing_data_help'] = 'Cohorts may not have a custom field data set yet. This option includes those cohorts in the final result.'; $string['cf_includingmissingdatadesc'] = '(including cohorts with missing data)'; -$string['delete_confirm'] = 'Are you sure you want to delete rule {$a}?'; +$string['delete_confirm'] = 'Are you sure you want to delete rule?'; $string['delete_confirm_condition'] = 'Are you sure you want to delete this condition?'; $string['delete_rule'] = 'Delete rule'; $string['description'] = 'Description'; $string['description_help'] = 'As short description of this rule'; $string['disabled'] = 'Disabled'; -$string['disable_confirm'] = 'Are you sure you want to disable rule {$a}?'; +$string['disable_confirm'] = 'Are you sure you want to disable rule?'; $string['dynamic_cohorts:manage'] = 'Manage rules'; $string['edit_rule'] = 'Edit rule'; $string['enabled'] = 'Enabled'; -$string['enable_confirm'] = 'Are you sure you want to enable rule {$a}?'; +$string['enable_confirm'] = 'Are you sure you want to enable rule?'; $string['enrolmethod'] = 'Enrolment method'; $string['enrolled'] = 'Enrolled'; $string['ever'] = 'Ever'; From 055d6731fdf7e41be1a2065169253afdfca5f041 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Sat, 22 Feb 2025 16:04:00 +1100 Subject: [PATCH 7/7] issue #130: add caching of the list of matching users --- classes/rule.php | 1 + classes/rule_manager.php | 29 ++++++++++++++++++++++++----- db/caches.php | 5 +++++ lang/en/tool_dynamic_cohorts.php | 1 + version.php | 2 +- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/classes/rule.php b/classes/rule.php index d4f4466..b62469b 100644 --- a/classes/rule.php +++ b/classes/rule.php @@ -189,5 +189,6 @@ protected function after_create() { */ protected function after_update($result) { cache_helper::purge_by_event('ruleschanged'); + cache::make('tool_dynamic_cohorts', 'matchinguserscount')->delete($this->get('id')); } } diff --git a/classes/rule_manager.php b/classes/rule_manager.php index 470d487..49e751f 100644 --- a/classes/rule_manager.php +++ b/classes/rule_manager.php @@ -225,9 +225,11 @@ public static function delete_rule(rule $rule): void { public static function get_matching_users(rule $rule, ?int $userid = null): array { global $DB; - $conditions = $rule->get_condition_records(); + $matchinguserscache = cache::make('tool_dynamic_cohorts', 'matchinguserscount'); + $conditions = $rule->get_condition_records(); if (empty($conditions)) { + $matchinguserscache->set($rule->get('id'), 0); return []; } @@ -238,15 +240,21 @@ public static function get_matching_users(rule $rule, ?int $userid = null): arra } catch (\Exception $exception ) { self::trigger_matching_failed_event($rule, $exception->getMessage()); $rule->mark_broken(); + $matchinguserscache->set($rule->get('id'), 0); return []; } try { - return $DB->get_records_sql($sql . $sqldata->get_join() . ' WHERE ' . $sqldata->get_where(), $sqldata->get_params()); + $users = $DB->get_records_sql($sql . $sqldata->get_join() . ' WHERE ' . $sqldata->get_where(), $sqldata->get_params()); + if (empty($userid)) { + $matchinguserscache->set($rule->get('id'), count($users)); + } + return $users; } catch (\Exception $exception) { self::trigger_matching_failed_event($rule, $exception->getMessage()); $rule->mark_broken(); + $matchinguserscache->set($rule->get('id'), 0); return []; } @@ -256,37 +264,48 @@ public static function get_matching_users(rule $rule, ?int $userid = null): arra * Get count of matching users for a given rule. * * @param \tool_dynamic_cohorts\rule $rule - * @param int|null $userid * * @return int */ - public static function get_matching_users_count(rule $rule, ?int $userid = null): int { + public static function get_matching_users_count(rule $rule): int { global $DB; + $matchinguserscache = cache::make('tool_dynamic_cohorts', 'matchinguserscount'); + + $count = $matchinguserscache->get($rule->get('id')); + if ($count !== false) { + return $count; + } + $conditions = $rule->get_condition_records(); if (empty($conditions)) { + $matchinguserscache->set($rule->get('id'), 0); return 0; } $sql = "SELECT COUNT(DISTINCT u.id) cnt FROM {user} u"; try { - $sqldata = condition_manager::build_sql_data($conditions, $rule->get('operator'), $userid); + $sqldata = condition_manager::build_sql_data($conditions, $rule->get('operator')); } catch (\Exception $exception ) { self::trigger_matching_failed_event($rule, $exception->getMessage()); $rule->mark_broken(); + $matchinguserscache->set($rule->get('id'), 0); return 0; } try { $result = $DB->get_record_sql($sql . $sqldata->get_join() . ' WHERE ' . $sqldata->get_where(), $sqldata->get_params()); + $matchinguserscache->set($rule->get('id'), $result->cnt); + return $result->cnt; } catch (\Exception $exception) { self::trigger_matching_failed_event($rule, $exception->getMessage()); $rule->mark_broken(); + $matchinguserscache->set($rule->get('id'), 0); return 0; } } diff --git a/db/caches.php b/db/caches.php index 0ae7751..bc76272 100644 --- a/db/caches.php +++ b/db/caches.php @@ -44,4 +44,9 @@ 'conditionschanged', ], ], + 'matchinguserscount' => [ + 'mode' => cache_store::MODE_APPLICATION, + 'simpledata' => true, + 'staticacceleration' => true, + ], ]; diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index 46abb47..2fb13a6 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -36,6 +36,7 @@ $string['bulkprocessing'] = 'Bulk processing'; $string['bulkprocessing_help'] = 'If this option is enabled, users will be added and removed from cohort in bulk. This will significantly improve processing performance. However, using this option will suppress triggering events when users added or removed from cohort.'; $string['cachedef_conditionrecords'] = 'Conditions for a rule'; +$string['cachedef_matchingusers'] = 'Matching users for a rule'; $string['cachedef_rulesconditions'] = 'Rules with a specific condition'; $string['cohort'] = 'Cohort'; $string['cohortid'] = 'Cohort'; diff --git a/version.php b/version.php index 1865255..6a90a85 100644 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ $plugin->component = 'tool_dynamic_cohorts'; $plugin->release = 2024112100; -$plugin->version = 2024112101; +$plugin->version = 2024112102; $plugin->requires = 2022112800; $plugin->supported = [404, 405]; $plugin->maturity = MATURITY_STABLE;