diff --git a/mod/forum/amd/build/grades/grader.min.js b/mod/forum/amd/build/grades/grader.min.js index 6de71f2efa8..2e0c3cf6510 100644 --- a/mod/forum/amd/build/grades/grader.min.js +++ b/mod/forum/amd/build/grades/grader.min.js @@ -5,6 +5,6 @@ define("mod_forum/grades/grader",["exports","./grader/selectors","mod_forum/repo * @module mod_forum/grades/grader * @copyright 2019 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.registerLaunchListeners=void 0,Selectors=_interopRequireWildcard(Selectors),_repository=_interopRequireDefault(_repository),_templates=_interopRequireDefault(_templates),Grader=_interopRequireWildcard(Grader),_notification=_interopRequireDefault(_notification),_repository2=_interopRequireDefault(_repository2);const templateNames_contentRegion="mod_forum/grades/grader/discussion/posts",getContentForUserIdFunction=(cmid,experimentalDisplayMode)=>userid=>_repository.default.getDiscussionByUserID(userid,cmid).then((context=>(context.discussions=context.discussions.map(discussionPostMapper),context.experimentaldisplaymode=!!experimentalDisplayMode,_templates.default.render(templateNames_contentRegion,context)))).catch(_notification.default.exception),getUsersForCmidFunction=(cmid,groupID)=>async()=>(await _repository2.default.getUsersFromCourseModuleID(cmid,groupID)).users,findGradableNode=node=>node.closest(Selectors.gradableItem),discussionPostMapper=discussion=>{const parentMap=new Map;discussion.posts.parentposts.forEach((post=>parentMap.set(post.id,post)));const userPosts=discussion.posts.userposts.map((post=>{post.readonly=!0,post.hasreplies=!1,post.replies=[];const parent=post.parentid?parentMap.get(post.parentid):null;return parent&&(parent.hasreplies=!1,parent.replies=[],parent.readonly=!0,post.parentauthorname=parent.author.fullname),{parent:parent,post:post}}));return{...discussion,posts:userPosts}};_exports.registerLaunchListeners=()=>{document.addEventListener("click",(async e=>{if(e.target.matches(Selectors.launch)){const rootNode=findGradableNode(e.target);if(!rootNode)throw Error("Unable to find a gradable item");if(!rootNode.matches(Selectors.gradableItems.wholeForum))throw Error("Unable to find a valid gradable item");e.preventDefault();try{await async function(rootNode){let{focusOnClose:focusOnClose=null}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const data=rootNode.dataset,gradingPanelFunctions=await Grader.getGradingPanelFunctions("mod_forum",data.contextid,data.gradingComponent,data.gradingComponentSubtype,data.gradableItemtype),groupID=data.group?data.group:0;await Grader.launch(getUsersForCmidFunction(data.cmid,groupID),getContentForUserIdFunction(data.cmid,"1"==data.experimentalDisplayMode),gradingPanelFunctions.getter,gradingPanelFunctions.setter,{groupid:data.groupid,initialUserId:data.initialuserid,moduleName:data.name,courseName:data.courseName,courseUrl:(0,_url.relativeUrl)("/course/view.php",{id:data.courseId}),sendStudentNotifications:data.sendStudentNotifications,focusOnClose:focusOnClose})}(rootNode,{focusOnClose:e.target})}catch(error){_notification.default.exception(error)}}if(e.target.matches(Selectors.viewGrade)){e.preventDefault();const rootNode=findGradableNode(e.target);if(!rootNode)throw Error("Unable to find a gradable item");if(!rootNode.matches(Selectors.gradableItems.wholeForum))throw Error("Unable to find a valid gradable item");e.preventDefault();try{await async function(rootNode){let{focusOnClose:focusOnClose=null}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const data=rootNode.dataset,gradingPanelFunctions=await Grader.getGradingPanelFunctions("mod_forum",data.contextid,data.gradingComponent,data.gradingComponentSubtype,data.gradableItemtype);await Grader.view(gradingPanelFunctions.getter,data.userid,data.name,{focusOnClose:focusOnClose})}(rootNode,{focusOnClose:e.target})}catch(error){_notification.default.exception(error)}}}))}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.registerLaunchListeners=void 0,Selectors=_interopRequireWildcard(Selectors),_repository=_interopRequireDefault(_repository),_templates=_interopRequireDefault(_templates),Grader=_interopRequireWildcard(Grader),_notification=_interopRequireDefault(_notification),_repository2=_interopRequireDefault(_repository2);const templateNames_contentRegion="mod_forum/grades/grader/discussion/posts",getContentForUserIdFunction=(cmid,experimentalDisplayMode)=>userid=>_repository.default.getDiscussionByUserID(userid,cmid).then((context=>(context.discussions=context.discussions.map(discussionPostMapper),context.experimentaldisplaymode=!!experimentalDisplayMode,_templates.default.render(templateNames_contentRegion,context)))).catch(_notification.default.exception),getUsersForCmidFunction=(cmid,groupID,onlyActive)=>async()=>(await _repository2.default.getUsersFromCourseModuleID(cmid,groupID,onlyActive)).users,findGradableNode=node=>node.closest(Selectors.gradableItem),discussionPostMapper=discussion=>{const parentMap=new Map;discussion.posts.parentposts.forEach((post=>parentMap.set(post.id,post)));const userPosts=discussion.posts.userposts.map((post=>{post.readonly=!0,post.hasreplies=!1,post.replies=[];const parent=post.parentid?parentMap.get(post.parentid):null;return parent&&(parent.hasreplies=!1,parent.replies=[],parent.readonly=!0,post.parentauthorname=parent.author.fullname),{parent:parent,post:post}}));return{...discussion,posts:userPosts}};_exports.registerLaunchListeners=()=>{document.addEventListener("click",(async e=>{if(e.target.matches(Selectors.launch)){const rootNode=findGradableNode(e.target);if(!rootNode)throw Error("Unable to find a gradable item");if(!rootNode.matches(Selectors.gradableItems.wholeForum))throw Error("Unable to find a valid gradable item");e.preventDefault();try{await async function(rootNode){let{focusOnClose:focusOnClose=null}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const data=rootNode.dataset,gradingPanelFunctions=await Grader.getGradingPanelFunctions("mod_forum",data.contextid,data.gradingComponent,data.gradingComponentSubtype,data.gradableItemtype),groupID=data.group?data.group:0,onlyActive=data.gradeOnlyActiveUsers;await Grader.launch(getUsersForCmidFunction(data.cmid,groupID,onlyActive),getContentForUserIdFunction(data.cmid,"1"==data.experimentalDisplayMode),gradingPanelFunctions.getter,gradingPanelFunctions.setter,{groupid:data.groupid,initialUserId:data.initialuserid,moduleName:data.name,courseName:data.courseName,courseUrl:(0,_url.relativeUrl)("/course/view.php",{id:data.courseId}),sendStudentNotifications:data.sendStudentNotifications,focusOnClose:focusOnClose})}(rootNode,{focusOnClose:e.target})}catch(error){_notification.default.exception(error)}}if(e.target.matches(Selectors.viewGrade)){e.preventDefault();const rootNode=findGradableNode(e.target);if(!rootNode)throw Error("Unable to find a gradable item");if(!rootNode.matches(Selectors.gradableItems.wholeForum))throw Error("Unable to find a valid gradable item");e.preventDefault();try{await async function(rootNode){let{focusOnClose:focusOnClose=null}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const data=rootNode.dataset,gradingPanelFunctions=await Grader.getGradingPanelFunctions("mod_forum",data.contextid,data.gradingComponent,data.gradingComponentSubtype,data.gradableItemtype);await Grader.view(gradingPanelFunctions.getter,data.userid,data.name,{focusOnClose:focusOnClose})}(rootNode,{focusOnClose:e.target})}catch(error){_notification.default.exception(error)}}}))}})); //# sourceMappingURL=grader.min.js.map \ No newline at end of file diff --git a/mod/forum/amd/build/grades/grader.min.js.map b/mod/forum/amd/build/grades/grader.min.js.map index 61aab8f47c0..b2e5cda5e3a 100644 --- a/mod/forum/amd/build/grades/grader.min.js.map +++ b/mod/forum/amd/build/grades/grader.min.js.map @@ -1 +1 @@ -{"version":3,"file":"grader.min.js","sources":["../../src/grades/grader.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 * This module will tie together all of the different calls the gradable module will make.\n *\n * @module mod_forum/grades/grader\n * @copyright 2019 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as Selectors from './grader/selectors';\nimport Repository from 'mod_forum/repository';\nimport Templates from 'core/templates';\nimport * as Grader from '../local/grades/grader';\nimport Notification from 'core/notification';\nimport CourseRepository from 'core_course/repository';\nimport {relativeUrl} from 'core/url';\n\nconst templateNames = {\n contentRegion: 'mod_forum/grades/grader/discussion/posts',\n};\n\n/**\n * Curried function with CMID set, this is then used in unified grader as a fetch a users content.\n *\n * @param {Number} cmid\n * @param {Bool} experimentalDisplayMode\n * @return {Function}\n */\nconst getContentForUserIdFunction = (cmid, experimentalDisplayMode) => (userid) => {\n /**\n * Given the parent function is called with the second param set execute the partially executed function.\n *\n * @param {Number} userid\n */\n return Repository.getDiscussionByUserID(userid, cmid)\n .then(context => {\n // Rebuild the returned data for the template.\n context.discussions = context.discussions.map(discussionPostMapper);\n context.experimentaldisplaymode = experimentalDisplayMode ? true : false;\n\n return Templates.render(templateNames.contentRegion, context);\n })\n .catch(Notification.exception);\n};\n\n/**\n * Curried function with CMID set, this is then used in unified grader as a fetch users call.\n * The function curried fetches all users in a course for a given CMID.\n *\n * @param {Number} cmid\n * @param {Number} groupID\n * @return {Array} Array of users for a given context.\n */\nconst getUsersForCmidFunction = (cmid, groupID) => async() => {\n const context = await CourseRepository.getUsersFromCourseModuleID(cmid, groupID);\n\n return context.users;\n};\n\n\nconst findGradableNode = node => node.closest(Selectors.gradableItem);\n\n/**\n * For a discussion we need to manipulate it's posts to hide certain UI elements.\n *\n * @param {Object} discussion\n * @return {Array} name, id, posts\n */\nconst discussionPostMapper = (discussion) => {\n // Map postid => post.\n const parentMap = new Map();\n discussion.posts.parentposts.forEach(post => parentMap.set(post.id, post));\n const userPosts = discussion.posts.userposts.map(post => {\n post.readonly = true;\n post.hasreplies = false;\n post.replies = [];\n\n const parent = post.parentid ? parentMap.get(post.parentid) : null;\n if (parent) {\n parent.hasreplies = false;\n parent.replies = [];\n parent.readonly = true;\n post.parentauthorname = parent.author.fullname;\n }\n\n return {\n parent,\n post\n };\n });\n\n return {\n ...discussion,\n posts: userPosts,\n };\n};\n\n/**\n * Launch the Grader.\n *\n * @param {HTMLElement} rootNode the root HTML element describing what is to be graded\n * @param {object} param\n * @param {bool} [param.focusOnClose=null]\n */\nconst launchWholeForumGrading = async(rootNode, {\n focusOnClose = null,\n} = {}) => {\n const data = rootNode.dataset;\n const gradingPanelFunctions = await Grader.getGradingPanelFunctions(\n 'mod_forum',\n data.contextid,\n data.gradingComponent,\n data.gradingComponentSubtype,\n data.gradableItemtype\n );\n\n const groupID = data.group ? data.group : 0;\n\n await Grader.launch(\n getUsersForCmidFunction(data.cmid, groupID),\n getContentForUserIdFunction(data.cmid, data.experimentalDisplayMode == \"1\"),\n gradingPanelFunctions.getter,\n gradingPanelFunctions.setter,\n {\n groupid: data.groupid,\n initialUserId: data.initialuserid,\n moduleName: data.name,\n courseName: data.courseName,\n courseUrl: relativeUrl('/course/view.php', {id: data.courseId}),\n sendStudentNotifications: data.sendStudentNotifications,\n focusOnClose,\n }\n );\n};\n\n/**\n * Launch the Grader.\n *\n * @param {HTMLElement} rootNode the root HTML element describing what is to be graded\n * @param {object} param\n * @param {bool} [param.focusOnClose=null]\n */\nconst launchViewGrading = async(rootNode, {\n focusOnClose = null,\n} = {}) => {\n const data = rootNode.dataset;\n const gradingPanelFunctions = await Grader.getGradingPanelFunctions(\n 'mod_forum',\n data.contextid,\n data.gradingComponent,\n data.gradingComponentSubtype,\n data.gradableItemtype\n );\n\n await Grader.view(\n gradingPanelFunctions.getter,\n data.userid,\n data.name,\n {\n focusOnClose,\n }\n );\n};\n\n/**\n * Register listeners to launch the grading panel.\n */\nexport const registerLaunchListeners = () => {\n document.addEventListener('click', async(e) => {\n if (e.target.matches(Selectors.launch)) {\n const rootNode = findGradableNode(e.target);\n\n if (!rootNode) {\n throw Error('Unable to find a gradable item');\n }\n\n if (rootNode.matches(Selectors.gradableItems.wholeForum)) {\n // Note: The preventDefault must be before any async function calls because the function becomes async\n // at that point and the default action is implemented.\n e.preventDefault();\n try {\n await launchWholeForumGrading(rootNode, {\n focusOnClose: e.target,\n });\n } catch (error) {\n Notification.exception(error);\n }\n } else {\n throw Error('Unable to find a valid gradable item');\n }\n }\n if (e.target.matches(Selectors.viewGrade)) {\n e.preventDefault();\n const rootNode = findGradableNode(e.target);\n\n if (!rootNode) {\n throw Error('Unable to find a gradable item');\n }\n\n if (rootNode.matches(Selectors.gradableItems.wholeForum)) {\n // Note: The preventDefault must be before any async function calls because the function becomes async\n // at that point and the default action is implemented.\n e.preventDefault();\n try {\n await launchViewGrading(rootNode, {\n focusOnClose: e.target,\n });\n } catch (error) {\n Notification.exception(error);\n }\n } else {\n throw Error('Unable to find a valid gradable item');\n }\n }\n });\n};\n"],"names":["templateNames","getContentForUserIdFunction","cmid","experimentalDisplayMode","userid","Repository","getDiscussionByUserID","then","context","discussions","map","discussionPostMapper","experimentaldisplaymode","Templates","render","catch","Notification","exception","getUsersForCmidFunction","groupID","async","CourseRepository","getUsersFromCourseModuleID","users","findGradableNode","node","closest","Selectors","gradableItem","discussion","parentMap","Map","posts","parentposts","forEach","post","set","id","userPosts","userposts","readonly","hasreplies","replies","parent","parentid","get","parentauthorname","author","fullname","document","addEventListener","e","target","matches","launch","rootNode","Error","gradableItems","wholeForum","preventDefault","focusOnClose","data","dataset","gradingPanelFunctions","Grader","getGradingPanelFunctions","contextid","gradingComponent","gradingComponentSubtype","gradableItemtype","group","getter","setter","groupid","initialUserId","initialuserid","moduleName","name","courseName","courseUrl","courseId","sendStudentNotifications","launchWholeForumGrading","error","viewGrade","view","launchViewGrading"],"mappings":";;;;;;;mYA8BMA,4BACa,2CAUbC,4BAA8B,CAACC,KAAMC,0BAA6BC,QAM7DC,oBAAWC,sBAAsBF,OAAQF,MAC3CK,MAAKC,UAEFA,QAAQC,YAAcD,QAAQC,YAAYC,IAAIC,sBAC9CH,QAAQI,0BAA0BT,wBAE3BU,mBAAUC,OAAOd,4BAA6BQ,YAExDO,MAAMC,sBAAaC,WAWtBC,wBAA0B,CAAChB,KAAMiB,UAAYC,gBACzBC,qBAAiBC,2BAA2BpB,KAAMiB,UAEzDI,MAIbC,iBAAmBC,MAAQA,KAAKC,QAAQC,UAAUC,cAQlDjB,qBAAwBkB,mBAEpBC,UAAY,IAAIC,IACtBF,WAAWG,MAAMC,YAAYC,SAAQC,MAAQL,UAAUM,IAAID,KAAKE,GAAIF,cAC9DG,UAAYT,WAAWG,MAAMO,UAAU7B,KAAIyB,OAC7CA,KAAKK,UAAW,EAChBL,KAAKM,YAAa,EAClBN,KAAKO,QAAU,SAETC,OAASR,KAAKS,SAAWd,UAAUe,IAAIV,KAAKS,UAAY,YAC1DD,SACAA,OAAOF,YAAa,EACpBE,OAAOD,QAAU,GACjBC,OAAOH,UAAW,EAClBL,KAAKW,iBAAmBH,OAAOI,OAAOC,UAGnC,CACHL,OAAAA,OACAR,KAAAA,eAID,IACAN,WACHG,MAAOM,6CA0EwB,KACnCW,SAASC,iBAAiB,SAAS9B,MAAAA,OAC3B+B,EAAEC,OAAOC,QAAQ1B,UAAU2B,QAAS,OAC9BC,SAAW/B,iBAAiB2B,EAAEC,YAE/BG,eACKC,MAAM,sCAGZD,SAASF,QAAQ1B,UAAU8B,cAAcC,kBAYnCF,MAAM,wCATZL,EAAEQ,2BA3EcvC,eAAMmC,cAAUK,aAC5CA,aAAe,6DACf,SACMC,KAAON,SAASO,QAChBC,4BAA8BC,OAAOC,yBACvC,YACAJ,KAAKK,UACLL,KAAKM,iBACLN,KAAKO,wBACLP,KAAKQ,kBAGHlD,QAAU0C,KAAKS,MAAQT,KAAKS,MAAQ,QAEpCN,OAAOV,OACTpC,wBAAwB2C,KAAK3D,KAAMiB,SACnClB,4BAA4B4D,KAAK3D,KAAsC,KAAhC2D,KAAK1D,yBAC5C4D,sBAAsBQ,OACtBR,sBAAsBS,OACtB,CACIC,QAASZ,KAAKY,QACdC,cAAeb,KAAKc,cACpBC,WAAYf,KAAKgB,KACjBC,WAAYjB,KAAKiB,WACjBC,WAAW,oBAAY,mBAAoB,CAAC1C,GAAIwB,KAAKmB,WACrDC,yBAA0BpB,KAAKoB,yBAC/BrB,aAAAA,eAmDcsB,CAAwB3B,SAAU,CACpCK,aAAcT,EAAEC,SAEtB,MAAO+B,6BACQlE,UAAUkE,WAM/BhC,EAAEC,OAAOC,QAAQ1B,UAAUyD,WAAY,CACvCjC,EAAEQ,uBACIJ,SAAW/B,iBAAiB2B,EAAEC,YAE/BG,eACKC,MAAM,sCAGZD,SAASF,QAAQ1B,UAAU8B,cAAcC,kBAYnCF,MAAM,wCATZL,EAAEQ,2BA5DQvC,eAAMmC,cAAUK,aACtCA,aAAe,6DACf,SACMC,KAAON,SAASO,QAChBC,4BAA8BC,OAAOC,yBACvC,YACAJ,KAAKK,UACLL,KAAKM,iBACLN,KAAKO,wBACLP,KAAKQ,wBAGHL,OAAOqB,KACTtB,sBAAsBQ,OACtBV,KAAKzD,OACLyD,KAAKgB,KACL,CACIjB,aAAAA,eA6Cc0B,CAAkB/B,SAAU,CAC9BK,aAAcT,EAAEC,SAEtB,MAAO+B,6BACQlE,UAAUkE"} \ No newline at end of file +{"version":3,"file":"grader.min.js","sources":["../../src/grades/grader.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 * This module will tie together all of the different calls the gradable module will make.\n *\n * @module mod_forum/grades/grader\n * @copyright 2019 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as Selectors from './grader/selectors';\nimport Repository from 'mod_forum/repository';\nimport Templates from 'core/templates';\nimport * as Grader from '../local/grades/grader';\nimport Notification from 'core/notification';\nimport CourseRepository from 'core_course/repository';\nimport {relativeUrl} from 'core/url';\n\nconst templateNames = {\n contentRegion: 'mod_forum/grades/grader/discussion/posts',\n};\n\n/**\n * Curried function with CMID set, this is then used in unified grader as a fetch a users content.\n *\n * @param {Number} cmid\n * @param {Bool} experimentalDisplayMode\n * @return {Function}\n */\nconst getContentForUserIdFunction = (cmid, experimentalDisplayMode) => (userid) => {\n /**\n * Given the parent function is called with the second param set execute the partially executed function.\n *\n * @param {Number} userid\n */\n return Repository.getDiscussionByUserID(userid, cmid)\n .then(context => {\n // Rebuild the returned data for the template.\n context.discussions = context.discussions.map(discussionPostMapper);\n context.experimentaldisplaymode = experimentalDisplayMode ? true : false;\n\n return Templates.render(templateNames.contentRegion, context);\n })\n .catch(Notification.exception);\n};\n\n/**\n * Curried function with CMID set, this is then used in unified grader as a fetch users call.\n * The function curried fetches all users in a course for a given CMID.\n *\n * @param {Number} cmid\n * @param {Number} groupID\n * @param {Boolean} onlyActive Whether to fetch only the active enrolled users or all enrolled users in the course.\n * @return {Array} Array of users for a given context.\n */\nconst getUsersForCmidFunction = (cmid, groupID, onlyActive) => async() => {\n const context = await CourseRepository.getUsersFromCourseModuleID(cmid, groupID, onlyActive);\n\n return context.users;\n};\n\n\nconst findGradableNode = node => node.closest(Selectors.gradableItem);\n\n/**\n * For a discussion we need to manipulate it's posts to hide certain UI elements.\n *\n * @param {Object} discussion\n * @return {Array} name, id, posts\n */\nconst discussionPostMapper = (discussion) => {\n // Map postid => post.\n const parentMap = new Map();\n discussion.posts.parentposts.forEach(post => parentMap.set(post.id, post));\n const userPosts = discussion.posts.userposts.map(post => {\n post.readonly = true;\n post.hasreplies = false;\n post.replies = [];\n\n const parent = post.parentid ? parentMap.get(post.parentid) : null;\n if (parent) {\n parent.hasreplies = false;\n parent.replies = [];\n parent.readonly = true;\n post.parentauthorname = parent.author.fullname;\n }\n\n return {\n parent,\n post\n };\n });\n\n return {\n ...discussion,\n posts: userPosts,\n };\n};\n\n/**\n * Launch the Grader.\n *\n * @param {HTMLElement} rootNode the root HTML element describing what is to be graded\n * @param {object} param\n * @param {bool} [param.focusOnClose=null]\n */\nconst launchWholeForumGrading = async(rootNode, {\n focusOnClose = null,\n} = {}) => {\n const data = rootNode.dataset;\n const gradingPanelFunctions = await Grader.getGradingPanelFunctions(\n 'mod_forum',\n data.contextid,\n data.gradingComponent,\n data.gradingComponentSubtype,\n data.gradableItemtype\n );\n\n const groupID = data.group ? data.group : 0;\n const onlyActive = data.gradeOnlyActiveUsers;\n\n await Grader.launch(\n getUsersForCmidFunction(data.cmid, groupID, onlyActive),\n getContentForUserIdFunction(data.cmid, data.experimentalDisplayMode == \"1\"),\n gradingPanelFunctions.getter,\n gradingPanelFunctions.setter,\n {\n groupid: data.groupid,\n initialUserId: data.initialuserid,\n moduleName: data.name,\n courseName: data.courseName,\n courseUrl: relativeUrl('/course/view.php', {id: data.courseId}),\n sendStudentNotifications: data.sendStudentNotifications,\n focusOnClose,\n }\n );\n};\n\n/**\n * Launch the Grader.\n *\n * @param {HTMLElement} rootNode the root HTML element describing what is to be graded\n * @param {object} param\n * @param {bool} [param.focusOnClose=null]\n */\nconst launchViewGrading = async(rootNode, {\n focusOnClose = null,\n} = {}) => {\n const data = rootNode.dataset;\n const gradingPanelFunctions = await Grader.getGradingPanelFunctions(\n 'mod_forum',\n data.contextid,\n data.gradingComponent,\n data.gradingComponentSubtype,\n data.gradableItemtype\n );\n\n await Grader.view(\n gradingPanelFunctions.getter,\n data.userid,\n data.name,\n {\n focusOnClose,\n }\n );\n};\n\n/**\n * Register listeners to launch the grading panel.\n */\nexport const registerLaunchListeners = () => {\n document.addEventListener('click', async(e) => {\n if (e.target.matches(Selectors.launch)) {\n const rootNode = findGradableNode(e.target);\n\n if (!rootNode) {\n throw Error('Unable to find a gradable item');\n }\n\n if (rootNode.matches(Selectors.gradableItems.wholeForum)) {\n // Note: The preventDefault must be before any async function calls because the function becomes async\n // at that point and the default action is implemented.\n e.preventDefault();\n try {\n await launchWholeForumGrading(rootNode, {\n focusOnClose: e.target,\n });\n } catch (error) {\n Notification.exception(error);\n }\n } else {\n throw Error('Unable to find a valid gradable item');\n }\n }\n if (e.target.matches(Selectors.viewGrade)) {\n e.preventDefault();\n const rootNode = findGradableNode(e.target);\n\n if (!rootNode) {\n throw Error('Unable to find a gradable item');\n }\n\n if (rootNode.matches(Selectors.gradableItems.wholeForum)) {\n // Note: The preventDefault must be before any async function calls because the function becomes async\n // at that point and the default action is implemented.\n e.preventDefault();\n try {\n await launchViewGrading(rootNode, {\n focusOnClose: e.target,\n });\n } catch (error) {\n Notification.exception(error);\n }\n } else {\n throw Error('Unable to find a valid gradable item');\n }\n }\n });\n};\n"],"names":["templateNames","getContentForUserIdFunction","cmid","experimentalDisplayMode","userid","Repository","getDiscussionByUserID","then","context","discussions","map","discussionPostMapper","experimentaldisplaymode","Templates","render","catch","Notification","exception","getUsersForCmidFunction","groupID","onlyActive","async","CourseRepository","getUsersFromCourseModuleID","users","findGradableNode","node","closest","Selectors","gradableItem","discussion","parentMap","Map","posts","parentposts","forEach","post","set","id","userPosts","userposts","readonly","hasreplies","replies","parent","parentid","get","parentauthorname","author","fullname","document","addEventListener","e","target","matches","launch","rootNode","Error","gradableItems","wholeForum","preventDefault","focusOnClose","data","dataset","gradingPanelFunctions","Grader","getGradingPanelFunctions","contextid","gradingComponent","gradingComponentSubtype","gradableItemtype","group","gradeOnlyActiveUsers","getter","setter","groupid","initialUserId","initialuserid","moduleName","name","courseName","courseUrl","courseId","sendStudentNotifications","launchWholeForumGrading","error","viewGrade","view","launchViewGrading"],"mappings":";;;;;;;mYA8BMA,4BACa,2CAUbC,4BAA8B,CAACC,KAAMC,0BAA6BC,QAM7DC,oBAAWC,sBAAsBF,OAAQF,MAC3CK,MAAKC,UAEFA,QAAQC,YAAcD,QAAQC,YAAYC,IAAIC,sBAC9CH,QAAQI,0BAA0BT,wBAE3BU,mBAAUC,OAAOd,4BAA6BQ,YAExDO,MAAMC,sBAAaC,WAYtBC,wBAA0B,CAAChB,KAAMiB,QAASC,aAAeC,gBACrCC,qBAAiBC,2BAA2BrB,KAAMiB,QAASC,aAElEI,MAIbC,iBAAmBC,MAAQA,KAAKC,QAAQC,UAAUC,cAQlDlB,qBAAwBmB,mBAEpBC,UAAY,IAAIC,IACtBF,WAAWG,MAAMC,YAAYC,SAAQC,MAAQL,UAAUM,IAAID,KAAKE,GAAIF,cAC9DG,UAAYT,WAAWG,MAAMO,UAAU9B,KAAI0B,OAC7CA,KAAKK,UAAW,EAChBL,KAAKM,YAAa,EAClBN,KAAKO,QAAU,SAETC,OAASR,KAAKS,SAAWd,UAAUe,IAAIV,KAAKS,UAAY,YAC1DD,SACAA,OAAOF,YAAa,EACpBE,OAAOD,QAAU,GACjBC,OAAOH,UAAW,EAClBL,KAAKW,iBAAmBH,OAAOI,OAAOC,UAGnC,CACHL,OAAAA,OACAR,KAAAA,eAID,IACAN,WACHG,MAAOM,6CA2EwB,KACnCW,SAASC,iBAAiB,SAAS9B,MAAAA,OAC3B+B,EAAEC,OAAOC,QAAQ1B,UAAU2B,QAAS,OAC9BC,SAAW/B,iBAAiB2B,EAAEC,YAE/BG,eACKC,MAAM,sCAGZD,SAASF,QAAQ1B,UAAU8B,cAAcC,kBAYnCF,MAAM,wCATZL,EAAEQ,2BA5EcvC,eAAMmC,cAAUK,aAC5CA,aAAe,6DACf,SACMC,KAAON,SAASO,QAChBC,4BAA8BC,OAAOC,yBACvC,YACAJ,KAAKK,UACLL,KAAKM,iBACLN,KAAKO,wBACLP,KAAKQ,kBAGHnD,QAAU2C,KAAKS,MAAQT,KAAKS,MAAQ,EACpCnD,WAAa0C,KAAKU,2BAElBP,OAAOV,OACTrC,wBAAwB4C,KAAK5D,KAAMiB,QAASC,YAC5CnB,4BAA4B6D,KAAK5D,KAAsC,KAAhC4D,KAAK3D,yBAC5C6D,sBAAsBS,OACtBT,sBAAsBU,OACtB,CACIC,QAASb,KAAKa,QACdC,cAAed,KAAKe,cACpBC,WAAYhB,KAAKiB,KACjBC,WAAYlB,KAAKkB,WACjBC,WAAW,oBAAY,mBAAoB,CAAC3C,GAAIwB,KAAKoB,WACrDC,yBAA0BrB,KAAKqB,yBAC/BtB,aAAAA,eAmDcuB,CAAwB5B,SAAU,CACpCK,aAAcT,EAAEC,SAEtB,MAAOgC,6BACQpE,UAAUoE,WAM/BjC,EAAEC,OAAOC,QAAQ1B,UAAU0D,WAAY,CACvClC,EAAEQ,uBACIJ,SAAW/B,iBAAiB2B,EAAEC,YAE/BG,eACKC,MAAM,sCAGZD,SAASF,QAAQ1B,UAAU8B,cAAcC,kBAYnCF,MAAM,wCATZL,EAAEQ,2BA5DQvC,eAAMmC,cAAUK,aACtCA,aAAe,6DACf,SACMC,KAAON,SAASO,QAChBC,4BAA8BC,OAAOC,yBACvC,YACAJ,KAAKK,UACLL,KAAKM,iBACLN,KAAKO,wBACLP,KAAKQ,wBAGHL,OAAOsB,KACTvB,sBAAsBS,OACtBX,KAAK1D,OACL0D,KAAKiB,KACL,CACIlB,aAAAA,eA6Cc2B,CAAkBhC,SAAU,CAC9BK,aAAcT,EAAEC,SAEtB,MAAOgC,6BACQpE,UAAUoE"} \ No newline at end of file diff --git a/mod/forum/amd/src/grades/grader.js b/mod/forum/amd/src/grades/grader.js index 71c146d0650..5be32cf3f74 100644 --- a/mod/forum/amd/src/grades/grader.js +++ b/mod/forum/amd/src/grades/grader.js @@ -62,10 +62,11 @@ const getContentForUserIdFunction = (cmid, experimentalDisplayMode) => (userid) * * @param {Number} cmid * @param {Number} groupID + * @param {Boolean} onlyActive Whether to fetch only the active enrolled users or all enrolled users in the course. * @return {Array} Array of users for a given context. */ -const getUsersForCmidFunction = (cmid, groupID) => async() => { - const context = await CourseRepository.getUsersFromCourseModuleID(cmid, groupID); +const getUsersForCmidFunction = (cmid, groupID, onlyActive) => async() => { + const context = await CourseRepository.getUsersFromCourseModuleID(cmid, groupID, onlyActive); return context.users; }; @@ -128,9 +129,10 @@ const launchWholeForumGrading = async(rootNode, { ); const groupID = data.group ? data.group : 0; + const onlyActive = data.gradeOnlyActiveUsers; await Grader.launch( - getUsersForCmidFunction(data.cmid, groupID), + getUsersForCmidFunction(data.cmid, groupID, onlyActive), getContentForUserIdFunction(data.cmid, data.experimentalDisplayMode == "1"), gradingPanelFunctions.getter, gradingPanelFunctions.setter, diff --git a/mod/forum/classes/grades/forum_gradeitem.php b/mod/forum/classes/grades/forum_gradeitem.php index 0094e578cf3..5760cb61b0e 100644 --- a/mod/forum/classes/grades/forum_gradeitem.php +++ b/mod/forum/classes/grades/forum_gradeitem.php @@ -236,6 +236,23 @@ class forum_gradeitem extends component_gradeitem { return (int) $this->forum->get_id(); } + /** + * Defines whether only active users in the course should be gradeable. + * + * @return bool Whether only active users in the course should be gradeable. + */ + public function should_grade_only_active_users(): bool { + global $CFG; + + $showonlyactiveenrolconfig = !empty($CFG->grade_report_showonlyactiveenrol); + // Grade only active users enrolled in the course either when the 'grade_report_showonlyactiveenrol' user + // preference is set to true or the current user does not have the capability to view suspended users in the + // course. In cases where the 'grade_report_showonlyactiveenrol' user preference is not set we are falling back + // to the set value for the 'grade_report_showonlyactiveenrol' config. + return get_user_preferences('grade_report_showonlyactiveenrol', $showonlyactiveenrolconfig) || + !has_capability('moodle/course:viewsuspendedusers', \context_course::instance($this->forum->get_course_id())); + } + /** * Create or update the grade. * diff --git a/mod/forum/classes/local/renderers/discussion_list.php b/mod/forum/classes/local/renderers/discussion_list.php index 6c57ab736b1..d2664393faa 100644 --- a/mod/forum/classes/local/renderers/discussion_list.php +++ b/mod/forum/classes/local/renderers/discussion_list.php @@ -197,6 +197,7 @@ class discussion_list { 'gradingcomponent' => $this->forumgradeitem->get_grading_component_name(), 'gradingcomponentsubtype' => $this->forumgradeitem->get_grading_component_subtype(), 'sendstudentnotifications' => $forum->should_notify_students_default_when_grade_for_forum(), + 'gradeonlyactiveusers' => $this->forumgradeitem->should_grade_only_active_users(), 'hasanyactions' => $hasanyactions, 'groupchangemenu' => groups_print_activity_menu( $cm, diff --git a/mod/forum/templates/grades/grade_button.mustache b/mod/forum/templates/grades/grade_button.mustache index e84e9a0fb82..ba51b3587b3 100644 --- a/mod/forum/templates/grades/grade_button.mustache +++ b/mod/forum/templates/grades/grade_button.mustache @@ -43,6 +43,7 @@ data-grading-component="{{gradingcomponent}}" data-grading-component-subtype="{{gradingcomponentsubtype}}" data-gradable-itemtype="forum" + data-grade-only-active-users="{{gradeonlyactiveusers}}" {{#sendstudentnotifications}}data-send-student-notifications="1" {{/sendstudentnotifications}} > {{#str}}gradeusers, forum{{/str}} diff --git a/mod/forum/tests/grades_forum_gradeitem_test.php b/mod/forum/tests/grades_forum_gradeitem_test.php index a7da3930c25..2e820fa4f7b 100644 --- a/mod/forum/tests/grades_forum_gradeitem_test.php +++ b/mod/forum/tests/grades_forum_gradeitem_test.php @@ -169,6 +169,91 @@ class grades_forum_gradeitem_test extends \advanced_testcase { ]); } + /** + * Test the logic in the should_grade_only_active_users() method. + * + * @covers ::should_grade_only_active_users + * @dataProvider should_grade_only_active_users_provider + * @param bool $showonlyactiveenrolconfig Whether the 'grade_report_showonlyactiveenrol' is enabled or not. + * @param bool $showonlyactiveenrolpreference Whether the 'grade_report_showonlyactiveenrol' preference is enabled or not. + * @param bool $viewsuspendeduserscapability Whether the 'moodle/course:viewsuspendedusers' capability is allowed or not. + * @param bool $expected The expected result. + */ + public function test_should_grade_only_active_users(bool $showonlyactiveenrolconfig, bool $showonlyactiveenrolpreference, + bool $viewsuspendeduserscapability, bool $expected): void { + global $DB; + + $this->resetAfterTest(); + + $forum = $this->get_forum_instance([ + 'grade_forum' => 100, + ]); + $course = $forum->get_course_record(); + $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum'); + + $user = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher'); + $editingteacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']); + + // Set the 'grade_report_showonlyactiveenrol' config setting. + set_config('grade_report_showonlyactiveenrol', $showonlyactiveenrolconfig); + + $this->setUser($user); + // Set the 'grade_report_showonlyactiveenrol' user preference. + set_user_preference('grade_report_showonlyactiveenrol', $showonlyactiveenrolpreference); + + // Set the 'moodle/course:viewsuspendedusers' user capability. + assign_capability('moodle/course:viewsuspendedusers', $viewsuspendeduserscapability ? + CAP_ALLOW : CAP_PROHIBIT, $editingteacherroleid, \context_course::instance($course->id)); + + $this->assertEquals($expected, $gradeitem->should_grade_only_active_users()); + } + + /** + * Data provider for test_should_grade_only_active_users. + * + * @return array + */ + public function should_grade_only_active_users_provider(): array { + return [ + 'Enabled showonlyactiveenrol setting; enabled showonlyactiveenrol preference; view suspended users capability' => + [ + 'showonlyactiveenrolconfig' => true, + 'showonlyactiveenrolpreference' => true, + 'viewsuspendeduserscapability' => true, + 'expected' => true, + ], + 'Disabled showonlyactiveenrol setting; enabled showonlyactiveenrol preference; view suspended users capability' => + [ + 'showonlyactiveenrolconfig' => false, + 'showonlyactiveenrolpreference' => true, + 'viewsuspendeduserscapability' => true, + 'expected' => true, + ], + 'Disabled showonlyactiveenrol setting; disabled showonlyactiveenrol preference; view suspended users capability' => + [ + 'showonlyactiveenrolconfig' => false, + 'showonlyactiveenrolpreference' => false, + 'viewsuspendeduserscapability' => true, + 'expected' => false, + ], + 'Disabled showonlyactiveenrol setting; disabled showonlyactiveenrol preference; no view suspended users capability' => + [ + 'showonlyactiveenrolconfig' => false, + 'showonlyactiveenrolpreference' => false, + 'viewsuspendeduserscapability' => false, + 'expected' => true, + ], + 'Enabled showonlyactiveenrol setting; enabled showonlyactiveenrol preference; no view suspended users capability' => + [ + 'showonlyactiveenrolconfig' => true, + 'showonlyactiveenrolpreference' => true, + 'viewsuspendeduserscapability' => false, + 'expected' => true, + ], + ]; + } + /** * Get a forum instance. * diff --git a/mod/forum/view.php b/mod/forum/view.php index fd7c14c132f..c45e8eba055 100644 --- a/mod/forum/view.php +++ b/mod/forum/view.php @@ -197,6 +197,7 @@ switch ($forum->get_type()) { 'gradingcomponent' => $forumgradeitem->get_grading_component_name(), 'gradingcomponentsubtype' => $forumgradeitem->get_grading_component_subtype(), 'sendstudentnotifications' => $forum->should_notify_students_default_when_grade_for_forum(), + 'gradeonlyactiveusers' => $forumgradeitem->should_grade_only_active_users(), ]; echo $OUTPUT->render_from_template('mod_forum/grades/grade_button', $gradeobj); }