diff --git a/.upgradenotes/MDL-82168-2024062815382042.yml b/.upgradenotes/MDL-82168-2024062815382042.yml new file mode 100644 index 00000000000..43a78574eee --- /dev/null +++ b/.upgradenotes/MDL-82168-2024062815382042.yml @@ -0,0 +1,5 @@ +issueNumber: MDL-82168 +notes: + core_badges: + - message: New webservices enable_badges and disable_badges have been added. + type: improved diff --git a/badges/action.php b/badges/action.php index c2a152db320..2e6eda4cb0b 100644 --- a/badges/action.php +++ b/badges/action.php @@ -29,9 +29,6 @@ require_once($CFG->libdir . '/badgeslib.php'); $badgeid = required_param('id', PARAM_INT); $copy = optional_param('copy', 0, PARAM_BOOL); -$activate = optional_param('activate', 0, PARAM_BOOL); -$deactivate = optional_param('lock', 0, PARAM_BOOL); -$confirm = optional_param('confirm', 0, PARAM_BOOL); $return = optional_param('return', 0, PARAM_LOCALURL); require_login(); @@ -74,64 +71,3 @@ if ($copy) { } redirect(new moodle_url('/badges/overview.php', array('id' => $cloneid))); } - -if ($activate) { - require_capability('moodle/badges:configurecriteria', $context); - - $PAGE->url->param('activate', 1); - $status = ($badge->status == BADGE_STATUS_INACTIVE) ? BADGE_STATUS_ACTIVE : BADGE_STATUS_ACTIVE_LOCKED; - if ($confirm == 1) { - require_sesskey(); - $badge->set_status($status); - $returnurl->param('msg', 'activatesuccess'); - - if ($badge->type == BADGE_TYPE_SITE) { - // Review on cron if there are more than 1000 users who can earn a site-level badge. - $sql = 'SELECT COUNT(u.id) as num - FROM {user} u - LEFT JOIN {badge_issued} bi - ON u.id = bi.userid AND bi.badgeid = :badgeid - WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0'; - $toearn = $DB->get_record_sql($sql, array('badgeid' => $badge->id, 'guestid' => $CFG->siteguest)); - - if ($toearn->num < 1000) { - $awards = $badge->review_all_criteria(); - $returnurl->param('awards', $awards); - } else { - $returnurl->param('awards', 'cron'); - } - } else { - $awards = $badge->review_all_criteria(); - $returnurl->param('awards', $awards); - } - redirect($returnurl); - } - - $strheading = get_string('reviewbadge', 'badges'); - $PAGE->navbar->add($strheading); - $PAGE->set_title($strheading); - $PAGE->set_heading($heading); - echo $OUTPUT->header(); - echo $OUTPUT->heading($strheading); - - $params = array('id' => $badge->id, 'activate' => 1, 'sesskey' => sesskey(), 'confirm' => 1, 'return' => $return); - $url = new moodle_url('/badges/action.php', $params); - - if (!$badge->has_criteria()) { - redirect($returnurl, get_string('error:cannotact', 'badges') . get_string('nocriteria', 'badges'), null, \core\output\notification::NOTIFY_ERROR); - } else { - $message = get_string('reviewconfirm', 'badges', $badge->name); - echo $OUTPUT->confirm($message, $url, $returnurl); - } - echo $OUTPUT->footer(); - die; -} - -if ($deactivate) { - require_sesskey(); - require_capability('moodle/badges:configurecriteria', $context); - - $status = ($badge->status == BADGE_STATUS_ACTIVE) ? BADGE_STATUS_INACTIVE : BADGE_STATUS_INACTIVE_LOCKED; - $badge->set_status($status); - redirect($returnurl); -} diff --git a/badges/amd/build/actions.min.js b/badges/amd/build/actions.min.js new file mode 100644 index 00000000000..4f9e98c3012 --- /dev/null +++ b/badges/amd/build/actions.min.js @@ -0,0 +1,10 @@ +define("core_badges/actions",["exports","core_badges/selectors","core/notification","core/prefetch","core/str","core/ajax","core/pending","core/event_dispatcher","core/toast","core_reportbuilder/local/events","core_reportbuilder/local/selectors"],(function(_exports,_selectors,_notification,_prefetch,_str,_ajax,_pending,_event_dispatcher,_toast,reportEvents,reportSelectors){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +/** + * Various actions on badges - enabling, disabling, etc. + * + * @module core_badges/actions + * @copyright 2024 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_selectors=_interopRequireDefault(_selectors),_notification=_interopRequireDefault(_notification),_ajax=_interopRequireDefault(_ajax),_pending=_interopRequireDefault(_pending),reportEvents=_interopRequireWildcard(reportEvents),reportSelectors=_interopRequireWildcard(reportSelectors);_exports.init=()=>{(0,_prefetch.prefetchStrings)("core_badges",["reviewconfirm","activatesuccess","deactivatesuccess","awardoncron","numawardstat"]),(0,_prefetch.prefetchStrings)("core",["confirm","enable"]),registerEventListeners()};const registerEventListeners=()=>{document.addEventListener("click",(event=>{const enableOption=event.target.closest(_selectors.default.actions.enablebadge);if(enableOption){event.preventDefault();const reportElement=event.target.closest(reportSelectors.regions.report),triggerElement=reportElement?enableOption.closest(".dropdown").querySelector(".dropdown-toggle"):null,badgeId=enableOption.dataset.badgeid,badgeName=enableOption.dataset.badgename;_notification.default.saveCancelPromise((0,_str.getString)("confirm","core"),(0,_str.getString)("reviewconfirm","core_badges",badgeName),(0,_str.getString)("enable","core"),{triggerElement:triggerElement}).then((()=>async function(badgeId,badgeName,reportElement){var request={methodname:"core_badges_enable_badges",args:{badgeids:[badgeId]}};const pendingPromise=new _pending.default("core_badges/enable");try{const result=await _ajax.default.call([request])[0];if(reportElement)!function(badgeName,result){var _result$result2;if((null===(_result$result2=result.result)||void 0===_result$result2?void 0:_result$result2.length)>0){var _result$result3;(0,_toast.add)((0,_str.getString)("activatesuccess","core_badges",badgeName),{type:"success"});const awards=null===(_result$result3=result.result)||void 0===_result$result3?void 0:_result$result3.pop().awards;"cron"==awards?(0,_toast.add)((0,_str.getString)("awardoncron","core_badges",{badgename:badgeName})):awards>0&&(0,_toast.add)((0,_str.getString)("numawardstat","core_badges",{badgename:badgeName,awards:awards}))}else result.warnings.length>0&&(0,_toast.add)(result.warnings[0].message,{type:"danger"})}(badgeName,result),(0,_event_dispatcher.dispatchEvent)(reportEvents.tableReload,{preservePagination:!0},reportElement);else{var _result$result;const awards=null===(_result$result=result.result)||void 0===_result$result?void 0:_result$result.pop().awards;document.location=document.location.pathname+"?id=".concat(badgeId,"&awards=").concat(awards)}}catch(error){_notification.default.exception(error)}pendingPromise.resolve()}(badgeId,badgeName,reportElement))).catch((()=>{}))}const disableOption=event.target.closest(_selectors.default.actions.disablebadge);if(disableOption){event.preventDefault();!async function(badgeId,badgeName,reportElement){var request={methodname:"core_badges_disable_badges",args:{badgeids:[badgeId]}};try{const result=await _ajax.default.call([request])[0];reportElement?(!function(badgeName,result){result.result?(0,_toast.add)((0,_str.getString)("deactivatesuccess","core_badges",badgeName),{type:"success"}):result.warnings.length>0&&(0,_toast.add)(result.warnings[0].message,{type:"danger"})}(badgeName,result),(0,_event_dispatcher.dispatchEvent)(reportEvents.tableReload,{preservePagination:!0},reportElement)):document.location=document.location.pathname+"?id=".concat(badgeId)}catch(error){_notification.default.exception(error)}}(disableOption.dataset.badgeid,disableOption.dataset.badgename,event.target.closest(reportSelectors.regions.report))}}))}})); + +//# sourceMappingURL=actions.min.js.map \ No newline at end of file diff --git a/badges/amd/build/actions.min.js.map b/badges/amd/build/actions.min.js.map new file mode 100644 index 00000000000..221b54306db --- /dev/null +++ b/badges/amd/build/actions.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"actions.min.js","sources":["../src/actions.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Various actions on badges - enabling, disabling, etc.\n *\n * @module core_badges/actions\n * @copyright 2024 Sara Arjona \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport selectors from 'core_badges/selectors';\nimport Notification from 'core/notification';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString} from 'core/str';\nimport Ajax from 'core/ajax';\nimport Pending from 'core/pending';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport {add as addToast} from 'core/toast';\nimport * as reportEvents from 'core_reportbuilder/local/events';\nimport * as reportSelectors from 'core_reportbuilder/local/selectors';\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n prefetchStrings('core_badges', [\n 'reviewconfirm',\n 'activatesuccess',\n 'deactivatesuccess',\n 'awardoncron',\n 'numawardstat',\n ]);\n prefetchStrings('core', [\n 'confirm',\n 'enable',\n ]);\n\n registerEventListeners();\n};\n\n/**\n * Register events for delete preset option in action menu.\n */\nconst registerEventListeners = () => {\n document.addEventListener('click', (event) => {\n const enableOption = event.target.closest(selectors.actions.enablebadge);\n\n if (enableOption) {\n event.preventDefault();\n\n // Use triggerElement to return focus to the action menu toggle.\n const reportElement = event.target.closest(reportSelectors.regions.report);\n const triggerElement = reportElement ? enableOption.closest('.dropdown').querySelector('.dropdown-toggle') : null;\n const badgeId = enableOption.dataset.badgeid;\n const badgeName = enableOption.dataset.badgename;\n\n Notification.saveCancelPromise(\n getString('confirm', 'core'),\n getString('reviewconfirm', 'core_badges', badgeName),\n getString('enable', 'core'),\n {triggerElement}\n ).then(() => {\n return enableBadge(badgeId, badgeName, reportElement);\n }).catch(() => {\n return;\n });\n }\n\n const disableOption = event.target.closest(selectors.actions.disablebadge);\n if (disableOption) {\n event.preventDefault();\n const badgeId = disableOption.dataset.badgeid;\n const badgeName = disableOption.dataset.badgename;\n const reportElement = event.target.closest(reportSelectors.regions.report);\n disableBadge(badgeId, badgeName, reportElement);\n }\n });\n};\n\n/**\n * Enable the badge.\n *\n * @param {Number} badgeId The id of the badge to enable.\n * @param {String} badgeName The name of the badge to enable.\n * @param {HTMLElement} reportElement the report element.\n */\nasync function enableBadge(badgeId, badgeName, reportElement) {\n var request = {\n methodname: 'core_badges_enable_badges',\n args: {\n badgeids: [badgeId],\n }\n };\n\n const pendingPromise = new Pending('core_badges/enable');\n try {\n const result = await Ajax.call([request])[0];\n if (reportElement) {\n showEnableResultToast(badgeName, result);\n // Report element is present, reload the table.\n dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);\n } else {\n // Report element is not present, add the parameters to the current page to display the message.\n const awards = result.result?.pop().awards;\n document.location = document.location.pathname + `?id=${badgeId}&awards=${awards}`;\n }\n } catch (error) {\n Notification.exception(error);\n }\n pendingPromise.resolve();\n}\n\n/**\n * Show the result of enabling a badge.\n *\n * @param {String} badgeName The name of the badge to enable.\n * @param {Object} result The result of enabling a badge.\n */\nfunction showEnableResultToast(badgeName, result) {\n if (result.result?.length > 0) {\n addToast(getString('activatesuccess', 'core_badges', badgeName), {type: 'success'});\n const awards = result.result?.pop().awards;\n if (awards == 'cron') {\n addToast(getString('awardoncron', 'core_badges', {badgename: badgeName}));\n } else if (awards > 0) {\n addToast(getString('numawardstat', 'core_badges', {badgename: badgeName, awards: awards}));\n }\n } else if (result.warnings.length > 0) {\n addToast(result.warnings[0].message, {type: 'danger'});\n }\n}\n\n/**\n * Disable the badge.\n *\n * @param {Number} badgeId The id of the badge to disable.\n * @param {String} badgeName The name of the badge to enable.\n * @param {HTMLElement} reportElement the report element.\n */\nasync function disableBadge(badgeId, badgeName, reportElement) {\n var request = {\n methodname: 'core_badges_disable_badges',\n args: {\n badgeids: [badgeId],\n }\n };\n\n try {\n const result = await Ajax.call([request])[0];\n if (reportElement) {\n // Report element is present, show the message in a toast and reload the table.\n showDisableResultToast(badgeName, result);\n dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);\n } else {\n // Report element is not present, the page should be reloaded.\n document.location = document.location.pathname + `?id=${badgeId}`;\n }\n } catch (error) {\n Notification.exception(error);\n }\n}\n\n/**\n * Show the result of disabling a badge.\n *\n * @param {String} badgeName The name of the badge to disable.\n * @param {Object} result The result of disabling a badge.\n */\nfunction showDisableResultToast(badgeName, result) {\n if (result.result) {\n addToast(\n getString('deactivatesuccess', 'core_badges', badgeName),\n {type: 'success'}\n );\n } else if (result.warnings.length > 0) {\n addToast(\n result.warnings[0].message,\n {type: 'danger'}\n );\n }\n}\n"],"names":["registerEventListeners","document","addEventListener","event","enableOption","target","closest","selectors","actions","enablebadge","preventDefault","reportElement","reportSelectors","regions","report","triggerElement","querySelector","badgeId","dataset","badgeid","badgeName","badgename","saveCancelPromise","then","request","methodname","args","badgeids","pendingPromise","Pending","result","Ajax","call","length","type","awards","_result$result3","pop","warnings","message","showEnableResultToast","reportEvents","tableReload","preservePagination","_result$result","location","pathname","error","exception","resolve","enableBadge","catch","disableOption","disablebadge","showDisableResultToast","disableBadge"],"mappings":";;;;;;;4XAqCoB,mCACA,cAAe,CAC3B,gBACA,kBACA,oBACA,cACA,+CAEY,OAAQ,CACpB,UACA,WAGJA,gCAMEA,uBAAyB,KAC3BC,SAASC,iBAAiB,SAAUC,cAC1BC,aAAeD,MAAME,OAAOC,QAAQC,mBAAUC,QAAQC,gBAExDL,aAAc,CACdD,MAAMO,uBAGAC,cAAgBR,MAAME,OAAOC,QAAQM,gBAAgBC,QAAQC,QAC7DC,eAAiBJ,cAAgBP,aAAaE,QAAQ,aAAaU,cAAc,oBAAsB,KACvGC,QAAUb,aAAac,QAAQC,QAC/BC,UAAYhB,aAAac,QAAQG,gCAE1BC,mBACT,kBAAU,UAAW,SACrB,kBAAU,gBAAiB,cAAeF,YAC1C,kBAAU,SAAU,QACpB,CAACL,eAAAA,iBACHQ,MAAK,mBAyBQN,QAASG,UAAWT,mBACvCa,QAAU,CACVC,WAAY,4BACZC,KAAM,CACFC,SAAU,CAACV,iBAIbW,eAAiB,IAAIC,iBAAQ,gCAEzBC,aAAeC,cAAKC,KAAK,CAACR,UAAU,MACtCb,wBAqBmBS,UAAWU,wDAClCA,OAAOA,yDAAQG,QAAS,EAAG,qCAClB,kBAAU,kBAAmB,cAAeb,WAAY,CAACc,KAAM,kBAClEC,+BAASL,OAAOA,yCAAPM,gBAAeC,MAAMF,OACtB,QAAVA,uBACS,kBAAU,cAAe,cAAe,CAACd,UAAWD,aACtDe,OAAS,mBACP,kBAAU,eAAgB,cAAe,CAACd,UAAWD,UAAWe,OAAQA,eAE9EL,OAAOQ,SAASL,OAAS,kBACvBH,OAAOQ,SAAS,GAAGC,QAAS,CAACL,KAAM,WA9BxCM,CAAsBpB,UAAWU,4CAEnBW,aAAaC,YAAa,CAACC,oBAAoB,GAAOhC,mBACjE,0BAEGwB,8BAASL,OAAOA,wCAAPc,eAAeP,MAAMF,OACpClC,SAAS4C,SAAW5C,SAAS4C,SAASC,uBAAkB7B,2BAAkBkB,SAEhF,MAAOY,6BACQC,UAAUD,OAE3BnB,eAAeqB,UA/CIC,CAAYjC,QAASG,UAAWT,iBACxCwC,OAAM,eAKPC,cAAgBjD,MAAME,OAAOC,QAAQC,mBAAUC,QAAQ6C,iBACzDD,cAAe,CACfjD,MAAMO,iCAqEUO,QAASG,UAAWT,mBACxCa,QAAU,CACVC,WAAY,6BACZC,KAAM,CACFC,SAAU,CAACV,qBAKTa,aAAeC,cAAKC,KAAK,CAACR,UAAU,GACtCb,yBAmBoBS,UAAWU,QACnCA,OAAOA,uBAEH,kBAAU,oBAAqB,cAAeV,WAC9C,CAACc,KAAM,YAEJJ,OAAOQ,SAASL,OAAS,kBAE5BH,OAAOQ,SAAS,GAAGC,QACnB,CAACL,KAAM,WA1BPoB,CAAuBlC,UAAWU,4CACpBW,aAAaC,YAAa,CAACC,oBAAoB,GAAOhC,gBAGpEV,SAAS4C,SAAW5C,SAAS4C,SAASC,uBAAkB7B,SAE9D,MAAO8B,6BACQC,UAAUD,QApFnBQ,CAHgBH,cAAclC,QAAQC,QACpBiC,cAAclC,QAAQG,UAClBlB,MAAME,OAAOC,QAAQM,gBAAgBC,QAAQC"} \ No newline at end of file diff --git a/badges/amd/build/selectors.min.js b/badges/amd/build/selectors.min.js index 916edb19d88..6651a0bd745 100644 --- a/badges/amd/build/selectors.min.js +++ b/badges/amd/build/selectors.min.js @@ -1,3 +1,11 @@ -define("core_badges/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;var name,value,_default={actions:{deletebackpack:(name="action",value="deletebackpack","[data-".concat(name,'="').concat(value,'"]'))},elements:{clearsearch:".input-group-append .clear-icon",main:"#backpacklist",backpackurl:"[data-backpackurl]"}};return _exports.default=_default,_exports.default})); +define("core_badges/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * Define all of the selectors we will be using on the backpack interface. + * + * @module core_badges/selectors + * @copyright 2020 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +const getDataSelector=(name,value)=>"[data-".concat(name,'="').concat(value,'"]');var _default={actions:{deletebackpack:getDataSelector("action","deletebackpack"),enablebadge:getDataSelector("action","enablebadge"),disablebadge:getDataSelector("action","disablebadge")},elements:{clearsearch:".input-group-append .clear-icon",main:"#backpacklist",backpackurl:"[data-backpackurl]"}};return _exports.default=_default,_exports.default})); //# sourceMappingURL=selectors.min.js.map \ No newline at end of file diff --git a/badges/amd/build/selectors.min.js.map b/badges/amd/build/selectors.min.js.map index 36bcd53ad01..9b3f4c7903b 100644 --- a/badges/amd/build/selectors.min.js.map +++ b/badges/amd/build/selectors.min.js.map @@ -1 +1 @@ -{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Define all of the selectors we will be using on the backpack interface.\n *\n * @module core_badges/selectors\n * @copyright 2020 Sara Arjona \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n *\n * @method getDataSelector\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n actions: {\n deletebackpack: getDataSelector('action', 'deletebackpack'),\n },\n elements: {\n clearsearch: '.input-group-append .clear-icon',\n main: '#backpacklist',\n backpackurl: '[data-backpackurl]',\n },\n};\n"],"names":["name","value","actions","deletebackpack","elements","clearsearch","main","backpackurl"],"mappings":"mJA+ByBA,KAAMC,eAIhB,CACXC,QAAS,CACLC,gBANiBH,KAMe,SANTC,MAMmB,iCAL9BD,kBAASC,cAOzBG,SAAU,CACNC,YAAa,kCACbC,KAAM,gBACNC,YAAa"} \ No newline at end of file +{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Define all of the selectors we will be using on the backpack interface.\n *\n * @module core_badges/selectors\n * @copyright 2020 Sara Arjona \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n *\n * @method getDataSelector\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n actions: {\n deletebackpack: getDataSelector('action', 'deletebackpack'),\n enablebadge: getDataSelector('action', 'enablebadge'),\n disablebadge: getDataSelector('action', 'disablebadge'),\n },\n elements: {\n clearsearch: '.input-group-append .clear-icon',\n main: '#backpacklist',\n backpackurl: '[data-backpackurl]',\n },\n};\n"],"names":["getDataSelector","name","value","actions","deletebackpack","enablebadge","disablebadge","elements","clearsearch","main","backpackurl"],"mappings":";;;;;;;;MA+BMA,gBAAkB,CAACC,KAAMC,wBACXD,kBAASC,yBAGd,CACXC,QAAS,CACLC,eAAgBJ,gBAAgB,SAAU,kBAC1CK,YAAaL,gBAAgB,SAAU,eACvCM,aAAcN,gBAAgB,SAAU,iBAE5CO,SAAU,CACNC,YAAa,kCACbC,KAAM,gBACNC,YAAa"} \ No newline at end of file diff --git a/badges/amd/src/actions.js b/badges/amd/src/actions.js new file mode 100644 index 00000000000..0cca5ddd170 --- /dev/null +++ b/badges/amd/src/actions.js @@ -0,0 +1,194 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Various actions on badges - enabling, disabling, etc. + * + * @module core_badges/actions + * @copyright 2024 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import selectors from 'core_badges/selectors'; +import Notification from 'core/notification'; +import {prefetchStrings} from 'core/prefetch'; +import {getString} from 'core/str'; +import Ajax from 'core/ajax'; +import Pending from 'core/pending'; +import {dispatchEvent} from 'core/event_dispatcher'; +import {add as addToast} from 'core/toast'; +import * as reportEvents from 'core_reportbuilder/local/events'; +import * as reportSelectors from 'core_reportbuilder/local/selectors'; + +/** + * Initialize module. + */ +export const init = () => { + prefetchStrings('core_badges', [ + 'reviewconfirm', + 'activatesuccess', + 'deactivatesuccess', + 'awardoncron', + 'numawardstat', + ]); + prefetchStrings('core', [ + 'confirm', + 'enable', + ]); + + registerEventListeners(); +}; + +/** + * Register events for delete preset option in action menu. + */ +const registerEventListeners = () => { + document.addEventListener('click', (event) => { + const enableOption = event.target.closest(selectors.actions.enablebadge); + + if (enableOption) { + event.preventDefault(); + + // Use triggerElement to return focus to the action menu toggle. + const reportElement = event.target.closest(reportSelectors.regions.report); + const triggerElement = reportElement ? enableOption.closest('.dropdown').querySelector('.dropdown-toggle') : null; + const badgeId = enableOption.dataset.badgeid; + const badgeName = enableOption.dataset.badgename; + + Notification.saveCancelPromise( + getString('confirm', 'core'), + getString('reviewconfirm', 'core_badges', badgeName), + getString('enable', 'core'), + {triggerElement} + ).then(() => { + return enableBadge(badgeId, badgeName, reportElement); + }).catch(() => { + return; + }); + } + + const disableOption = event.target.closest(selectors.actions.disablebadge); + if (disableOption) { + event.preventDefault(); + const badgeId = disableOption.dataset.badgeid; + const badgeName = disableOption.dataset.badgename; + const reportElement = event.target.closest(reportSelectors.regions.report); + disableBadge(badgeId, badgeName, reportElement); + } + }); +}; + +/** + * Enable the badge. + * + * @param {Number} badgeId The id of the badge to enable. + * @param {String} badgeName The name of the badge to enable. + * @param {HTMLElement} reportElement the report element. + */ +async function enableBadge(badgeId, badgeName, reportElement) { + var request = { + methodname: 'core_badges_enable_badges', + args: { + badgeids: [badgeId], + } + }; + + const pendingPromise = new Pending('core_badges/enable'); + try { + const result = await Ajax.call([request])[0]; + if (reportElement) { + showEnableResultToast(badgeName, result); + // Report element is present, reload the table. + dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement); + } else { + // Report element is not present, add the parameters to the current page to display the message. + const awards = result.result?.pop().awards; + document.location = document.location.pathname + `?id=${badgeId}&awards=${awards}`; + } + } catch (error) { + Notification.exception(error); + } + pendingPromise.resolve(); +} + +/** + * Show the result of enabling a badge. + * + * @param {String} badgeName The name of the badge to enable. + * @param {Object} result The result of enabling a badge. + */ +function showEnableResultToast(badgeName, result) { + if (result.result?.length > 0) { + addToast(getString('activatesuccess', 'core_badges', badgeName), {type: 'success'}); + const awards = result.result?.pop().awards; + if (awards == 'cron') { + addToast(getString('awardoncron', 'core_badges', {badgename: badgeName})); + } else if (awards > 0) { + addToast(getString('numawardstat', 'core_badges', {badgename: badgeName, awards: awards})); + } + } else if (result.warnings.length > 0) { + addToast(result.warnings[0].message, {type: 'danger'}); + } +} + +/** + * Disable the badge. + * + * @param {Number} badgeId The id of the badge to disable. + * @param {String} badgeName The name of the badge to enable. + * @param {HTMLElement} reportElement the report element. + */ +async function disableBadge(badgeId, badgeName, reportElement) { + var request = { + methodname: 'core_badges_disable_badges', + args: { + badgeids: [badgeId], + } + }; + + try { + const result = await Ajax.call([request])[0]; + if (reportElement) { + // Report element is present, show the message in a toast and reload the table. + showDisableResultToast(badgeName, result); + dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement); + } else { + // Report element is not present, the page should be reloaded. + document.location = document.location.pathname + `?id=${badgeId}`; + } + } catch (error) { + Notification.exception(error); + } +} + +/** + * Show the result of disabling a badge. + * + * @param {String} badgeName The name of the badge to disable. + * @param {Object} result The result of disabling a badge. + */ +function showDisableResultToast(badgeName, result) { + if (result.result) { + addToast( + getString('deactivatesuccess', 'core_badges', badgeName), + {type: 'success'} + ); + } else if (result.warnings.length > 0) { + addToast( + result.warnings[0].message, + {type: 'danger'} + ); + } +} diff --git a/badges/amd/src/selectors.js b/badges/amd/src/selectors.js index a8b66a3461a..b7a557a91cc 100644 --- a/badges/amd/src/selectors.js +++ b/badges/amd/src/selectors.js @@ -36,6 +36,8 @@ const getDataSelector = (name, value) => { export default { actions: { deletebackpack: getDataSelector('action', 'deletebackpack'), + enablebadge: getDataSelector('action', 'enablebadge'), + disablebadge: getDataSelector('action', 'disablebadge'), }, elements: { clearsearch: '.input-group-append .clear-icon', diff --git a/badges/classes/external/disable_badges.php b/badges/classes/external/disable_badges.php new file mode 100644 index 00000000000..e3c2bb7f27b --- /dev/null +++ b/badges/classes/external/disable_badges.php @@ -0,0 +1,126 @@ +. + +namespace core_badges\external; + +use core_badges\badge; +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_single_structure; +use core_external\external_multiple_structure; +use core_external\external_value; +use core_external\external_warnings; +use moodle_exception; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir . '/badgeslib.php'); + +/** + * External service to disable badges. + * + * @package core_badges + * @category external + * @copyright 2024 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 4.5 + */ +class disable_badges extends external_api { + + /** + * Describes the parameters. + * + * @return external_function_parameters + */ + public static function execute_parameters(): external_function_parameters { + return new external_function_parameters([ + 'badgeids' => new external_multiple_structure( + new external_value(PARAM_TEXT, 'The badge identifiers to update', VALUE_REQUIRED), + ), + ]); + } + + /** + * Disable the given badges. + * + * @param array $badgeids List of badge identifiers to disable. + * @return array List of results and warnings. + */ + public static function execute(array $badgeids): array { + global $CFG, $DB; + + $warnings = []; + + [ + 'badgeids' => $badgeids, + ] = self::validate_parameters(self::execute_parameters(), [ + 'badgeids' => $badgeids, + ]); + + // Check if badges are enabled. + if (empty($CFG->enablebadges)) { + throw new moodle_exception('badgesdisabled', 'badges'); + } + + foreach ($badgeids as $badgeid) { + $badge = new badge($badgeid); + + // Check capabilities. + $context = $badge->get_context(); + self::validate_context($context); + if (!has_capability('moodle/badges:configurecriteria', $context)) { + $warnings[] = [ + 'item' => $badgeid, + 'warningcode' => 'nopermissions', + 'message' => get_string('nopermissions', 'error'), + ]; + continue; + } + + // Check if course badges are enabled. + if (empty($CFG->badges_allowcoursebadges) && ($badge->type == BADGE_TYPE_COURSE)) { + $warnings[] = [ + 'item' => $badgeid, + 'warningcode' => 'coursebadgesdisabled', + 'message' => get_string('coursebadgesdisabled', 'badges'), + ]; + continue; + } + + $status = ($badge->status == BADGE_STATUS_ACTIVE) ? BADGE_STATUS_INACTIVE : BADGE_STATUS_INACTIVE_LOCKED; + // Deactivate the badge. + $badge->set_status($status); + } + + return [ + 'result' => empty($warnings), + 'warnings' => $warnings, + ]; + } + + /** + * Describe the return structure of the external service. + * + * @return external_single_structure + */ + public static function execute_returns(): external_single_structure { + return new external_single_structure([ + 'result' => new external_value(PARAM_BOOL, 'The processing result'), + 'warnings' => new external_warnings(), + ]); + } +} diff --git a/badges/classes/external/enable_badges.php b/badges/classes/external/enable_badges.php new file mode 100644 index 00000000000..ddf9f9be3c2 --- /dev/null +++ b/badges/classes/external/enable_badges.php @@ -0,0 +1,183 @@ +. + +namespace core_badges\external; + +use core_badges\badge; +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_single_structure; +use core_external\external_multiple_structure; +use core_external\external_value; +use core_external\external_warnings; +use moodle_exception; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir . '/badgeslib.php'); + +/** + * External service to enable badges. + * + * @package core_badges + * @category external + * @copyright 2024 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 4.5 + */ +class enable_badges extends external_api { + + /** + * Describes the parameters. + * + * @return external_function_parameters + */ + public static function execute_parameters(): external_function_parameters { + return new external_function_parameters([ + 'badgeids' => new external_multiple_structure( + new external_value(PARAM_TEXT, 'The badge identifiers to update', VALUE_REQUIRED), + ), + ]); + } + + /** + * Enable the given badges. + * + * @param array $badgeids List of badge identifiers to enable. + * @return array The number of awarded users for each badge or 'cron' when there are more than 1000 users. + */ + public static function execute(array $badgeids): array { + global $CFG, $DB; + + $result = []; + $warnings = []; + + [ + 'badgeids' => $badgeids, + ] = self::validate_parameters(self::execute_parameters(), [ + 'badgeids' => $badgeids, + ]); + + // Check if badges are enabled. + if (empty($CFG->enablebadges)) { + throw new moodle_exception('badgesdisabled', 'badges'); + } + + foreach ($badgeids as $badgeid) { + $badge = new badge($badgeid); + + // Check capabilities. + $context = $badge->get_context(); + self::validate_context($context); + if (!has_capability('moodle/badges:configurecriteria', $context)) { + $warnings[] = [ + 'item' => $badgeid, + 'warningcode' => 'nopermissions', + 'message' => get_string('nopermissions', 'error'), + ]; + continue; + } + + // Check if course badges are enabled. + if (empty($CFG->badges_allowcoursebadges) && ($badge->type == BADGE_TYPE_COURSE)) { + $warnings[] = [ + 'item' => $badgeid, + 'warningcode' => 'coursebadgesdisabled', + 'message' => get_string('coursebadgesdisabled', 'badges'), + ]; + continue; + } + + // Check if the badge has criteria. + if (!$badge->has_criteria()) { + $warnings[] = [ + 'item' => $badgeid, + 'warningcode' => 'nocriteria', + 'message' => get_string('nocriteria', 'badges'), + ]; + continue; + } + + // Activate the badge. + $status = ($badge->status == BADGE_STATUS_INACTIVE) ? BADGE_STATUS_ACTIVE : BADGE_STATUS_ACTIVE_LOCKED; + $badge->set_status($status); + $awards = self::review_criteria($badge); + + $result[] = [ + 'badgeid' => $badgeid, + 'awards' => $awards, + ]; + } + + return [ + 'result' => $result, + 'warnings' => $warnings, + ]; + } + + /** + * Describe the return structure of the external service. + * + * @return external_single_structure + */ + public static function execute_returns(): external_single_structure { + return new external_single_structure([ + 'result' => new external_multiple_structure( + new external_single_structure([ + 'badgeid' => new external_value(PARAM_INT, 'The badge identifier'), + 'awards' => new external_value(PARAM_ALPHANUM, 'The processing result'), + ]), + ), + 'warnings' => new external_warnings(), + ]); + } + + /** + * Review the criteria of the badge. + * + * @param \core_badges\badge $badge The badge to review the criteria. + * @return string The number of awarded users or 'cron' when there are more than 1000 users. + */ + private static function review_criteria(badge $badge): string { + global $CFG, $DB; + + if ($badge->type == BADGE_TYPE_SITE) { + // Review on cron if there are more than 1000 users who can earn a site-level badge. + $sql = 'SELECT COUNT(u.id) as num + FROM {user} u + LEFT JOIN {badge_issued} bi + ON u.id = bi.userid AND bi.badgeid = :badgeid + WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0'; + $toearn = $DB->get_record_sql( + $sql, + [ + 'badgeid' => $badge->id, + 'guestid' => $CFG->siteguest, + ], + ); + if ($toearn->num < 1000) { + $awards = $badge->review_all_criteria(); + } else { + $awards = 'cron'; + } + } else { + $awards = $badge->review_all_criteria(); + } + + return $awards; + } +} diff --git a/badges/classes/reportbuilder/local/systemreports/badges.php b/badges/classes/reportbuilder/local/systemreports/badges.php index 5a8da89262f..cbe8384a1ec 100644 --- a/badges/classes/reportbuilder/local/systemreports/badges.php +++ b/badges/classes/reportbuilder/local/systemreports/badges.php @@ -158,21 +158,19 @@ class badges extends system_report { protected function add_actions(): void { // Activate badge. $this->add_action((new action( - new moodle_url('/badges/action.php', [ - 'id' => ':id', - 'activate' => true, - 'return' => ':return', - ]), + new moodle_url('#'), new pix_icon('t/show', '', 'core'), - [], + [ + 'data-action' => 'enablebadge', + 'data-badgeid' => ':id', + 'data-badgename' => ':badgename', + 'data-courseid' => ':courseid', + ], false, new lang_string('activate', 'badges') ))->add_callback(static function(stdclass $row): bool { $badge = new \core_badges\badge($row->id); - - // Populate the return URL. - $row->return = (new moodle_url('/badges/index.php', - ['type' => $badge->type, 'id' => (int) $badge->courseid]))->out_as_local_url(false); + $row->badgename = $badge->name; return has_capability('moodle/badges:configuredetails', $badge->get_context()) && $badge->has_criteria() && @@ -182,18 +180,19 @@ class badges extends system_report { // Deactivate badge. $this->add_action((new action( - new moodle_url('/badges/index.php', [ - 'lock' => ':id', - 'sesskey' => sesskey(), - 'type' => ':type', - 'id' => ':courseid', - ]), + new moodle_url('#'), new pix_icon('t/hide', '', 'core'), - [], + [ + 'data-action' => 'disablebadge', + 'data-badgeid' => ':id', + 'data-badgename' => ':badgename', + 'data-courseid' => ':courseid', + ], false, new lang_string('deactivate', 'badges') ))->add_callback(static function(stdclass $row): bool { $badge = new \core_badges\badge($row->id); + $row->badgename = $badge->name; return has_capability('moodle/badges:configuredetails', $badge->get_context()) && $badge->has_criteria() && $row->status != BADGE_STATUS_INACTIVE && $row->status != BADGE_STATUS_INACTIVE_LOCKED; diff --git a/badges/index.php b/badges/index.php index df043ec35e8..df0f3ad3d7b 100644 --- a/badges/index.php +++ b/badges/index.php @@ -161,5 +161,6 @@ $report = system_report_factory::create(badges::class, $PAGE->context); $report->set_default_no_results_notice(new lang_string('nobadges', 'badges')); echo $report->output(); +$PAGE->requires->js_call_amd('core_badges/actions', 'init'); echo $OUTPUT->footer(); diff --git a/badges/overview.php b/badges/overview.php index 87ea1d76948..e401eb52642 100644 --- a/badges/overview.php +++ b/badges/overview.php @@ -74,9 +74,9 @@ echo $output->render_tertiary_navigation($actionbar); echo $OUTPUT->heading(print_badge_image($badge, $context, 'small') . ' ' . $badge->name); if ($awards == 'cron') { - echo $OUTPUT->notification(get_string('awardoncron', 'badges'), 'notifysuccess'); + echo $OUTPUT->notification(get_string('awardoncron', 'badges', ['badgename' => $badge->name]), 'info'); } else if ((int)$awards > 0) { - echo $OUTPUT->notification(get_string('numawardstat', 'badges', $awards), 'notifysuccess'); + echo $OUTPUT->notification(get_string('numawardstat', 'badges', ['badgename' => $badge->name, 'awards' => $awards]), 'info'); } echo $output->print_badge_status_box($badge); echo $output->print_badge_overview($badge, $context); diff --git a/badges/renderer.php b/badges/renderer.php index 8740f66f0f3..182229e6881 100644 --- a/badges/renderer.php +++ b/badges/renderer.php @@ -242,6 +242,7 @@ class core_badges_renderer extends plugin_renderer_base { if ($badge->has_awards()) { $url = new moodle_url('/badges/recipients.php', array('id' => $badge->id)); $a = new stdClass(); + $a->badgename = $badge->name; $a->link = $url->out(); $a->count = count($badge->get_awards()); $display .= get_string('numawards', 'badges', $a); @@ -573,17 +574,34 @@ class core_badges_renderer extends plugin_renderer_base { $message = $status . $action; } else { + $this->page->requires->js_call_amd('core_badges/actions', 'init'); + $status = get_string('statusmessage_' . $badge->status, 'badges'); if ($badge->is_active()) { - $action = $this->output->single_button(new moodle_url('/badges/action.php', - array('id' => $badge->id, 'lock' => 1, 'sesskey' => sesskey(), - 'return' => $this->page->url->out_as_local_url(false))), - get_string('deactivate', 'badges'), 'POST', array('class' => 'activatebadge')); + $action = $this->output->single_button( + new moodle_url('#'), + get_string('deactivate', 'badges'), + 'POST', + [ + 'class' => 'activatebadge', + 'data-action' => 'disablebadge', + 'data-badgeid' => $badge->id, + 'data-badgename' => $badge->name, + 'data-courseid' => $badge->courseid, + ], + ); } else { - $action = $this->output->single_button(new moodle_url('/badges/action.php', - array('id' => $badge->id, 'activate' => 1, 'sesskey' => sesskey(), - 'return' => $this->page->url->out_as_local_url(false))), - get_string('activate', 'badges'), 'POST', array('class' => 'activatebadge')); + $action = $this->output->single_button( + new moodle_url('#'), + get_string('activate', 'badges'), + 'POST', + [ + 'class' => 'activatebadge', + 'data-action' => 'enablebadge', + 'data-badgeid' => $badge->id, + 'data-badgename' => $badge->name, + 'data-courseid' => $badge->courseid, + ]); } $message = $status . $this->output->help_icon('status', 'badges') . $action; diff --git a/badges/tests/behat/award_badge.feature b/badges/tests/behat/award_badge.feature index 2ce8fcbfe37..3a6a99a9511 100644 --- a/badges/tests/behat/award_badge.feature +++ b/badges/tests/behat/award_badge.feature @@ -29,37 +29,23 @@ Feature: Award badges @javascript Scenario: Award badge on other badges as criteria - Given I log in as "teacher1" - And I am on "Course 1" course homepage - # Create course badge 1. - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge 1 | - | Description | Course badge 1 description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - And I set the field "type" to "Manual issue by role" - And I expand all fieldsets - # Set to ANY of the roles awards badge. - And I set the field "Teacher" to "1" - And I set the field "Any of the selected roles awards the badge" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" - # Badge #2 - And I am on "Course 1" course homepage - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge 2 | - | Description | Course badge 2 description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - # Set "course badge 1" as criteria + Given the following "core_badges > Badges" exist: + | name | course | description | image | status | type | + | Course Badge 1 | C1 | Course badge 1 description | badges/tests/behat/badge.png | active | 2 | + | Course Badge 2 | C1 | Course badge 2 description | badges/tests/behat/badge.png | 0 | 2 | + And the following "core_badges > Criteria" exists: + | badge | Course Badge 1 | + | role | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge 2" + And I select "Criteria" from the "jump" singleselect + # Set "course badge 1" as criteria for Badge 2. And I set the field "type" to "Awarded badges" And I set the field "id_badge_badges" to "Course Badge 1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I am on "Course 1" course homepage And I navigate to "Badges > Manage badges" in current page administration And I follow "Course Badge 1" @@ -110,13 +96,16 @@ Feature: Award badges @javascript Scenario: Award profile badge + Given the following "core_badges > Badge" exists: + | name | Profile Badge | + | description | Test badge description | + | image | badges/tests/behat/badge.png | + | status | 0 | + | type | 1 | Given I log in as "admin" - And I navigate to "Badges > Add a new badge" in site administration - And I set the following fields to these values: - | Name | Profile Badge | - | Description | Test badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" + And I navigate to "Badges > Manage badges" in site administration + And I follow "Profile Badge" + And I select "Criteria" from the "jump" singleselect And I set the field "type" to "Profile completion" And I expand all fieldsets And I set the field "First name" to "1" @@ -131,7 +120,7 @@ Feature: Award badges And I should see "Criterion description" And I should not see "Criteria for this badge have not been set up yet." And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I open my profile in edit mode And I expand all fieldsets And I set the field "Phone" to "123456789" @@ -142,18 +131,18 @@ Feature: Award badges @javascript Scenario: Award site badge - Given I log in as "admin" - And I navigate to "Badges > Add a new badge" in site administration - And I set the following fields to these values: - | Name | Site Badge | - | Description | Site badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - And I set the field "type" to "Manual issue by role" - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + Given the following "core_badges > Badge" exists: + | name | Site Badge | + | description | Site badge description | + | image | badges/tests/behat/badge.png | + | status | active | + | type | 1 | + And the following "core_badges > Criteria" exists: + | badge | Site Badge | + | role | editingteacher | + And I log in as "admin" + And I navigate to "Badges > Manage badges" in site administration + And I follow "Site Badge" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)" @@ -170,19 +159,19 @@ Feature: Award badges @javascript Scenario: Award course badge - Given I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - And I set the field "type" to "Manual issue by role" - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + Given the following "core_badges > Badge" exists: + | name | Course Badge | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | active | + | type | 2 | + And the following "core_badges > Criteria" exists: + | badge | Course Badge | + | role | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Student 2 (student2@example.com)" @@ -202,20 +191,22 @@ Feature: Award badges @javascript Scenario: Award badge on activity completion - Given I log in as "teacher1" - And I am on "Course 1" course homepage - And I change window size to "large" - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" + Given the following "core_badges > Badge" exists: + | name | Course Badge | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | 0 | + | type | 2 | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge" + And I select "Criteria" from the "jump" singleselect And I set the field "type" to "Activity completion" And I set the field "Test assignment name" to "1" And I press "Save" And I press "Enable access" - When I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I log out And I log in as "student1" And I follow "Profile" in the user menu @@ -236,25 +227,28 @@ Feature: Award badges | section | 1 | | completion | 2 | | completionview | 1 | - And I log in as "teacher1" - And I am on "Course 1" course homepage + Given the following "core_badges > Badge" exists: + | name | Course Badge | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | 0 | + | type | 2 | + And I am on the "Course 1" "course" page logged in as "teacher1" And I navigate to "Course completion" in current page administration And I set the field "id_overall_aggregation" to "2" And I click on "Condition: Activity completion" "link" And I set the field "Assignment - Music history" to "1" And I press "Save changes" And I am on "Course 1" course homepage - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge" + And I select "Criteria" from the "jump" singleselect And I set the field "type" to "Course completion" And I set the field with xpath ".//*[contains(., 'Minimum grade required')]/ancestor::*[contains(concat(' ', @class, ' '), ' fitem ')]//input[1]" to "0" And I press "Save" And I press "Enable access" - When I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I log out And I log in as "student1" And I follow "Profile" in the user menu @@ -276,23 +270,19 @@ Feature: Award badges @javascript Scenario: All of the selected roles can award badges - Given I log in as "teacher1" - And I am on "Course 1" course homepage - # Create course badge 1. - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge 1 | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - And I set the field "type" to "Manual issue by role" - And I expand all fieldsets - # Set to ANY of the roles awards badge. - And I set the field "Teacher" to "1" - And I set the field "Any of the selected roles awards the badge" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + Given the following "core_badges > Badge" exists: + | name | Course Badge 1 | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | active | + | type | 2 | + And the following "core_badges > Criteria" exists: + | badge | Course Badge 1 | + | role | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge 1" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" # Award course badge 1 to student 1. @@ -304,13 +294,16 @@ Feature: Award badges And I select "Recipients (1)" from the "jump" singleselect Then I should see "Recipients (1)" # Add course badge 2. - And I am on "Course 1" course homepage - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge 2 | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" + Given the following "core_badges > Badge" exists: + | name | Course Badge 2 | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | 0 | + | type | 2 | + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge 2" + And I select "Criteria" from the "jump" singleselect And I set the field "type" to "Manual issue by role" And I expand all fieldsets # Set to ALL of the selected roles award badge. @@ -318,7 +311,7 @@ Feature: Award badges And I set the field "All of the selected roles award the badge" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" # Award course badge 2 to student 2. @@ -347,19 +340,19 @@ Feature: Award badges @javascript Scenario: Revoke badge - Given I log in as "teacher1" - And I am on "Course 1" course homepage - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - And I set the field "type" to "Manual issue by role" - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + Given the following "core_badges > Badge" exists: + | name | Course Badge | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | active | + | type | 2 | + And the following "core_badges > Criteria" exists: + | badge | Course Badge | + | role | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Student 2 (student2@example.com)" diff --git a/badges/tests/behat/award_badge_groups.feature b/badges/tests/behat/award_badge_groups.feature index 8dfbe061692..798787636eb 100644 --- a/badges/tests/behat/award_badge_groups.feature +++ b/badges/tests/behat/award_badge_groups.feature @@ -13,7 +13,7 @@ Feature: Award badges with separate groups | student2 | Student | 2 | student2@example.com | And the following "courses" exist: | fullname | shortname | category | groupmode | - | Course 1 | C1 | 0 | 1 | + | Course 1 | C1 | 0 | 1 | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | @@ -30,16 +30,17 @@ Feature: Award badges with separate groups | teacher1 | CB | | student2 | CA | | teacher2 | CA | - And I am on the "Course 1" "course editing" page logged in as "teacher1" - And I expand all fieldsets - And I set the field "Group mode" to "Separate groups" - And I press "Save and display" - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | Name | Course Badge | - | Description | Course badge description | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" + And the following "core_badges > Badge" exists: + | name | Course Badge | + | course | C1 | + | description | Course badge description | + | image | badges/tests/behat/badge.png | + | status | 0 | + | type | 2 | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Course Badge" + And I select "Criteria" from the "jump" singleselect And I set the field "type" to "Manual issue by role" And I expand all fieldsets And I set the field "Teacher" to "1" @@ -48,8 +49,7 @@ Feature: Award badges with separate groups And I set the field "Any of the selected roles awards the badge" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" - And I log out + And I click on "Enable" "button" in the "Confirm" "dialogue" @javascript Scenario: Award course badge as non-editing teacher with only one group diff --git a/badges/tests/behat/badge_navigation.feature b/badges/tests/behat/badge_navigation.feature index a057b29e55a..7d80f81a42d 100644 --- a/badges/tests/behat/badge_navigation.feature +++ b/badges/tests/behat/badge_navigation.feature @@ -86,7 +86,7 @@ Feature: Test tertiary navigation as various users And I navigate to "Badges" in current page administration And I click on "Manage badges" "button" And I press "Enable access" action in the "Testing course badge" report row - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I log out # Now student should see the Badges link. And I am on the "C1" "Course" page logged in as "student1" diff --git a/badges/tests/behat/criteria_activity.feature b/badges/tests/behat/criteria_activity.feature index 81459ae7609..0d9f8818b01 100644 --- a/badges/tests/behat/criteria_activity.feature +++ b/badges/tests/behat/criteria_activity.feature @@ -59,7 +59,7 @@ Feature: Award badges based on activity completion And I set the field "Quiz - Test quiz name 1" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I should see "Recipients (0)" # Pass grade for student1. Activity is considered complete because student1 got a passing grade. And user "student1" has attempted "Test quiz name 1" with responses: @@ -85,7 +85,7 @@ Feature: Award badges based on activity completion And I set the field "Quiz - Test quiz name 2" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Pass grade for student1. And user "student1" has attempted "Test quiz name 2" with responses: | slot | response | @@ -119,7 +119,7 @@ Feature: Award badges based on activity completion And I press "Save" # Enable badge access once students have completed the activity. When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Only student1 should earn the badge because student2 did not pass the quiz. Then I should see "Recipients (1)" And I select "Recipients (1)" from the "jump" singleselect diff --git a/badges/tests/behat/criteria_cohort.feature b/badges/tests/behat/criteria_cohort.feature index 2670408553e..5fc5504a2e2 100644 --- a/badges/tests/behat/criteria_cohort.feature +++ b/badges/tests/behat/criteria_cohort.feature @@ -31,7 +31,7 @@ Feature: Award badges based on cohort And I set the field "id_cohort_cohorts" to "One Cohort" And I press "Save" And I press "Enable access" - When I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" Then I should see "Recipients (1)" And I log out And I log in as "user1" @@ -70,7 +70,7 @@ Feature: Award badges based on cohort And I set the field "id_agg_1" to "1" And I press "Save" When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" Then I should see "Recipients (1)" And I log out And I log in as "user1" @@ -110,7 +110,7 @@ Feature: Award badges based on cohort And I set the field "id_cohort_cohorts" to "One Cohort" And I press "Save" When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" Then I should see "Recipients (2)" And I log out And I log in as "user1" @@ -153,7 +153,7 @@ Feature: Award badges based on cohort And I set the field "Any of the selected roles awards the badge" to "1" And I press "Save" When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "First User (first@example.com)" @@ -207,7 +207,7 @@ Feature: Award badges based on cohort And I press "Save" And I set the field "update" to "Any" When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I select "Recipients (1)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "First User (first@example.com)" @@ -266,7 +266,7 @@ Feature: Award badges based on cohort And I press "Save" And I set the field "update" to "Any" When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I select "Recipients (1)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "First User (first@example.com)" @@ -327,7 +327,7 @@ Feature: Award badges based on cohort And I press "Save" And I set the field "update" to "All" When I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "First User (first@example.com)" @@ -378,7 +378,7 @@ Feature: Award badges based on cohort And I set the field "id_cohort_cohorts" to "One Cohort" And I press "Save" And I press "Enable access" - When I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I should see "Recipients (1)" And I navigate to "Badges > Manage badges" in site administration And I press "Edit" action in the "Site Badge 2" report row @@ -387,7 +387,7 @@ Feature: Award badges based on cohort And I set the field "id_cohort_cohorts" to "Two Cohort" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" Then I should see "Recipients (2)" And I log out And I log in as "user1" @@ -436,8 +436,8 @@ Feature: Award badges based on cohort And I set the field "id_cohort_cohorts" to "One Cohort,Two Cohort" And I set the field "id_agg_1" to "1" And I press "Save" - And I press "Enable access" - When I press "Continue" + When I press "Enable access" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I should see "Recipients (1)" And I navigate to "Badges > Manage badges" in site administration And I press "Edit" action in the "Site Badge 2" report row @@ -448,7 +448,7 @@ Feature: Award badges based on cohort And I set the field "id_agg_1" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I should see "Recipients (1)" And I log out And I log in as "user1" diff --git a/badges/tests/behat/criteria_competency.feature b/badges/tests/behat/criteria_competency.feature index 2404932b309..778468a4ede 100644 --- a/badges/tests/behat/criteria_competency.feature +++ b/badges/tests/behat/criteria_competency.feature @@ -59,7 +59,7 @@ Feature: Award badges based on competency completion And I wait until the page is ready # Enable the badge And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Rate the competency in the course And I am on "Course 1" course homepage And I navigate to "Competencies" in current page administration @@ -112,7 +112,7 @@ Feature: Award badges based on competency completion # Enable the badge And I wait until the page is ready And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Rate the competency in the course And I am on "Course 1" course homepage And I navigate to "Competencies" in current page administration @@ -167,7 +167,7 @@ Feature: Award badges based on competency completion # Enable the badge And I wait until the page is ready And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Rate the competency in the course And I am on "Course 1" course homepage And I navigate to "Competencies" in current page administration diff --git a/badges/tests/behat/criteria_profile.feature b/badges/tests/behat/criteria_profile.feature index a3ce8b55fc7..a3a5d90c2a5 100644 --- a/badges/tests/behat/criteria_profile.feature +++ b/badges/tests/behat/criteria_profile.feature @@ -22,7 +22,7 @@ Feature: Award badges based on user profile field And I set the field "id_field_picture" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I log out When I log in as "user1" And I follow "Profile" in the user menu diff --git a/badges/tests/behat/manage_badges.feature b/badges/tests/behat/manage_badges.feature index 072fb9b55bc..a4e5f1c6c64 100644 --- a/badges/tests/behat/manage_badges.feature +++ b/badges/tests/behat/manage_badges.feature @@ -77,14 +77,14 @@ Feature: Manage badges And I press "Save" And I navigate to "Badges > Manage badges" in site administration And I press "Enable access" action in the "Badge #1" report row - And I should see "Changes in badge access" - And I press "Continue" - And I should see "Access to the badges was successfully enabled" + And I should see "This will make your badge visible to users and allow them to start earning it." + And I click on "Enable" "button" in the "Confirm" "dialogue" + And I should see "Access to badge 'Badge #1' enabled" Then the following should exist in the "reportbuilder-table" table: | Name | Badge status | | Badge #1 | Available | And I press "Disable access" action in the "Badge #1" report row - And I should see "Access to the badges was successfully disabled" + And I should see "Access to badge 'Badge #1' disabled" And the following should exist in the "reportbuilder-table" table: | Name | Badge status | | Badge #1 | Not available | @@ -99,7 +99,7 @@ Feature: Manage badges And I press "Save" And I navigate to "Badges > Manage badges" in site administration And I press "Enable access" action in the "Badge #1" report row - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I press "Award badge" action in the "Badge #1" report row And I set the field "potentialrecipients[]" to "Admin User (moodle@example.com)" And I press "Award badge" diff --git a/badges/tests/behat/nobadge_navigation.feature b/badges/tests/behat/nobadge_navigation.feature index 714062d974d..119e2d9298c 100644 --- a/badges/tests/behat/nobadge_navigation.feature +++ b/badges/tests/behat/nobadge_navigation.feature @@ -52,7 +52,7 @@ Feature: Manage badges is not shown when there are no existing badges. And I should not see "Testing course badge" And I click on "Manage badges" "button" And I press "Enable access" action in the "Testing course badge" report row - And I click on "Continue" "button" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I should see "Testing course badge" And I click on "Back" "button" And "Manage badges" "button" should exist @@ -92,7 +92,7 @@ Feature: Manage badges is not shown when there are no existing badges. And I navigate to "Badges" in current page administration And I click on "Manage badges" "button" And I press "Enable access" action in the "Testing course badge" report row - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" And I log out # Now student should see the Badges link. And I am on the "C1" "Course" page logged in as "student1" diff --git a/badges/tests/behat/view_badge.feature b/badges/tests/behat/view_badge.feature index 2a82efa3efa..adac0083adf 100644 --- a/badges/tests/behat/view_badge.feature +++ b/badges/tests/behat/view_badge.feature @@ -9,26 +9,26 @@ Feature: Display badges | username | firstname | lastname | email | | student1 | Student | 1 | student1@example.com | # Create system badge and define a criterion. + Given the following "core_badges > Badge" exists: + | name | Testing system badge | + | description | Testing system badge description | + | image | badges/tests/behat/badge.png | + | version | 1.1 | + | status | 0 | + | type | 1 | + | language | ca | + And the following "core_badges > Criteria" exists: + | badge | Testing system badge | + | role | editingteacher | And I log in as "admin" - And I navigate to "Badges > Add a new badge" in site administration - And I set the following fields to these values: - | Name | Testing system badge | - | Version | 1.1 | - | Language | Catalan | - | Description | Testing system badge description | - | Image author | http://author.example.com | - | Image caption | Test caption image | - And I upload "badges/tests/behat/badge.png" file to "Image" filemanager - And I press "Create badge" - And I set the field "type" to "Manual issue by role" - And I expand all fieldsets - And I set the field "Teacher" to "1" - And I press "Save" + And I navigate to "Badges > Manage badges" in site administration + And I follow "Testing system badge" + And I select "Criteria" from the "jump" singleselect Scenario: Display badge without expired date # Enable the badge. Given I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Award badge to student1. And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" @@ -53,7 +53,7 @@ Feature: Display badges And I set the field "id_field_firstname" to "1" And I press "Save" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Award badge to student1. And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" @@ -81,7 +81,7 @@ Feature: Display badges And I press "Save" And I set the field "update" to "2" And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Check badge details are displayed. And I select "Recipients (2)" from the "jump" singleselect And I press "View issued badge" action in the "Student 1" report row @@ -101,8 +101,10 @@ Feature: Display badges When I click on "Relative date" "radio" And I set the field "expireperiod[number]" to "1" And I press "Save changes" + And I should see "Changes saved" + And I select "Overview" from the "jump" singleselect And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Award badge to student1. And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" @@ -123,8 +125,10 @@ Feature: Display badges And I set the field "expireperiod[timeunit]" to "1" And I set the field "expireperiod[number]" to "1" And I press "Save changes" + And I should see "Changes saved" + And I select "Overview" from the "jump" singleselect And I press "Enable access" - And I press "Continue" + And I click on "Enable" "button" in the "Confirm" "dialogue" # Award badge to student1. And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" diff --git a/badges/tests/external/disable_badges_test.php b/badges/tests/external/disable_badges_test.php new file mode 100644 index 00000000000..397dc6f2a0c --- /dev/null +++ b/badges/tests/external/disable_badges_test.php @@ -0,0 +1,224 @@ +. + +namespace core_badges\external; + +use core_badges_generator; +use core_badges\badge; +use externallib_advanced_testcase; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/webservice/tests/helpers.php'); +require_once($CFG->libdir . '/badgeslib.php'); + +/** + * Tests for external function disable_badges. + * + * @package core_badges + * @copyright 2024 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 4.5 + * @covers \core_badges\external\disable_badges + */ +final class disable_badges_test extends externallib_advanced_testcase { + + /** + * Test execute method. + */ + public function test_execute(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + + $this->assertTrue($data['sitebadge']->is_active()); + $this->assertTrue($data['coursebadge']->is_active()); + + $result = disable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result); + $this->assertTrue($result['result']); + $this->assertEmpty($result['warnings']); + + $sitebadge = new badge($data['sitebadge']->id); + $coursebadge = new badge($data['coursebadge']->id); + $this->assertFalse($sitebadge->is_active()); + $this->assertFalse($coursebadge->is_active()); + } + + /** + * Test execute method when badges are disabled. + */ + public function test_execute_badgesdisabled(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + // Disable course badges. + set_config('enablebadges', 0); + + $data = $this->prepare_test_data(); + + $this->expectException(\moodle_exception::class); + $this->expectExceptionMessage(get_string('badgesdisabled', 'core_badges')); + $result = disable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result); + } + + /** + * Test execute method when course badges are disabled. + */ + public function test_execute_coursebadgesdisabled(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + // Disable course badges. + set_config('badges_allowcoursebadges', 0); + + $data = $this->prepare_test_data(); + + $this->assertTrue($data['sitebadge']->is_active()); + $this->assertTrue($data['coursebadge']->is_active()); + + $result = disable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result); + // Course badge can't be disabled because course badges are disabled. + $this->assertFalse($result['result']); + $this->assertNotEmpty($result['warnings']); + $this->assertEquals($data['coursebadge']->id, $result['warnings'][0]['item']); + $this->assertEquals('coursebadgesdisabled', $result['warnings'][0]['warningcode']); + + $sitebadge = new badge($data['sitebadge']->id); + $coursebadge = new badge($data['coursebadge']->id); + $this->assertFalse($sitebadge->is_active()); + $this->assertTrue($coursebadge->is_active()); + } + + /** + * Test execute method when the user doesn't have the capability to disable badges. + */ + public function test_execute_without_capability(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + $this->setUser($data['teacher']); + + $this->assertTrue($data['sitebadge']->is_active()); + $this->assertTrue($data['coursebadge']->is_active()); + + $result = disable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result); + // Teacher doesn't have capability to disable site badges. + $this->assertFalse($result['result']); + $this->assertNotEmpty($result['warnings']); + $this->assertEquals($data['sitebadge']->id, $result['warnings'][0]['item']); + $this->assertEquals('nopermissions', $result['warnings'][0]['warningcode']); + + $sitebadge = new badge($data['sitebadge']->id); + $coursebadge = new badge($data['coursebadge']->id); + $this->assertTrue($sitebadge->is_active()); + $this->assertFalse($coursebadge->is_active()); + } + + /** + * Test execute method when the badge is already disabled. + */ + public function test_execute_disabledisabledbadge(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + + $this->assertTrue($data['coursebadge']->is_active()); + $data['coursebadge']->set_status(BADGE_STATUS_INACTIVE); + $this->assertFalse($data['coursebadge']->is_active()); + + $result = disable_badges::execute([ + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result); + // Disabled badges can be disabled again. + $this->assertTrue($result['result']); + $this->assertEmpty($result['warnings']); + + $coursebadge = new badge($data['coursebadge']->id); + $this->assertFalse($coursebadge->is_active()); + } + + /** + * Prepare the test, creating a few users and badges. + * + * @return array Test data. + */ + private function prepare_test_data(): array { + global $DB; + + // Setup test data. + $course = $this->getDataGenerator()->create_course(); + + // Create users and enrolments. + $student1 = $this->getDataGenerator()->create_and_enrol($course); + $student2 = $this->getDataGenerator()->create_and_enrol($course); + $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + + /** @var core_badges_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_badges'); + $sitebadge = $generator->create_badge([ + 'name' => 'Site badge', + 'description' => 'Site badge', + 'status' => BADGE_STATUS_ACTIVE, + ]); + $coursebadge = $generator->create_badge([ + 'name' => 'Course badge', + 'description' => 'Course badge', + 'type' => BADGE_TYPE_COURSE, + 'courseid' => $course->id, + 'status' => BADGE_STATUS_ACTIVE, + ]); + + // Create criteria for manually awarding by role. + $managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']); + $generator->create_criteria(['badgeid' => $sitebadge->id, 'roleid' => $managerrole]); + $generator->create_criteria(['badgeid' => $coursebadge->id, 'roleid' => $managerrole]); + + // Issue badges to student1. + $sitebadge->issue($student1->id, true); + $coursebadge->issue($student1->id, true); + + return [ + 'course' => $course, + 'student1' => $student1, + 'student2' => $student2, + 'teacher' => $teacher, + 'sitebadge' => $sitebadge, + 'coursebadge' => $coursebadge, + ]; + } +} diff --git a/badges/tests/external/enable_badges_test.php b/badges/tests/external/enable_badges_test.php new file mode 100644 index 00000000000..891ac305bd6 --- /dev/null +++ b/badges/tests/external/enable_badges_test.php @@ -0,0 +1,312 @@ +. + +namespace core_badges\external; + +use core_badges_generator; +use core_badges\badge; +use externallib_advanced_testcase; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/webservice/tests/helpers.php'); +require_once($CFG->libdir . '/badgeslib.php'); + +/** + * Tests for external function enable_badges. + * + * @package core_badges + * @copyright 2024 Sara Arjona + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 4.5 + * @covers \core_badges\external\enable_badges + */ +final class enable_badges_test extends externallib_advanced_testcase { + + /** + * Test execute method. + */ + public function test_execute(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + + $this->assertFalse($data['sitebadge']->is_active()); + $this->assertFalse($data['coursebadge']->is_active()); + + $result = enable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + $this->assertEquals($data['sitebadge']->id, $result['result'][0]['badgeid']); + $this->assertEquals($data['coursebadge']->id, $result['result'][1]['badgeid']); + $this->assertEmpty($result['warnings']); + + $sitebadge = new badge($data['sitebadge']->id); + $coursebadge = new badge($data['coursebadge']->id); + $this->assertTrue($sitebadge->is_active()); + $this->assertTrue($coursebadge->is_active()); + } + + /** + * Test execute method when badges are disabled. + */ + public function test_execute_badgesdisabled(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + // Disable course badges. + set_config('enablebadges', 0); + + $data = $this->prepare_test_data(); + + $this->expectException(\moodle_exception::class); + $this->expectExceptionMessage(get_string('badgesdisabled', 'core_badges')); + $result = enable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + } + + /** + * Test execute method when course badges are disabled. + */ + public function test_execute_coursebadgesdisabled(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + // Disable course badges. + set_config('badges_allowcoursebadges', 0); + + $data = $this->prepare_test_data(); + + $this->assertFalse($data['sitebadge']->is_active()); + $this->assertFalse($data['coursebadge']->is_active()); + + $result = enable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + $this->assertEquals($data['sitebadge']->id, $result['result'][0]['badgeid']); + // Course badge can't be enabled because course badges are disabled. + $this->assertNotEmpty($result['warnings']); + $this->assertEquals($data['coursebadge']->id, $result['warnings'][0]['item']); + $this->assertEquals('coursebadgesdisabled', $result['warnings'][0]['warningcode']); + + $sitebadge = new badge($data['sitebadge']->id); + $coursebadge = new badge($data['coursebadge']->id); + $this->assertTrue($sitebadge->is_active()); + $this->assertFalse($coursebadge->is_active()); + } + + /** + * Test execute method when badge doesn't have criteria. + */ + public function test_execute_badgewithoutcriteria(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + + $this->assertFalse($data['nocriteriabadge']->has_criteria()); + $this->assertFalse($data['nocriteriabadge']->is_active()); + + $result = enable_badges::execute([ + $data['nocriteriabadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + $this->assertEmpty($result['result']); + // Badges without criteria can't be enabled. + $this->assertNotEmpty($result['warnings']); + $this->assertEquals($data['nocriteriabadge']->id, $result['warnings'][0]['item']); + $this->assertEquals('nocriteria', $result['warnings'][0]['warningcode']); + + $nocriteriabadge = new badge($data['nocriteriabadge']->id); + $this->assertFalse($nocriteriabadge->is_active()); + } + + /** + * Test execute method when the badge is already enabled. + */ + public function test_execute_enableenabledbadge(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + + $this->assertFalse($data['coursebadge']->is_active()); + $data['coursebadge']->set_status(BADGE_STATUS_ACTIVE); + $this->assertTrue($data['coursebadge']->is_active()); + + $result = enable_badges::execute([ + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + $this->assertEquals($data['coursebadge']->id, $result['result'][0]['badgeid']); + // Enabled badges can be enabled again. + $this->assertEmpty($result['warnings']); + + $coursebadge = new badge($data['coursebadge']->id); + $this->assertTrue($coursebadge->is_active()); + } + + /** + * Test execute method when badgeid doesn't exist. + */ + public function test_execute_wrongbadgeid(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $badgeid = 1234; + $this->expectException(\moodle_exception::class); + $this->expectExceptionMessage(get_string('error:nosuchbadge', 'core_badges', $badgeid)); + $result = enable_badges::execute([ + $badgeid, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + } + + /** + * Test execute method when the user doesn't have the capability to enable badges. + */ + public function test_execute_without_capability(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + $this->setUser($data['teacher']); + + $this->assertFalse($data['sitebadge']->is_active()); + $this->assertFalse($data['coursebadge']->is_active()); + + $result = enable_badges::execute([ + $data['sitebadge']->id, + $data['coursebadge']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + $this->assertEquals($data['coursebadge']->id, $result['result'][0]['badgeid']); + // Teacher doesn't have capability to enable site badges. + $this->assertNotEmpty($result['warnings']); + $this->assertEquals($data['sitebadge']->id, $result['warnings'][0]['item']); + $this->assertEquals('nopermissions', $result['warnings'][0]['warningcode']); + + $sitebadge = new badge($data['sitebadge']->id); + $coursebadge = new badge($data['coursebadge']->id); + $this->assertFalse($sitebadge->is_active()); + $this->assertTrue($coursebadge->is_active()); + } + + /** + * Test execute method when the badge has the same name as another enabled badge. + */ + public function test_execute_duplicatedname(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $data = $this->prepare_test_data(); + + $this->assertFalse($data['coursebadge']->is_active()); + $this->assertFalse($data['coursebadge2']->is_active()); + + $result = enable_badges::execute([ + $data['coursebadge']->id, + $data['coursebadge2']->id, + ]); + $result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result); + // Badge can be enabled because badges with the same name are now allowed. + $this->assertEquals($data['coursebadge']->id, $result['result'][0]['badgeid']); + $this->assertEquals($data['coursebadge2']->id, $result['result'][1]['badgeid']); + $this->assertEmpty($result['warnings']); + + $coursebadge = new badge($data['coursebadge']->id); + $coursebadge2 = new badge($data['coursebadge2']->id); + $this->assertTrue($coursebadge->is_active()); + $this->assertTrue($coursebadge2->is_active()); + } + + /** + * Prepare the test, creating a few users and badges. + * + * @return array Test data. + */ + private function prepare_test_data(): array { + global $DB; + + // Setup test data. + $course = $this->getDataGenerator()->create_course(); + + // Create users and enrolments. + $student1 = $this->getDataGenerator()->create_and_enrol($course); + $student2 = $this->getDataGenerator()->create_and_enrol($course); + $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + + /** @var core_badges_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_badges'); + $sitebadge = $generator->create_badge([ + 'name' => 'Site badge', + 'description' => 'Site badge', + 'status' => BADGE_STATUS_INACTIVE, + ]); + $coursebadge = $generator->create_badge([ + 'name' => 'Course badge', + 'description' => 'Course badge', + 'type' => BADGE_TYPE_COURSE, + 'courseid' => $course->id, + 'status' => BADGE_STATUS_INACTIVE, + ]); + $coursebadge2 = $generator->create_badge([ + 'name' => 'Course badge', + 'description' => 'Course badge', + 'type' => BADGE_TYPE_COURSE, + 'courseid' => $course->id, + 'status' => BADGE_STATUS_INACTIVE, + ]); + $nocriteriabadge = $generator->create_badge([ + 'name' => 'No criteria badge', + 'description' => 'No criteria badge', + 'type' => BADGE_TYPE_COURSE, + 'courseid' => $course->id, + 'status' => BADGE_STATUS_INACTIVE, + ]); + + // Create criteria for manually awarding by role. + $managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']); + $generator->create_criteria(['badgeid' => $sitebadge->id, 'roleid' => $managerrole]); + $generator->create_criteria(['badgeid' => $coursebadge->id, 'roleid' => $managerrole]); + $generator->create_criteria(['badgeid' => $coursebadge2->id, 'roleid' => $managerrole]); + + // Issue badges to student1. + $sitebadge->issue($student1->id, true); + $coursebadge->issue($student1->id, true); + + return [ + 'course' => $course, + 'student1' => $student1, + 'student2' => $student2, + 'teacher' => $teacher, + 'sitebadge' => $sitebadge, + 'coursebadge' => $coursebadge, + 'coursebadge2' => $coursebadge2, + 'nocriteriabadge' => $nocriteriabadge, + ]; + } +} diff --git a/blocks/badges/tests/behat/block_badges_course.feature b/blocks/badges/tests/behat/block_badges_course.feature index 5cdacf20f67..59869476631 100644 --- a/blocks/badges/tests/behat/block_badges_course.feature +++ b/blocks/badges/tests/behat/block_badges_course.feature @@ -14,37 +14,25 @@ Feature: Enable Block Badges in a course And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | - And I log in as "teacher1" - And I am on "Course 1" course homepage - # Issue badge 1 of 2 - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | id_name | Badge 1 | - | id_description | Badge 1 | - And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager - And I press "Create badge" - And I select "Manual issue by role" from the "Add badge criteria" singleselect - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + And the following "core_badges > Badges" exist: + | name | course | description | image | status | type | + | Badge 1 | C1 | Badge 1 | badges/tests/behat/badge.png | active | 2 | + | Badge 2 | C1 | Badge 2 | badges/tests/behat/badge.png | active | 2 | + And the following "core_badges > Criterias" exist: + | badge | role | + | Badge 1 | editingteacher | + | Badge 2 | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Badge 1" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)" And I press "Award badge" # Issue Badge 2 of 2 And I am on "Course 1" course homepage - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | id_name | Badge 2 | - | id_description | Badge 2 | - And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager - And I press "Create badge" - And I select "Manual issue by role" from the "Add badge criteria" singleselect - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Badge 2" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)" diff --git a/blocks/badges/tests/behat/block_badges_dashboard.feature b/blocks/badges/tests/behat/block_badges_dashboard.feature index 3c7b6c34f61..c7251dc7bc8 100644 --- a/blocks/badges/tests/behat/block_badges_dashboard.feature +++ b/blocks/badges/tests/behat/block_badges_dashboard.feature @@ -17,20 +17,19 @@ Feature: Enable Block Badges on the dashboard and view awarded badges And the following "blocks" exist: | blockname | contextlevel | reference | pagetypepattern | defaultregion | | badges | System | 1 | my-index | side-post | - And I log in as "teacher1" - And I am on "Course 1" course homepage - # Issue badge 1 of 2 - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | id_name | Badge 1 | - | id_description | Badge 1 | - And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager - And I press "Create badge" - And I select "Manual issue by role" from the "Add badge criteria" singleselect - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + And the following "core_badges > Badge" exists: + | name | Badge 1 | + | course | C1 | + | description | Badge 1 | + | image | badges/tests/behat/badge.png | + | status | active | + | type | 2 | + And the following "core_badges > Criteria" exists: + | badge | Badge 1 | + | role | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Badge 1" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)" diff --git a/blocks/badges/tests/behat/block_badges_frontpage.feature b/blocks/badges/tests/behat/block_badges_frontpage.feature index f5710414887..e2e113dabc0 100644 --- a/blocks/badges/tests/behat/block_badges_frontpage.feature +++ b/blocks/badges/tests/behat/block_badges_frontpage.feature @@ -17,19 +17,19 @@ Feature: Enable Block Badges on the frontpage and view awarded badges And the following "blocks" exist: | blockname | contextlevel | reference | pagetypepattern | defaultregion | | badges | System | 1 | site-index | side-pre | - And I am on the "Course 1" course page logged in as teacher1 - # Issue badge 1 of 2 - And I navigate to "Badges > Add a new badge" in current page administration - And I set the following fields to these values: - | id_name | Badge 1 | - | id_description | Badge 1 | - And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager - And I press "Create badge" - And I select "Manual issue by role" from the "Add badge criteria" singleselect - And I set the field "Teacher" to "1" - And I press "Save" - And I press "Enable access" - And I press "Continue" + And the following "core_badges > Badge" exists: + | name | Badge 1 | + | course | C1 | + | description | Badge 1 | + | image | badges/tests/behat/badge.png | + | status | active | + | type | 2 | + And the following "core_badges > Criteria" exists: + | badge | Badge 1 | + | role | editingteacher | + And I am on the "Course 1" "course" page logged in as "teacher1" + And I navigate to "Badges > Manage badges" in current page administration + And I follow "Badge 1" And I select "Recipients (0)" from the "jump" singleselect And I press "Award badge" And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)" diff --git a/lang/en/badges.php b/lang/en/badges.php index eb7686e4622..83a5b9a0bf0 100644 --- a/lang/en/badges.php +++ b/lang/en/badges.php @@ -26,7 +26,7 @@ $string['actions'] = 'Actions'; $string['activate'] = 'Enable access'; -$string['activatesuccess'] = 'Access to the badges was successfully enabled.'; +$string['activatesuccess'] = 'Access to badge \'{$a}\' enabled.'; $string['addalignment'] = 'Add external skill or standard'; $string['addbadge'] = 'Add badges'; $string['addbadge_help'] = 'Select all badges that should be added to this badge requirement. Hold CTRL key to select multiple items.'; @@ -78,7 +78,7 @@ $string['attachment_help'] = 'If enabled, an issued badge will be attached to th $string['award'] = 'Award badge'; $string['awardedto'] = 'Awarded to {$a}'; $string['awardedtoyou'] = 'Issued to me'; -$string['awardoncron'] = 'Access to the badges was successfully enabled. Too many users can instantly earn this badge. To ensure site performance, this action will take some time to process.'; +$string['awardoncron'] = 'A high number of users are being awarded the badge \'{$a->badgename}\'. It may take some time for all users to receive it.'; $string['awards'] = 'Recipients'; $string['backpackavailability'] = 'External badge verification'; $string['backpackconnectionok'] = 'Backpack connection successfully established'; @@ -272,7 +272,7 @@ $string['dateawarded'] = 'Date issued'; $string['dateearned'] = 'Date: {$a}'; $string['day'] = 'Day(s)'; $string['deactivate'] = 'Disable access'; -$string['deactivatesuccess'] = 'Access to the badges was successfully disabled.'; +$string['deactivatesuccess'] = 'Access to badge \'{$a}\' disabled.'; $string['defaultissuercontact'] = 'Badge issuer email address'; $string['defaultissuercontact_desc'] = 'An email address associated with the badge issuer. For an Open Badges v2.0 backpack, this is used for authentication when publishing badges to a backpack.'; $string['defaultissuerpassword'] = 'Badge issuer password'; @@ -296,7 +296,6 @@ $string['error:backpackdatainvalid'] = 'The data return from the backpack was in $string['error:backpackemailnotfound'] = 'The email \'{$a}\' is not associated with a backpack. You need to create a backpack for that account or sign in with another email address.'; $string['error:badgeawardnotfound'] = 'Cannot verify this awarded badge. This badge may have been revoked.'; $string['error:badgenotfound'] = 'Badge not found'; -$string['error:cannotact'] = 'Cannot activate the badge. '; $string['error:cannotawardbadge'] = 'Cannot award badge to a user.'; $string['error:cannotrevokebadge'] = 'Cannot revoke badge from a user.'; $string['error:cannotdeletecriterion'] = 'This criterion cannot be deleted. '; @@ -461,8 +460,8 @@ $string['notifydaily'] = 'Daily'; $string['notifyevery'] = 'Every time'; $string['notifymonthly'] = 'Monthly'; $string['notifyweekly'] = 'Weekly'; -$string['numawards'] = 'This badge has been issued to {$a->count} user(s).'; -$string['numawardstat'] = 'This badge has been issued {$a} user(s).'; +$string['numawards'] = 'Users awarded badge \'{$a->badgename}\': {$a->count}.'; +$string['numawardstat'] = 'Users awarded badge \'{$a->badgename}\': {$a->awards}.'; $string['overallcrit'] = 'of the selected criteria are complete.'; $string['oauth2issuer'] = 'OAuth 2 services'; $string['openbadgesv1'] = 'Open Badges v1.0'; @@ -516,7 +515,6 @@ $string['requiredcohort'] = 'At least one cohort should be added to the cohort c $string['requiredcompetency'] = 'At least one competency should be added to the competency criterion.'; $string['requiredcourse'] = 'At least one course should be added to the courseset criterion.'; $string['requiredbadge'] = 'At least one badge should be added to the badge criterion.'; -$string['reviewbadge'] = 'Changes in badge access'; $string['reviewconfirm'] = '

This will make your badge visible to users and allow them to start earning it.

It is possible that some users already meet this badge\'s criteria and will be issued this badge immediately after you enable it.

@@ -598,4 +596,6 @@ $string['backpackemail'] = 'Email address'; $string['backpackemail_help'] = 'The email address associated with your backpack. While you are connected, any badges earned on this site will be associated with this email address.'; // Deprecated since Moodle 4.5. +$string['error:cannotact'] = 'Cannot activate the badge. '; $string['error:duplicatename'] = 'Badge with such name already exists in the system.'; +$string['reviewbadge'] = 'Changes in badge access'; diff --git a/lang/en/deprecated.txt b/lang/en/deprecated.txt index ff603afa0d6..a9924fa2680 100644 --- a/lang/en/deprecated.txt +++ b/lang/en/deprecated.txt @@ -121,3 +121,5 @@ siteregistrationcontact_help,core_hub registrationcontactno,core registrationcontactyes,core error:duplicatename,core_badges +error:cannotact,core_badges +reviewbadge,core_badges diff --git a/lib/db/services.php b/lib/db/services.php index feb0ce346c4..27622ce9b9f 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -119,6 +119,18 @@ $functions = array( 'ajax' => true, 'loginrequired' => true, ), + 'core_badges_disable_badges' => [ + 'classname' => 'core_badges\external\disable_badges', + 'description' => 'Disable badges', + 'type' => 'write', + 'ajax' => true, + ], + 'core_badges_enable_badges' => [ + 'classname' => 'core_badges\external\enable_badges', + 'description' => 'Enable badges', + 'type' => 'write', + 'ajax' => true, + ], 'core_badges_get_user_badges' => array( 'classname' => 'core_badges_external', 'methodname' => 'get_user_badges',