diff --git a/mod/lti/amd/build/course_tools_list.min.js b/mod/lti/amd/build/course_tools_list.min.js index df23cfcb606..b9fab6a4486 100644 --- a/mod/lti/amd/build/course_tools_list.min.js +++ b/mod/lti/amd/build/course_tools_list.min.js @@ -1,3 +1,3 @@ -define("mod_lti/course_tools_list",["exports","core/notification","core/pending","core/ajax","core/toast","core/str","core_table/dynamic","core_table/local/dynamic/selectors"],(function(_exports,_notification,_pending,_ajax,_toast,_str,_dynamic,Selectors){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_ajax=_interopRequireDefault(_ajax),Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors);_exports.init=()=>{document.addEventListener("click",(event=>{const courseToolDelete=event.target.closest('[data-action="course-tool-delete"]');if(courseToolDelete){event.preventDefault();const deleteBodyStringId=courseToolDelete.dataset.courseToolUsage>0?"deletecoursetoolwithusageconfirm":"deletecoursetoolconfirm",requiredStrings=[{key:"deletecoursetool",component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:deleteBodyStringId,component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:"delete",component:"core",param:courseToolDelete.dataset.courseToolName},{key:"coursetooldeleted",component:"mod_lti",param:courseToolDelete.dataset.courseToolName}],triggerElement=courseToolDelete.closest(".dropdown").querySelector(".dropdown-toggle");(0,_str.getStrings)(requiredStrings).then((_ref=>{let[modalTitle,modalBody,deleteLabel]=_ref;return _notification.default.deleteCancelPromise(modalTitle,modalBody,deleteLabel,{triggerElement:triggerElement})})).then((()=>{const pendingPromise=new _pending.default("mod_lti/course_tools:delete"),request={methodname:"mod_lti_delete_course_tool_type",args:{tooltypeid:courseToolDelete.dataset.courseToolId}};return _ajax.default.call([request])[0].then((0,_toast.add)((0,_str.getString)("coursetooldeleted","mod_lti",courseToolDelete.dataset.courseToolName))).then((()=>{const tableRoot=triggerElement.closest(Selectors.main.region);return(0,_dynamic.refreshTableContent)(tableRoot)})).then(pendingPromise.resolve).catch(_notification.default.exception)})).catch((()=>{}))}}))}})); +define("mod_lti/course_tools_list",["exports","core/notification","core/pending","core/ajax","core/toast","core/str","core_table/dynamic","core_table/local/dynamic/selectors","./repository"],(function(_exports,_notification,_pending,_ajax,_toast,_str,_dynamic,Selectors,_repository){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_ajax=_interopRequireDefault(_ajax),Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors);_exports.init=()=>{document.addEventListener("click",(event=>{const courseToolDelete=event.target.closest('[data-action="course-tool-delete"]');if(courseToolDelete){event.preventDefault();const deleteBodyStringId=courseToolDelete.dataset.courseToolUsage>0?"deletecoursetoolwithusageconfirm":"deletecoursetoolconfirm",requiredStrings=[{key:"deletecoursetool",component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:deleteBodyStringId,component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:"delete",component:"core",param:courseToolDelete.dataset.courseToolName},{key:"coursetooldeleted",component:"mod_lti",param:courseToolDelete.dataset.courseToolName}],triggerElement=courseToolDelete.closest(".dropdown").querySelector(".dropdown-toggle");(0,_str.getStrings)(requiredStrings).then((_ref=>{let[modalTitle,modalBody,deleteLabel]=_ref;return _notification.default.deleteCancelPromise(modalTitle,modalBody,deleteLabel,{triggerElement:triggerElement})})).then((()=>{const pendingPromise=new _pending.default("mod_lti/course_tools:delete"),request={methodname:"mod_lti_delete_course_tool_type",args:{tooltypeid:courseToolDelete.dataset.courseToolId}};return _ajax.default.call([request])[0].then((0,_toast.add)((0,_str.getString)("coursetooldeleted","mod_lti",courseToolDelete.dataset.courseToolName))).then((()=>{const tableRoot=triggerElement.closest(Selectors.main.region);return(0,_dynamic.refreshTableContent)(tableRoot)})).then(pendingPromise.resolve).catch(_notification.default.exception)})).catch((()=>{}))}const courseShowInActivityChooser=event.target.closest('[data-action="showinactivitychooser-toggle"]');if(courseShowInActivityChooser){const showInActivityChooserStateToggle="0"===courseShowInActivityChooser.dataset.state?1:0;return(0,_repository.toggleShowInActivityChooser)(courseShowInActivityChooser.dataset.id,courseShowInActivityChooser.dataset.courseid,showInActivityChooserStateToggle)}}))}})); //# sourceMappingURL=course_tools_list.min.js.map \ No newline at end of file diff --git a/mod/lti/amd/build/course_tools_list.min.js.map b/mod/lti/amd/build/course_tools_list.min.js.map index e4ee0474cee..1d32cc4d836 100644 --- a/mod/lti/amd/build/course_tools_list.min.js.map +++ b/mod/lti/amd/build/course_tools_list.min.js.map @@ -1 +1 @@ -{"version":3,"file":"course_tools_list.min.js","sources":["../src/course_tools_list.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 * Course LTI External tools list management.\n *\n * @module mod_lti/course_tools_list\n * @copyright 2023 Jake Dallimore \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n\"use strict\";\n\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Ajax from 'core/ajax';\nimport {add as addToast} from 'core/toast';\nimport {getString, getStrings} from 'core/str';\nimport {refreshTableContent} from 'core_table/dynamic';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\n\n/**\n * Initialise module.\n */\nexport const init = () => {\n document.addEventListener('click', event => {\n\n const courseToolDelete = event.target.closest('[data-action=\"course-tool-delete\"]');\n if (courseToolDelete) {\n event.preventDefault();\n\n // A different message is used in the modal if the tool has usages within the course.\n const usage = courseToolDelete.dataset.courseToolUsage;\n const deleteBodyStringId = usage > 0 ? 'deletecoursetoolwithusageconfirm' : 'deletecoursetoolconfirm';\n const requiredStrings = [\n {key: 'deletecoursetool', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName},\n {key: deleteBodyStringId, component: 'mod_lti', param: courseToolDelete.dataset.courseToolName},\n {key: 'delete', component: 'core', param: courseToolDelete.dataset.courseToolName},\n {key: 'coursetooldeleted', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName}\n ];\n // Use triggerElement to return focus to the action menu toggle.\n const triggerElement = courseToolDelete.closest('.dropdown').querySelector('.dropdown-toggle');\n\n getStrings(requiredStrings).then(([modalTitle, modalBody, deleteLabel]) => {\n return Notification.deleteCancelPromise(\n modalTitle,\n modalBody,\n deleteLabel,\n {triggerElement});\n }).then(() => {\n const pendingPromise = new Pending('mod_lti/course_tools:delete');\n\n const request = {\n methodname: 'mod_lti_delete_course_tool_type',\n args: {tooltypeid: courseToolDelete.dataset.courseToolId}\n };\n return Ajax.call([request])[0]\n .then(addToast(getString('coursetooldeleted', 'mod_lti', courseToolDelete.dataset.courseToolName)))\n .then(() => {\n const tableRoot = triggerElement.closest(Selectors.main.region);\n return refreshTableContent(tableRoot);\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n }).catch(() => {\n return;\n });\n }\n });\n};\n"],"names":["document","addEventListener","event","courseToolDelete","target","closest","preventDefault","deleteBodyStringId","dataset","courseToolUsage","requiredStrings","key","component","param","courseToolName","triggerElement","querySelector","then","_ref","modalTitle","modalBody","deleteLabel","Notification","deleteCancelPromise","pendingPromise","Pending","request","methodname","args","tooltypeid","courseToolId","Ajax","call","tableRoot","Selectors","main","region","resolve","catch","exception"],"mappings":"o+CAoCoB,KAChBA,SAASC,iBAAiB,SAASC,cAEzBC,iBAAmBD,MAAME,OAAOC,QAAQ,yCAC1CF,iBAAkB,CAClBD,MAAMI,uBAIAC,mBADQJ,iBAAiBK,QAAQC,gBACJ,EAAI,mCAAqC,0BACtEC,gBAAkB,CACpB,CAACC,IAAK,mBAAoBC,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,gBAChF,CAACH,IAAKJ,mBAAoBK,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,gBAChF,CAACH,IAAK,SAAUC,UAAW,OAAQC,MAAOV,iBAAiBK,QAAQM,gBACnE,CAACH,IAAK,oBAAqBC,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,iBAG/EC,eAAiBZ,iBAAiBE,QAAQ,aAAaW,cAAc,wCAEhEN,iBAAiBO,MAAKC,WAAEC,WAAYC,UAAWC,yBAC/CC,sBAAaC,oBAChBJ,WACAC,UACAC,YACA,CAACN,eAAAA,oBACNE,MAAK,WACEO,eAAiB,IAAIC,iBAAQ,+BAE7BC,QAAU,CACZC,WAAY,kCACZC,KAAM,CAACC,WAAY1B,iBAAiBK,QAAQsB,sBAEzCC,cAAKC,KAAK,CAACN,UAAU,GACvBT,MAAK,eAAS,kBAAU,oBAAqB,UAAWd,iBAAiBK,QAAQM,kBACjFG,MAAK,WACIgB,UAAYlB,eAAeV,QAAQ6B,UAAUC,KAAKC,eACjD,gCAAoBH,cAE9BhB,KAAKO,eAAea,SACpBC,MAAMhB,sBAAaiB,cACzBD,OAAM"} \ No newline at end of file +{"version":3,"file":"course_tools_list.min.js","sources":["../src/course_tools_list.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 * Course LTI External tools list management.\n *\n * @module mod_lti/course_tools_list\n * @copyright 2023 Jake Dallimore \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n\"use strict\";\n\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Ajax from 'core/ajax';\nimport {add as addToast} from 'core/toast';\nimport {getString, getStrings} from 'core/str';\nimport {refreshTableContent} from 'core_table/dynamic';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\nimport {toggleShowInActivityChooser} from \"./repository\";\n\n/**\n * Initialise module.\n */\nexport const init = () => {\n document.addEventListener('click', event => {\n\n const courseToolDelete = event.target.closest('[data-action=\"course-tool-delete\"]');\n if (courseToolDelete) {\n event.preventDefault();\n\n // A different message is used in the modal if the tool has usages within the course.\n const usage = courseToolDelete.dataset.courseToolUsage;\n const deleteBodyStringId = usage > 0 ? 'deletecoursetoolwithusageconfirm' : 'deletecoursetoolconfirm';\n const requiredStrings = [\n {key: 'deletecoursetool', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName},\n {key: deleteBodyStringId, component: 'mod_lti', param: courseToolDelete.dataset.courseToolName},\n {key: 'delete', component: 'core', param: courseToolDelete.dataset.courseToolName},\n {key: 'coursetooldeleted', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName}\n ];\n // Use triggerElement to return focus to the action menu toggle.\n const triggerElement = courseToolDelete.closest('.dropdown').querySelector('.dropdown-toggle');\n\n getStrings(requiredStrings).then(([modalTitle, modalBody, deleteLabel]) => {\n return Notification.deleteCancelPromise(\n modalTitle,\n modalBody,\n deleteLabel,\n {triggerElement});\n }).then(() => {\n const pendingPromise = new Pending('mod_lti/course_tools:delete');\n\n const request = {\n methodname: 'mod_lti_delete_course_tool_type',\n args: {tooltypeid: courseToolDelete.dataset.courseToolId}\n };\n return Ajax.call([request])[0]\n .then(addToast(getString('coursetooldeleted', 'mod_lti', courseToolDelete.dataset.courseToolName)))\n .then(() => {\n const tableRoot = triggerElement.closest(Selectors.main.region);\n return refreshTableContent(tableRoot);\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n }).catch(() => {\n return;\n });\n }\n\n const courseShowInActivityChooser = event.target.closest('[data-action=\"showinactivitychooser-toggle\"]');\n if (courseShowInActivityChooser) {\n const showInActivityChooserStateToggle = courseShowInActivityChooser.dataset.state === \"0\" ? 1 : 0;\n return toggleShowInActivityChooser(\n courseShowInActivityChooser.dataset.id,\n courseShowInActivityChooser.dataset.courseid,\n showInActivityChooserStateToggle,\n );\n }\n });\n};\n"],"names":["document","addEventListener","event","courseToolDelete","target","closest","preventDefault","deleteBodyStringId","dataset","courseToolUsage","requiredStrings","key","component","param","courseToolName","triggerElement","querySelector","then","_ref","modalTitle","modalBody","deleteLabel","Notification","deleteCancelPromise","pendingPromise","Pending","request","methodname","args","tooltypeid","courseToolId","Ajax","call","tableRoot","Selectors","main","region","resolve","catch","exception","courseShowInActivityChooser","showInActivityChooserStateToggle","state","id","courseid"],"mappings":"+/CAqCoB,KAChBA,SAASC,iBAAiB,SAASC,cAEzBC,iBAAmBD,MAAME,OAAOC,QAAQ,yCAC1CF,iBAAkB,CAClBD,MAAMI,uBAIAC,mBADQJ,iBAAiBK,QAAQC,gBACJ,EAAI,mCAAqC,0BACtEC,gBAAkB,CACpB,CAACC,IAAK,mBAAoBC,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,gBAChF,CAACH,IAAKJ,mBAAoBK,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,gBAChF,CAACH,IAAK,SAAUC,UAAW,OAAQC,MAAOV,iBAAiBK,QAAQM,gBACnE,CAACH,IAAK,oBAAqBC,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,iBAG/EC,eAAiBZ,iBAAiBE,QAAQ,aAAaW,cAAc,wCAEhEN,iBAAiBO,MAAKC,WAAEC,WAAYC,UAAWC,yBAC/CC,sBAAaC,oBAChBJ,WACAC,UACAC,YACA,CAACN,eAAAA,oBACNE,MAAK,WACEO,eAAiB,IAAIC,iBAAQ,+BAE7BC,QAAU,CACZC,WAAY,kCACZC,KAAM,CAACC,WAAY1B,iBAAiBK,QAAQsB,sBAEzCC,cAAKC,KAAK,CAACN,UAAU,GACvBT,MAAK,eAAS,kBAAU,oBAAqB,UAAWd,iBAAiBK,QAAQM,kBACjFG,MAAK,WACIgB,UAAYlB,eAAeV,QAAQ6B,UAAUC,KAAKC,eACjD,gCAAoBH,cAE9BhB,KAAKO,eAAea,SACpBC,MAAMhB,sBAAaiB,cACzBD,OAAM,eAKPE,4BAA8BtC,MAAME,OAAOC,QAAQ,mDACrDmC,4BAA6B,OACvBC,iCAAiF,MAA9CD,4BAA4BhC,QAAQkC,MAAgB,EAAI,SAC1F,2CACHF,4BAA4BhC,QAAQmC,GACpCH,4BAA4BhC,QAAQoC,SACpCH"} \ No newline at end of file diff --git a/mod/lti/amd/build/repository.min.js b/mod/lti/amd/build/repository.min.js new file mode 100644 index 00000000000..0463554ddc1 --- /dev/null +++ b/mod/lti/amd/build/repository.min.js @@ -0,0 +1,10 @@ +define("mod_lti/repository",["exports","core/ajax"],(function(_exports,_ajax){var obj; +/** + * Module to handle AJAX interactions. + * + * @module mod_lti/repository + * @copyright 2023 Ilya Tregubov + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.toggleShowInActivityChooser=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.toggleShowInActivityChooser=(tooltypeid,courseid,coursevisible)=>_ajax.default.call([{methodname:"mod_lti_toggle_showinactivitychooser",args:{tooltypeid:tooltypeid,courseid:courseid,coursevisible:coursevisible}}])[0]})); + +//# sourceMappingURL=repository.min.js.map \ No newline at end of file diff --git a/mod/lti/amd/build/repository.min.js.map b/mod/lti/amd/build/repository.min.js.map new file mode 100644 index 00000000000..a86f231996d --- /dev/null +++ b/mod/lti/amd/build/repository.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"repository.min.js","sources":["../src/repository.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 * Module to handle AJAX interactions.\n *\n * @module mod_lti/repository\n * @copyright 2023 Ilya Tregubov \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Toggle coursevisible of a tool\n *\n * @param {Number} tooltypeid Too type id\n * @param {Number} courseid Course ID\n * @param {Number} coursevisible coursevisible state\n * @return {Promise}\n */\nexport const toggleShowInActivityChooser = (\n tooltypeid,\n courseid,\n coursevisible,\n) => Ajax.call([{\n methodname: 'mod_lti_toggle_showinactivitychooser',\n args: {\n tooltypeid,\n courseid,\n coursevisible,\n },\n}])[0];\n"],"names":["tooltypeid","courseid","coursevisible","Ajax","call","methodname","args"],"mappings":";;;;;;;kMAiC2C,CACvCA,WACAC,SACAC,gBACCC,cAAKC,KAAK,CAAC,CACZC,WAAY,uCACZC,KAAM,CACFN,WAAAA,WACAC,SAAAA,SACAC,cAAAA,kBAEJ"} \ No newline at end of file diff --git a/mod/lti/amd/src/course_tools_list.js b/mod/lti/amd/src/course_tools_list.js index da17abb72b2..6fac7469f05 100644 --- a/mod/lti/amd/src/course_tools_list.js +++ b/mod/lti/amd/src/course_tools_list.js @@ -30,6 +30,7 @@ import {add as addToast} from 'core/toast'; import {getString, getStrings} from 'core/str'; import {refreshTableContent} from 'core_table/dynamic'; import * as Selectors from 'core_table/local/dynamic/selectors'; +import {toggleShowInActivityChooser} from "./repository"; /** * Initialise module. @@ -78,5 +79,15 @@ export const init = () => { return; }); } + + const courseShowInActivityChooser = event.target.closest('[data-action="showinactivitychooser-toggle"]'); + if (courseShowInActivityChooser) { + const showInActivityChooserStateToggle = courseShowInActivityChooser.dataset.state === "0" ? 1 : 0; + return toggleShowInActivityChooser( + courseShowInActivityChooser.dataset.id, + courseShowInActivityChooser.dataset.courseid, + showInActivityChooserStateToggle, + ); + } }); }; diff --git a/mod/lti/amd/src/repository.js b/mod/lti/amd/src/repository.js new file mode 100644 index 00000000000..0f1b4a9a326 --- /dev/null +++ b/mod/lti/amd/src/repository.js @@ -0,0 +1,45 @@ +// 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 . + +/** + * Module to handle AJAX interactions. + * + * @module mod_lti/repository + * @copyright 2023 Ilya Tregubov + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import Ajax from 'core/ajax'; + +/** + * Toggle coursevisible of a tool + * + * @param {Number} tooltypeid Too type id + * @param {Number} courseid Course ID + * @param {Number} coursevisible coursevisible state + * @return {Promise} + */ +export const toggleShowInActivityChooser = ( + tooltypeid, + courseid, + coursevisible, +) => Ajax.call([{ + methodname: 'mod_lti_toggle_showinactivitychooser', + args: { + tooltypeid, + courseid, + coursevisible, + }, +}])[0]; diff --git a/mod/lti/backup/moodle2/backup_lti_stepslib.php b/mod/lti/backup/moodle2/backup_lti_stepslib.php index eae88a71bf4..ae211860f3d 100644 --- a/mod/lti/backup/moodle2/backup_lti_stepslib.php +++ b/mod/lti/backup/moodle2/backup_lti_stepslib.php @@ -146,6 +146,12 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step 'state' )); + $lticoursevisible = new backup_nested_element('lticoursevisible', ['id'], [ + 'typeid', + 'courseid', + 'coursevisible', + ]); + // Build the tree $lti->add_child($ltitype); $ltitype->add_child($ltitypesconfigs); @@ -156,6 +162,7 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step $ltitoolsettings->add_child($ltitoolsetting); $lti->add_child($ltisubmissions); $ltisubmissions->add_child($ltisubmission); + $lti->add_child($lticoursevisible); // Define sources. $ltirecord = $DB->get_record('lti', ['id' => $this->task->get_activityid()]); @@ -193,6 +200,9 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step $ltisubmission->set_source_table('lti_submission', array('ltiid' => backup::VAR_ACTIVITYID)); } + $lticoursevisibledata = $this->retrieve_lti_coursevisible($ltirecord); + $lticoursevisible->set_source_array($lticoursevisibledata ? [$lticoursevisibledata] : []); + // Define id annotations $ltitype->annotate_ids('user', 'createdby'); $ltitype->annotate_ids('course', 'course'); @@ -238,4 +248,18 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step return $record; } + + /** + * Retrieves a record from {lti_coursevisible} table associated with the current type + * + * @param stdClass $ltirecord record from {lti} table + * @return mixed + */ + protected function retrieve_lti_coursevisible(stdClass $ltirecord): mixed { + global $DB; + if (!$ltirecord->typeid) { + return null; + } + return $DB->get_record('lti_coursevisible', ['typeid' => $ltirecord->typeid, 'courseid' => $ltirecord->course]); + } } diff --git a/mod/lti/backup/moodle2/restore_lti_stepslib.php b/mod/lti/backup/moodle2/restore_lti_stepslib.php index f01440b0e73..02bcf846fb1 100644 --- a/mod/lti/backup/moodle2/restore_lti_stepslib.php +++ b/mod/lti/backup/moodle2/restore_lti_stepslib.php @@ -78,6 +78,8 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste $paths[] = $submission; } + $paths[] = new restore_path_element('lticoursevisible', '/activity/lti/lticoursevisible'); + // Add support for subplugin structures. $this->add_subplugin_structure('ltisource', $lti); $this->add_subplugin_structure('ltiservice', $lti); @@ -149,6 +151,23 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste $DB->update_record('lti', ['id' => $this->get_new_parentid('lti'), 'typeid' => $ltitypeid]); } + /** + * Process an lti coursevisible restore + * @param mixed $data The data from backup XML file + * @return void + */ + protected function process_lticoursevisible($data) { + global $DB; + + $data = (object)$data; + $data->typeid = $this->get_new_parentid('ltitype'); + $data->courseid = $this->get_courseid(); + + if ($data->typeid) { + $DB->insert_record('lti_coursevisible', $data); + } + } + /** * Attempts to find existing record in lti_type * @param stdClass $data diff --git a/mod/lti/classes/external/toggle_showinactivitychooser.php b/mod/lti/classes/external/toggle_showinactivitychooser.php new file mode 100644 index 00000000000..5c44241615d --- /dev/null +++ b/mod/lti/classes/external/toggle_showinactivitychooser.php @@ -0,0 +1,116 @@ +. + +namespace mod_lti\external; + +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_value; +use mod_lti\local\ltiopenid\registration_helper; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/mod/lti/locallib.php'); + +/** + * External function to toggle showinactivitychooser setting. + * + * @package mod_lti + * @copyright 2023 Ilya Tregubov + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class toggle_showinactivitychooser extends external_api { + + /** + * Get parameter definition. + * + * @return external_function_parameters + */ + public static function execute_parameters(): external_function_parameters { + return new external_function_parameters([ + 'tooltypeid' => new external_value(PARAM_INT, 'Tool type ID'), + 'courseid' => new external_value(PARAM_INT, 'Course ID'), + 'coursevisible' => new external_value(PARAM_BOOL, 'Show in activity chooser'), + ]); + } + + /** + * Toggles showinactivitychooser setting. + * + * @param int $tooltypeid the id of the course external tool type. + * @param int $courseid the id of the course we are in. + * @param bool $showinactivitychooser Show in activity chooser setting. + * @return bool true + */ + public static function execute(int $tooltypeid, int $courseid, bool $showinactivitychooser): bool { + global $DB; + + [ + 'tooltypeid' => $tooltypeid, + 'courseid' => $courseid, + 'coursevisible' => $showinactivitychooser, + ] = self::validate_parameters(self::execute_parameters(), [ + 'tooltypeid' => $tooltypeid, + 'courseid' => $courseid, + 'coursevisible' => $showinactivitychooser, + ]); + + $context = \context_course::instance($courseid); + self::validate_context($context); + require_capability('mod/lti:addcoursetool', $context); + + if ($showinactivitychooser) { + $coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; + } else { + $coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED; + } + $ltitype = $DB->get_record('lti_types', ['id' => $tooltypeid]); + $ltitype->coursevisible = $coursevisible; + + $config = new \stdClass(); + $config->lti_coursevisible = $coursevisible; + + if (intval($ltitype->course) !== intval(get_site()->id)) { + // It is course tool - just update it. + lti_update_type($ltitype, $config); + } else { + // This is site tool, but we would like to have course level setting for it. + $lticoursevisible = $DB->get_record('lti_coursevisible', ['typeid' => $tooltypeid, 'courseid' => $courseid]); + if (!$lticoursevisible) { + $lticoursevisible = new \stdClass(); + $lticoursevisible->typeid = $tooltypeid; + $lticoursevisible->courseid = $courseid; + $lticoursevisible->coursevisible = $coursevisible; + $DB->insert_record('lti_coursevisible', $lticoursevisible); + } else { + $lticoursevisible->coursevisible = $coursevisible; + $DB->update_record('lti_coursevisible', $lticoursevisible); + } + } + + return true; + } + + /** + * Get service returns definition. + * + * @return external_value + */ + public static function execute_returns(): external_value { + return new external_value(PARAM_BOOL, 'Success'); + } +} diff --git a/mod/lti/classes/local/types_helper.php b/mod/lti/classes/local/types_helper.php index 45dd6bd3e3b..a462082a9c8 100644 --- a/mod/lti/classes/local/types_helper.php +++ b/mod/lti/classes/local/types_helper.php @@ -48,25 +48,36 @@ class types_helper { if (empty($coursevisible)) { $coursevisible = [LTI_COURSEVISIBLE_PRECONFIGURED, LTI_COURSEVISIBLE_ACTIVITYCHOOSER]; } - list($coursevisiblesql, $coursevisparams) = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible'); + [$coursevisiblesql, $coursevisparams] = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible'); + [$coursevisiblesql1, $coursevisparams1] = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible'); + [$coursevisibleoverriddensql, $coursevisoverriddenparams] = $DB->get_in_or_equal( + $coursevisible, + SQL_PARAMS_NAMED, + 'coursevisibleoverridden'); $coursecond = implode(" OR ", ["t.course = :courseid", "t.course = :siteid"]); $coursecategory = $DB->get_field('course', 'category', ['id' => $courseid]); - $query = "SELECT t.* - FROM {lti_types} t - LEFT JOIN {lti_types_categories} tc ON t.id = tc.typeid - WHERE t.coursevisible $coursevisiblesql - AND ($coursecond) - AND t.state = :active - AND (tc.id IS NULL OR tc.categoryid = :categoryid) - ORDER BY t.name ASC"; + $query = "SELECT * + FROM (SELECT t.*, c.coursevisible as coursevisibleoverridden + FROM {lti_types} t + LEFT JOIN {lti_types_categories} tc ON t.id = tc.typeid + LEFT JOIN {lti_coursevisible} c ON c.typeid = t.id AND c.courseid = $courseid + WHERE (t.coursevisible $coursevisiblesql OR c.coursevisible $coursevisiblesql1) + AND ($coursecond) + AND t.state = :active + AND (tc.id IS NULL OR tc.categoryid = :categoryid)) tt + WHERE tt.coursevisibleoverridden IS NULL + OR tt.coursevisibleoverridden $coursevisibleoverriddensql"; - return $DB->get_records_sql($query, + return $DB->get_records_sql( + $query, [ 'siteid' => $SITE->id, 'courseid' => $courseid, 'active' => LTI_TOOL_STATE_CONFIGURED, - 'categoryid' => $coursecategory - ] + $coursevisparams); + 'categoryid' => $coursecategory, + 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER, + ] + $coursevisparams + $coursevisparams1 + $coursevisoverriddenparams + ); } } diff --git a/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php b/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php index 14cab9dd3c4..2dd78c7fd7a 100644 --- a/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php +++ b/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php @@ -20,6 +20,7 @@ use core_reportbuilder\local\helpers\database; use core_reportbuilder\local\report\column; use mod_lti\reportbuilder\local\entities\tool_types; use core_reportbuilder\system_report; +use stdClass; /** * Course external tools list system report class implementation. @@ -109,6 +110,7 @@ class course_external_tools_list extends system_report { */ protected function add_columns(tool_types $tooltypesentity): void { $entitymainalias = $tooltypesentity->get_table_alias('lti_types'); + $courseid = $this->course->id; $columns = [ 'tool_types:name', @@ -129,6 +131,57 @@ class course_external_tools_list extends system_report { ->add_field("{$entitymainalias}.id") ->add_callback(fn() => $this->perrowtoolusage); + // Enable toggle column. + $this->add_column((new column( + 'showinactivitychooser', + new \lang_string('showinactivitychooser', 'mod_lti'), + $tooltypesentity->get_entity_name() + )) + // Site tools can be overridden on course level. + ->add_join("LEFT JOIN {lti_coursevisible} lc ON lc.typeid = {$entitymainalias}.id AND lc.courseid = $courseid") + ->set_type(column::TYPE_INTEGER) + ->add_fields("{$entitymainalias}.id, {$entitymainalias}.coursevisible, lc.coursevisible as coursevisibleoverridden") + ->set_is_sortable(false) + ->set_callback(static function(int $id, stdClass $row): string { + global $PAGE, $COURSE; + $coursevisible = $row->coursevisible; + $courseid = $COURSE->id; + if (!empty($row->coursevisibleoverridden)) { + $coursevisible = $row->coursevisibleoverridden; + } + + if ($coursevisible == LTI_COURSEVISIBLE_ACTIVITYCHOOSER) { + $coursevisible = true; + } else { + $coursevisible = false; + } + + $renderer = $PAGE->get_renderer('core_reportbuilder'); + $attributes = [ + ['name' => 'id', 'value' => $row->id], + ['name' => 'courseid', 'value' => $courseid], + ['name' => 'action', 'value' => 'showinactivitychooser-toggle'], + ['name' => 'state', 'value' => $coursevisible], + ]; + $label = $coursevisible ? get_string('dontshowinactivitychooser', 'mod_lti') + : get_string('showinactivitychooser', 'mod_lti'); + + $disabled = false; + if (!has_capability('mod/lti:addcoursetool', \context_course::instance($courseid))) { + $disabled = true; + } + + return $renderer->render_from_template('core/toggle', [ + 'id' => 'showinactivitychooser-toggle-' . $row->id, + 'checked' => $coursevisible, + 'disabled' => $disabled, + 'dataattributes' => $attributes, + 'label' => $label, + 'labelclasses' => 'sr-only' + ]); + }) + ); + // Attempt to create a dummy actions column, working around the limitations of the official actions feature. $this->add_column(new column( 'actions', new \lang_string('actions'), diff --git a/mod/lti/db/install.xml b/mod/lti/db/install.xml index 5e3b8578113..1b9c717a2de 100644 --- a/mod/lti/db/install.xml +++ b/mod/lti/db/install.xml @@ -1,5 +1,5 @@ - @@ -175,5 +175,20 @@ + + + + + + + + + + + + + + +
diff --git a/mod/lti/db/services.php b/mod/lti/db/services.php index 93c385382cb..aeef21484a5 100644 --- a/mod/lti/db/services.php +++ b/mod/lti/db/services.php @@ -154,6 +154,14 @@ $functions = array( 'ajax' => true ), + 'mod_lti_toggle_showinactivitychooser' => array( + 'classname' => 'mod_lti\external\toggle_showinactivitychooser', + 'description' => 'Toggle showinactivitychooser for a course tool type', + 'type' => 'write', + 'capabilities' => 'mod/lti:addcoursetool', + 'ajax' => true + ), + 'mod_lti_is_cartridge' => array( 'classname' => 'mod_lti_external', 'methodname' => 'is_cartridge', diff --git a/mod/lti/db/upgrade.php b/mod/lti/db/upgrade.php index 46b8aa138d9..4a4c2ebd7e0 100644 --- a/mod/lti/db/upgrade.php +++ b/mod/lti/db/upgrade.php @@ -133,10 +133,31 @@ function xmldb_lti_upgrade($oldversion) { if (!$dbman->table_exists($table)) { $dbman->create_table($table); } - // Lti savepoint reached. upgrade_mod_savepoint(true, 2023070501, 'lti'); } + if ($oldversion < 2023081101) { + // Define communication table. + $table = new xmldb_table('lti_coursevisible'); + + // Adding fields to table lti_coursevisible. + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE); + $table->add_field('typeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id'); + $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'typeid'); + $table->add_field('coursevisible', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'courseid'); + + // Add key. + $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); + + // Conditionally launch create table for communication. + if (!$dbman->table_exists($table)) { + $dbman->create_table($table); + } + + // Lti savepoint reached. + upgrade_mod_savepoint(true, 2023081101, 'lti'); + } + return true; } diff --git a/mod/lti/lang/en/lti.php b/mod/lti/lang/en/lti.php index d74124d0d3b..7cf4420ddea 100644 --- a/mod/lti/lang/en/lti.php +++ b/mod/lti/lang/en/lti.php @@ -523,6 +523,8 @@ $string['share_roster_help'] = 'Specify whether the tool can access the list of Note that this setting may be overridden in the tool configuration.'; $string['show_in_course_activity_chooser'] = 'Show in activity chooser and as a preconfigured tool'; +$string['showinactivitychooser'] = 'Show in activity chooser'; +$string['dontshowinactivitychooser'] = 'Don\'t show in activity chooser'; $string['show_in_course_lti1'] = 'Tool configuration usage'; $string['show_in_course_lti1_help'] = 'This tool may be shown in the activity chooser for a teacher to select to add to a course. Alternatively, it may be shown in the preconfigured tool drop-down menu when adding an external tool to a course. A further option is for the tool configuration to only be used if the exact tool URL is entered when adding an external tool to a course.'; $string['show_in_course_lti2'] = 'Tool configuration usage'; diff --git a/mod/lti/tests/behat/managecoursetools.feature b/mod/lti/tests/behat/managecoursetools.feature index 6a50146f973..c51cf74e212 100644 --- a/mod/lti/tests/behat/managecoursetools.feature +++ b/mod/lti/tests/behat/managecoursetools.feature @@ -147,3 +147,136 @@ Feature: Manage course tools And the field "Tool URL" matches value "http://www.example.com/lti/provider.php" And the field "Icon URL" matches value "http://download.moodle.org/unittest/test.jpg" And the field "Secure icon URL" matches value "https://download.moodle.org/unittest/test.jpg" + + @javascript + Scenario: Site tool appearing in activity chooser according to settings + Given the following "mod_lti > tool types" exist: + | name | baseurl | coursevisible | state | + | Teaching Tool 1 | /mod/lti/tests/fixtures/tool_provider.php | 2 | 1 | + | Teaching Tool 2 | /mod/lti/tests/fixtures/tool_provider.php | 1 | 1 | + | Teaching Tool 3 | /mod/lti/tests/fixtures/tool_provider.php | 0 | 1 | + And the following "courses" exist: + | fullname | shortname | category | + | Course 2 | C2 | 0 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C2 | editingteacher | + And I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should see "Teaching Tool 1" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 2" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 3" in the ".modal-body" "css_element" + And I click on "Close" "button" in the ".modal-dialog" "css_element" + And I navigate to "LTI External tools" in current page administration + And I should not see "Teaching Tool 3" + And I click on "Don't show in activity chooser" "field" in the "Teaching Tool 1" "table_row" + And I click on "Show in activity chooser" "field" in the "Teaching Tool 2" "table_row" + And I am on "Course 1" course homepage + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should not see "Teaching Tool 1" in the ".modal-body" "css_element" + And I should see "Teaching Tool 2" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 3" in the ".modal-body" "css_element" + And I click on "Close" "button" in the ".modal-dialog" "css_element" + + # Should not affect other courses. + And I am on "Course 2" course homepage + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should see "Teaching Tool 1" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 2" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 3" in the ".modal-body" "css_element" + And I click on "Close" "button" in the ".modal-dialog" "css_element" + + And I am on "Course 1" course homepage + And I navigate to "LTI External tools" in current page administration + And I click on "Show in activity chooser" "field" in the "Teaching Tool 1" "table_row" + And I click on "Don't show in activity chooser" "field" in the "Teaching Tool 2" "table_row" + And I am on "Course 1" course homepage + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should see "Teaching Tool 1" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 2" in the ".modal-body" "css_element" + And I should not see "Teaching Tool 3" in the ".modal-body" "css_element" + + When the following "role capability" exists: + | role | editingteacher | + | mod/lti:addcoursetool | prohibit | + And I am on "Course 1" course homepage with editing mode on + And I navigate to "LTI External tools" in current page administration + Then the "Don't show in activity chooser" "field" should be disabled + And the "Show in activity chooser" "field" should be disabled + + @javascript + Scenario: Course tool appearing in activity chooser according to settings + Given the following "mod_lti > course tools" exist: + | name | baseurl | course | coursevisible | + | Course Tool 1 | /mod/lti/tests/fixtures/tool_provider.php | C1 | 2 | + | Course Tool 2 | /mod/lti/tests/fixtures/tool_provider.php | C1 | 1 | + And I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should see "Course Tool 1" in the ".modal-body" "css_element" + And I should not see "Course Tool 2" in the ".modal-body" "css_element" + And I click on "Close" "button" in the ".modal-dialog" "css_element" + And I navigate to "LTI External tools" in current page administration + And I click on "Don't show in activity chooser" "field" in the "Course Tool 1" "table_row" + And I click on "Show in activity chooser" "field" in the "Course Tool 2" "table_row" + And I am on "Course 1" course homepage + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should not see "Course Tool 1" in the ".modal-body" "css_element" + And I should see "Course Tool 2" in the ".modal-body" "css_element" + And I click on "Close" "button" in the ".modal-dialog" "css_element" + And I navigate to "LTI External tools" in current page administration + And I click on "Show in activity chooser" "field" in the "Course Tool 1" "table_row" + And I click on "Don't show in activity chooser" "field" in the "Course Tool 2" "table_row" + And I am on "Course 1" course homepage + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + And I should see "Course Tool 1" in the ".modal-body" "css_element" + And I should not see "Course Tool 2" in the ".modal-body" "css_element" + + When the following "role capability" exists: + | role | editingteacher | + | mod/lti:addcoursetool | prohibit | + And I am on "Course 1" course homepage with editing mode on + And I navigate to "LTI External tools" in current page administration + Then the "Don't show in activity chooser" "field" should be disabled + And the "Show in activity chooser" "field" should be disabled + + @javascript + Scenario: Site and course tools settings are preserved when backup and restore + Given the following "mod_lti > tool types" exist: + | name | baseurl | coursevisible | state | + | Teaching Tool 1 | /mod/lti/tests/fixtures/tool_provider.php | 2 | 1 | + | Teaching Tool 2 | /mod/lti/tests/fixtures/tool_provider.php | 1 | 1 | + And the following "mod_lti > course tools" exist: + | name | description | baseurl | course | + | Course Tool 1 | Example description | https://example.com/tool | C1 | + And I log in as "admin" + And I am on "Course 1" course homepage with editing mode on + And I add a "Teaching Tool 1" to section "1" + And I set the field "Activity name" to "Test tool activity 1" + And I press "Save and return to course" + And I add a "Course Tool 1" to section "1" + And I set the field "Activity name" to "Course tool activity 1" + And I press "Save and return to course" + And I navigate to "LTI External tools" in current page administration + And I click on "Don't show in activity chooser" "field" in the "Teaching Tool 1" "table_row" + And I click on "Show in activity chooser" "field" in the "Teaching Tool 2" "table_row" + And I click on "Don't show in activity chooser" "field" in the "Course Tool 1" "table_row" + And I am on "Course 1" course homepage + And I add a "Teaching Tool 2" to section "1" + And I set the field "Activity name" to "Test tool activity 2" + And I press "Save and return to course" + When I backup "Course 1" course using this options: + | Confirmation | Filename | test_backup.mbz | + And I restore "test_backup.mbz" backup into a new course using this options: + | Schema | Course name | Restored course | + And I should see "Restored course" + And I click on "Add an activity or resource" "button" in the "Topic 1" "section" + Then I should not see "Teaching Tool 1" in the ".modal-body" "css_element" + And I should see "Teaching Tool 2" in the ".modal-body" "css_element" + And I should not see "Course Tool 2" in the ".modal-body" "css_element" + And I click on "Close" "button" in the ".modal-dialog" "css_element" + And I navigate to "LTI External tools" in current page administration + And I should see "Show in activity chooser" in the "Teaching Tool 1" "table_row" + And I should see "Don't show in activity chooser" in the "Teaching Tool 2" "table_row" + And I should see "Show in activity chooser" in the "Course Tool 1" "table_row" diff --git a/mod/lti/tests/external/toggle_showinactivitychooser_test.php b/mod/lti/tests/external/toggle_showinactivitychooser_test.php new file mode 100644 index 00000000000..650c82c555f --- /dev/null +++ b/mod/lti/tests/external/toggle_showinactivitychooser_test.php @@ -0,0 +1,111 @@ +. + +namespace mod_lti\external; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/mod/lti/tests/mod_lti_testcase.php'); + +/** + * PHPUnit tests for toggle_showinactivitychooser external function. + * + * @package mod_lti + * @copyright 2023 Ilya Tregubov + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \mod_lti\external\toggle_showinactivitychooser + */ +class toggle_showinactivitychooser_test extends \mod_lti_testcase { + + /** + * Test toggle_showinactivitychooser for course tool. + * @covers ::execute + */ + public function test_toggle_showinactivitychooser_course_tool() { + global $DB; + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + $this->setUser($editingteacher); + + $typeid = lti_add_type( + (object) [ + 'state' => LTI_TOOL_STATE_CONFIGURED, + 'course' => $course->id, + 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER + ], + (object) [ + 'lti_typename' => "My course tool", + 'lti_toolurl' => 'http://example.com', + 'lti_ltiversion' => 'LTI-1p0', + 'lti_coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER + ] + ); + toggle_showinactivitychooser::execute($typeid, $course->id, false); + $sql = "SELECT lt.coursevisible coursevisible1, ltc.value AS coursevisible2 + FROM {lti_types} lt + LEFT JOIN {lti_types_config} ltc ON lt.id = ltc.typeid + WHERE lt.id = ? + AND ltc.name = 'coursevisible'"; + $actual = $DB->get_record_sql($sql, [$typeid]); + $this->assertEquals(LTI_COURSEVISIBLE_PRECONFIGURED, $actual->coursevisible1); + $this->assertEquals(LTI_COURSEVISIBLE_PRECONFIGURED, $actual->coursevisible2); + + toggle_showinactivitychooser::execute($typeid, $course->id, true); + $actual = $DB->get_record_sql($sql, [$typeid]); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible1); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible2); + } + + /** + * Test toggle_showinactivitychooser for site tool. + * @covers ::execute + */ + public function test_toggle_showinactivitychooser_site_tool() { + global $DB; + + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + $this->setUser($editingteacher); + + $type = $this->generate_tool_type(123); // Creates a site tool. + + toggle_showinactivitychooser::execute($type->id, $course->id, false); + $sql = "SELECT lt.coursevisible coursevisible1, ltc.value AS coursevisible2, lc.coursevisible AS coursevisible3 + FROM {lti_types} lt + LEFT JOIN {lti_types_config} ltc ON lt.id = ltc.typeid + LEFT JOIN {lti_coursevisible} lc ON lt.id = lc.typeid + WHERE lt.id = ? + AND lc.courseid = ? + AND ltc.name = 'coursevisible'"; + $actual = $DB->get_record_sql($sql, [$type->id, $course->id]); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible1); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible2); + $this->assertEquals(LTI_COURSEVISIBLE_PRECONFIGURED, $actual->coursevisible3); + + toggle_showinactivitychooser::execute($type->id, $course->id, true); + $actual = $DB->get_record_sql($sql, [$type->id, $course->id]); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible1); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible2); + $this->assertEquals(LTI_COURSEVISIBLE_ACTIVITYCHOOSER, $actual->coursevisible3); + } + +} diff --git a/mod/lti/tests/generator/lib.php b/mod/lti/tests/generator/lib.php index d6837c0c30a..d4032b67588 100644 --- a/mod/lti/tests/generator/lib.php +++ b/mod/lti/tests/generator/lib.php @@ -151,13 +151,14 @@ class mod_lti_generator extends testing_module_generator { } $type['baseurl'] = (new moodle_url($type['baseurl']))->out(false); // Permits relative URLs in behat features. - $type['coursevisible'] = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; // The default for course tools. + $type['coursevisible'] = $type['coursevisible'] ?? LTI_COURSEVISIBLE_ACTIVITYCHOOSER; $type['state'] = LTI_TOOL_STATE_CONFIGURED; // The default for course tools. // Sensible defaults permitting the tool type to be used in a launch. $type['lti_acceptgrades'] = $type['lti_acceptgrades'] ?? LTI_SETTING_ALWAYS; $type['lti_sendname'] = $type['lti_sendname'] ?? LTI_SETTING_ALWAYS; $type['lti_sendemailaddr'] = $type['lti_sendemailaddr'] ?? LTI_SETTING_ALWAYS; + $type['lti_coursevisible'] = $type['coursevisible'] ?? LTI_COURSEVISIBLE_ACTIVITYCHOOSER; // Required for cartridge processing support. $type['lti_toolurl'] = $type['baseurl']; diff --git a/mod/lti/tests/local/types_helper_test.php b/mod/lti/tests/local/types_helper_test.php index 30283f38299..7a6ab969ef7 100644 --- a/mod/lti/tests/local/types_helper_test.php +++ b/mod/lti/tests/local/types_helper_test.php @@ -69,12 +69,20 @@ class types_helper_test extends mod_lti_testcase { $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); $teacher2 = $this->getDataGenerator()->create_and_enrol($course2, 'editingteacher'); - // Create the following tool types for testing: - // - Site tool configured as "Do not show" (LTI_COURSEVISIBLE_NO). - // - Site tool configured as "Show as a preconfigured tool only" (LTI_COURSEVISIBLE_PRECONFIGURED). - // - Site tool configured as "Show as a preconfigured tool and in the activity chooser" (LTI_COURSEVISIBLE_ACTIVITYCHOOSER). - // - Course tool which, by default, is configured as LTI_COURSEVISIBLE_ACTIVITYCHOOSER). - // - Site tool configured to "Show as a preconfigured tool and in the activity chooser" but restricted to a category. + /* + Create the following tool types for testing: + | tooltype | sitecoursevisible | coursecoursevisible | restrictedtocategory | + | site | LTI_COURSEVISIBLE_NO | | | + | site | LTI_COURSEVISIBLE_PRECONFIGURED | | | + | site | LTI_COURSEVISIBLE_PRECONFIGURED | LTI_COURSEVISIBLE_PRECONFIGURED | | + | site | LTI_COURSEVISIBLE_PRECONFIGURED | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | | + | site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | | | + | site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | | + | site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | LTI_COURSEVISIBLE_PRECONFIGURED | | + | site | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | yes | + | course | LTI_COURSEVISIBLE_ACTIVITYCHOOSER | | | + | course | LTI_COURSEVISIBLE_PRECONFIGURED | | | + */ /** @var \mod_lti_generator $ltigenerator */ $ltigenerator = $this->getDataGenerator()->get_plugin_generator('mod_lti'); @@ -108,41 +116,129 @@ class types_helper_test extends mod_lti_testcase { 'state' => LTI_TOOL_STATE_CONFIGURED, 'lti_coursecategories' => $coursecat2->id ]); + $ltigenerator->create_tool_types([ + 'name' => 'site tool preconfigured only, overridden to preconfigured only in course', + 'baseurl' => 'http://example.com/tool/6', + 'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED, + 'state' => LTI_TOOL_STATE_CONFIGURED + ]); + $tool = $DB->get_record('lti_types', + ['name' => 'site tool preconfigured only, overridden to preconfigured only in course']); + $record = new \stdClass(); + $record->typeid = $tool->id; + $record->courseid = $course->id; + $record->coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED; + $DB->insert_record('lti_coursevisible', $record); + + $ltigenerator->create_tool_types([ + 'name' => 'site tool preconfigured only, overridden to activity chooser in course', + 'baseurl' => 'http://example.com/tool/7', + 'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED, + 'state' => LTI_TOOL_STATE_CONFIGURED + ]); + $tool = $DB->get_record('lti_types', ['name' => 'site tool preconfigured only, overridden to activity chooser in course']); + $record = new \stdClass(); + $record->typeid = $tool->id; + $record->courseid = $course->id; + $record->coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; + $DB->insert_record('lti_coursevisible', $record); + + $ltigenerator->create_tool_types([ + 'name' => 'site tool preconfigured and activity chooser, overridden to activity chooser in course', + 'baseurl' => 'http://example.com/tool/8', + 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER, + 'state' => LTI_TOOL_STATE_CONFIGURED + ]); + $tool = $DB->get_record('lti_types', + ['name' => 'site tool preconfigured and activity chooser, overridden to activity chooser in course']); + $record = new \stdClass(); + $record->typeid = $tool->id; + $record->courseid = $course->id; + $record->coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; + $DB->insert_record('lti_coursevisible', $record); + + $ltigenerator->create_tool_types([ + 'name' => 'site tool preconfigured and activity chooser, overridden to preconfigured in course', + 'baseurl' => 'http://example.com/tool/9', + 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER, + 'state' => LTI_TOOL_STATE_CONFIGURED + ]); + $tool = $DB->get_record('lti_types', + ['name' => 'site tool preconfigured and activity chooser, overridden to preconfigured in course']); + $record = new \stdClass(); + $record->typeid = $tool->id; + $record->courseid = $course->id; + $record->coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED; + $DB->insert_record('lti_coursevisible', $record); + + $ltigenerator->create_course_tool_types([ + 'name' => 'course tool preconfigured', + 'baseurl' => 'http://example.com/tool/91', + 'course' => $course->id, + 'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED + ]); // Request using the default 'coursevisible' param will include all tools except the one configured as "Do not show" and // the tool restricted to category 2. $coursetooltypes = types_helper::get_lti_types_by_course($course->id, $teacher->id); - $this->assertCount(3, $coursetooltypes); - $this->assertEmpty(array_diff( - ['http://example.com/tool/2', 'http://example.com/tool/3', 'http://example.com/tool/4'], - array_column($coursetooltypes, 'baseurl') - )); + $this->assertCount(8, $coursetooltypes); + $this->assertEmpty(array_diff([ + 'http://example.com/tool/2', + 'http://example.com/tool/3', + 'http://example.com/tool/4', + 'http://example.com/tool/6', + 'http://example.com/tool/7', + 'http://example.com/tool/8', + 'http://example.com/tool/9', + 'http://example.com/tool/91', + ], array_column($coursetooltypes, 'baseurl'))); // Request for only those tools configured to show in the activity chooser for the teacher. $coursetooltypes = types_helper::get_lti_types_by_course($course->id, $teacher->id, [LTI_COURSEVISIBLE_ACTIVITYCHOOSER]); - $this->assertCount(2, $coursetooltypes); - $this->assertEmpty(array_diff( - ['http://example.com/tool/3', 'http://example.com/tool/4'], - array_column($coursetooltypes, 'baseurl') - )); + $this->assertCount(4, $coursetooltypes); + $expected = [ + 'http://example.com/tool/3', + 'http://example.com/tool/4', + 'http://example.com/tool/7', + 'http://example.com/tool/8' + ]; + sort($expected); + $actual = array_column($coursetooltypes, 'baseurl'); + sort($actual); + $this->assertEquals($expected, $actual); // Request for only those tools configured to show as a preconfigured tool for the teacher. $coursetooltypes = types_helper::get_lti_types_by_course($course->id, $teacher->id, [LTI_COURSEVISIBLE_PRECONFIGURED]); - $this->assertCount(1, $coursetooltypes); - $this->assertEmpty(array_diff( - ['http://example.com/tool/2'], - array_column($coursetooltypes, 'baseurl') - )); + $this->assertCount(4, $coursetooltypes); + $expected = [ + 'http://example.com/tool/2', + 'http://example.com/tool/6', + 'http://example.com/tool/9', + 'http://example.com/tool/91' + ]; + sort($expected); + $actual = array_column($coursetooltypes, 'baseurl'); + sort($actual); + $this->assertEquals($expected, $actual); // Request for teacher2 in course2 (course category 2). $coursetooltypes = types_helper::get_lti_types_by_course($course2->id, $teacher2->id); - $this->assertCount(3, $coursetooltypes); - $this->assertEmpty(array_diff( - ['http://example.com/tool/2', 'http://example.com/tool/3', 'http://example.com/tool/5'], - array_column($coursetooltypes, 'baseurl') - )); + $this->assertCount(7, $coursetooltypes); + $expected = [ + 'http://example.com/tool/2', + 'http://example.com/tool/3', + 'http://example.com/tool/5', + 'http://example.com/tool/6', + 'http://example.com/tool/7', + 'http://example.com/tool/8', + 'http://example.com/tool/9' + ]; + sort($expected); + $actual = array_column($coursetooltypes, 'baseurl'); + sort($actual); + $this->assertEquals($expected, $actual); // Request for a teacher who cannot use preconfigured tools in the course. $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); diff --git a/mod/lti/tests/mod_lti_testcase.php b/mod/lti/tests/mod_lti_testcase.php index cdd82f866c7..9fe7b76d441 100644 --- a/mod/lti/tests/mod_lti_testcase.php +++ b/mod/lti/tests/mod_lti_testcase.php @@ -48,8 +48,11 @@ abstract class mod_lti_testcase extends externallib_advanced_testcase { $type->description = "Example description $uniqueid"; $type->toolproxyid = $toolproxyid; $type->baseurl = $this->getExternalTestFileUrl("/test$uniqueid.html"); + $type->coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; + $config = new stdClass(); + $config->lti_coursevisible = LTI_COURSEVISIBLE_ACTIVITYCHOOSER; - $type->id = lti_add_type($type, new stdClass()); + $type->id = lti_add_type($type, $config); return $type; } diff --git a/mod/lti/version.php b/mod/lti/version.php index 542dcd5b45d..9ef820be421 100644 --- a/mod/lti/version.php +++ b/mod/lti/version.php @@ -48,7 +48,7 @@ defined('MOODLE_INTERNAL') || die; -$plugin->version = 2023081100; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2023081101; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2023041800; // Requires this Moodle version. $plugin->component = 'mod_lti'; // Full name of the plugin (used for diagnostics). $plugin->cron = 0;