1 // This file is part of Moodle - http://moodle.org/
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 * This module will tie together all of the different calls the gradable module will make.
19 * @module mod_forum/grades/grader
21 * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 import * as Selectors from './grader/selectors';
25 import Repository from 'mod_forum/repository';
26 import Templates from 'core/templates';
27 import * as Grader from '../local/grades/grader';
28 import Notification from 'core/notification';
29 import CourseRepository from 'core_course/repository';
30 import {relativeUrl} from 'core/url';
32 const templateNames = {
33 contentRegion: 'mod_forum/grades/grader/discussion/posts',
37 * Curried function with CMID set, this is then used in unified grader as a fetch a users content.
39 * @param {Number} cmid
42 const getContentForUserIdFunction = (cmid) => (userid) => {
44 * Given the parent function is called with the second param set execute the partially executed function.
46 * @param {Number} userid
48 return Repository.getDiscussionByUserID(userid, cmid)
50 // Rebuild the returned data for the template.
51 context.discussions = context.discussions.map(discussionPostMapper);
53 return Templates.render(templateNames.contentRegion, context);
55 .catch(Notification.exception);
59 * Curried function with CMID set, this is then used in unified grader as a fetch users call.
60 * The function curried fetches all users in a course for a given CMID.
62 * @param {Number} cmid
63 * @return {Array} Array of users for a given context.
65 const getUsersForCmidFunction = (cmid) => async() => {
66 const context = await CourseRepository.getUsersFromCourseModuleID(cmid);
72 const findGradableNode = node => node.closest(Selectors.gradableItem);
75 * For a discussion we need to manipulate it's posts to hide certain UI elements.
77 * @param {Object} discussion
78 * @return {Array} name, id, posts
80 const discussionPostMapper = (discussion) => {
81 // Map postid => post.
82 const parentMap = new Map();
83 discussion.posts.parentposts.forEach(post => parentMap.set(post.id, post));
84 const userPosts = discussion.posts.userposts.map(post => {
87 post.starter = !post.parentid;
88 post.parent = parentMap.get(post.parentid);
89 post.html.rating = null;
96 name: discussion.name,
104 * @param {HTMLElement} rootNode the root HTML element describing what is to be graded
106 const launchWholeForumGrading = async(rootNode) => {
107 const data = rootNode.dataset;
108 const gradingPanelFunctions = await Grader.getGradingPanelFunctions(
111 data.gradingComponent,
112 data.gradingComponentSubtype,
113 data.gradableItemtype
117 getUsersForCmidFunction(data.cmid),
118 getContentForUserIdFunction(data.cmid),
119 gradingPanelFunctions.getter,
120 gradingPanelFunctions.setter,
122 groupid: data.groupid,
123 initialUserId: data.initialuserid,
124 moduleName: data.name,
125 courseName: data.courseName,
126 courseUrl: relativeUrl('/course/view.php', {id: data.courseId})
132 * Register listeners to launch the grading panel.
134 export const registerLaunchListeners = () => {
135 document.addEventListener('click', async(e) => {
136 if (e.target.matches(Selectors.launch)) {
137 const rootNode = findGradableNode(e.target);
140 throw Error('Unable to find a gradable item');
143 if (rootNode.matches(Selectors.gradableItems.wholeForum)) {
144 // Note: The preventDefault must be before any async function calls because the function becomes async
145 // at that point and the default action is implemented.
148 await launchWholeForumGrading(rootNode);
150 Notification.exception(error);
153 throw Error('Unable to find a valid gradable item');