Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Web services relating to fetching of a rubric for the grading panel.
19
 *
20
 * @package    gradingform_rubric
21
 * @copyright  2019 Mathew May <mathew.solutions>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
declare(strict_types = 1);
26
 
27
namespace gradingform_rubric\grades\grader\gradingpanel\external;
28
 
29
global $CFG;
30
 
31
use coding_exception;
32
use context;
33
use core_grades\component_gradeitem as gradeitem;
34
use core_grades\component_gradeitems;
35
use core_external\external_api;
36
use core_external\external_function_parameters;
37
use core_external\external_multiple_structure;
38
use core_external\external_single_structure;
39
use core_external\external_value;
40
use core_external\external_warnings;
41
use stdClass;
42
use moodle_exception;
43
require_once($CFG->dirroot.'/grade/grading/form/rubric/lib.php');
44
 
45
/**
46
 * Web services relating to fetching of a rubric for the grading panel.
47
 *
48
 * @package    gradingform_rubric
49
 * @copyright  2019 Mathew May <mathew.solutions>
50
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
51
 */
52
class fetch extends external_api {
53
 
54
    /**
55
     * Describes the parameters for fetching the grading panel for a simple grade.
56
     *
57
     * @return external_function_parameters
58
     * @since Moodle 3.8
59
     */
60
    public static function execute_parameters(): external_function_parameters {
61
        return new external_function_parameters ([
62
            'component' => new external_value(
63
                PARAM_ALPHANUMEXT,
64
                'The name of the component',
65
                VALUE_REQUIRED
66
            ),
67
            'contextid' => new external_value(
68
                PARAM_INT,
69
                'The ID of the context being graded',
70
                VALUE_REQUIRED
71
            ),
72
            'itemname' => new external_value(
73
                PARAM_ALPHANUM,
74
                'The grade item itemname being graded',
75
                VALUE_REQUIRED
76
            ),
77
            'gradeduserid' => new external_value(
78
                PARAM_INT,
79
                'The ID of the user show',
80
                VALUE_REQUIRED
81
            ),
82
        ]);
83
    }
84
 
85
    /**
86
     * Fetch the data required to build a grading panel for a simple grade.
87
     *
88
     * @param string $component
89
     * @param int $contextid
90
     * @param string $itemname
91
     * @param int $gradeduserid
92
     * @return array
93
     * @since Moodle 3.8
94
     */
95
    public static function execute(string $component, int $contextid, string $itemname, int $gradeduserid): array {
96
        global $CFG, $USER;
97
        require_once("{$CFG->libdir}/gradelib.php");
98
        [
99
            'component' => $component,
100
            'contextid' => $contextid,
101
            'itemname' => $itemname,
102
            'gradeduserid' => $gradeduserid,
103
        ] = self::validate_parameters(self::execute_parameters(), [
104
            'component' => $component,
105
            'contextid' => $contextid,
106
            'itemname' => $itemname,
107
            'gradeduserid' => $gradeduserid,
108
        ]);
109
 
110
        // Validate the context.
111
        $context = context::instance_by_id($contextid);
112
        self::validate_context($context);
113
 
114
        // Validate that the supplied itemname is a gradable item.
115
        if (!component_gradeitems::is_valid_itemname($component, $itemname)) {
116
            throw new coding_exception("The '{$itemname}' item is not valid for the '{$component}' component");
117
        }
118
 
119
        // Fetch the gradeitem instance.
120
        $gradeitem = gradeitem::instance($component, $context, $itemname);
121
 
122
        if (RUBRIC !== $gradeitem->get_advanced_grading_method()) {
123
            throw new moodle_exception(
124
                "The {$itemname} item in {$component}/{$contextid} is not configured for advanced grading with a rubric"
125
            );
126
        }
127
 
128
        // Fetch the actual data.
129
        $gradeduser = \core_user::get_user($gradeduserid, '*', MUST_EXIST);
130
 
131
        // One can access its own grades. Others just if they're graders.
132
        if ($gradeduserid != $USER->id) {
133
            $gradeitem->require_user_can_grade($gradeduser, $USER);
134
        }
135
 
136
        return self::get_fetch_data($gradeitem, $gradeduser);
137
    }
138
 
139
    /**
140
     * Get the data to be fetched and create the structure ready for Mustache.
141
     *
142
     * @param gradeitem $gradeitem
143
     * @param stdClass $gradeduser
144
     * @return array
145
     */
146
    public static function get_fetch_data(gradeitem $gradeitem, stdClass $gradeduser): array {
147
        global $USER;
148
        // Set up all the controllers etc that we'll be needing.
149
        $hasgrade = $gradeitem->user_has_grade($gradeduser);
150
        $grade = $gradeitem->get_formatted_grade_for_user($gradeduser, $USER);
151
        $instance = $gradeitem->get_advanced_grading_instance($USER, $grade);
152
        if (!$instance) {
153
            throw new moodle_exception('error:gradingunavailable', 'grading');
154
        }
155
 
156
        $controller = $instance->get_controller();
157
        $definition = $controller->get_definition();
158
        $fillings = $instance->get_rubric_filling();
159
        $context = $controller->get_context();
160
        $definitionid = (int) $definition->id;
161
 
162
        // Set up some items we need to return on other interfaces.
163
        $gradegrade = \grade_grade::fetch(['itemid' => $gradeitem->get_grade_item()->id, 'userid' => $gradeduser->id]);
164
        $gradername = $gradegrade ? fullname(\core_user::get_user($gradegrade->usermodified)) : null;
165
        $maxgrade = max(array_keys($controller->get_grade_range()));
166
 
167
        $teacherdescription = self::get_formatted_text(
168
            $context,
169
            $definitionid,
170
            'description',
171
            $definition->description,
172
            (int) $definition->descriptionformat
173
        );
174
 
175
        $criterion = [];
176
        if ($definition->rubric_criteria) {
177
            // Iterate over the defined criterion in the rubric and map out what we need to render each item.
178
            $criterion = array_map(function($criterion) use ($definitionid, $fillings, $context, $hasgrade) {
179
                // The general structure we'll be returning, we still need to get the remark (if any) and the levels associated.
180
                $result = [
181
                    'id' => $criterion['id'],
182
                    'description' => self::get_formatted_text(
183
                        $context,
184
                        $definitionid,
185
                        'description',
186
                        $criterion['description'],
187
                        (int) $criterion['descriptionformat']
188
                    ),
189
                ];
190
 
191
                // Do we have an existing grade filling? if so lets get the remark associated to this criteria.
192
                $filling = [];
193
                if (array_key_exists($criterion['id'], $fillings['criteria'])) {
194
                    $filling = $fillings['criteria'][$criterion['id']];
195
                    $result['remark'] = self::get_formatted_text($context,
196
                        $definitionid,
197
                        'remark',
198
                        $filling['remark'],
199
                        (int) $filling['remarkformat']
200
                    );
201
                }
202
 
203
                // Lets build the levels within a criteria and figure out what needs to go where.
204
                $result['levels'] = array_map(function($level) use ($criterion, $filling, $context, $definitionid) {
205
                    // The bulk of what'll be returned can be defined easily we'll add to this further down.
206
                    $result = [
207
                        'id' => $level['id'],
208
                        'criterionid' => $criterion['id'],
209
                        'score' => $level['score'],
210
                        'definition' => self::get_formatted_text(
211
                            $context,
212
                            $definitionid,
213
                            'definition',
214
                            $level['definition'],
215
                            (int) $level['definitionformat']
216
                        ),
217
                        'checked' => null,
218
                    ];
219
 
220
                    // Consult the grade filling to see if a level has been selected and if it is the current level.
221
                    if (array_key_exists('levelid', $filling) && $filling['levelid'] == $level['id']) {
222
                        $result['checked'] = true;
223
                    }
224
 
225
                    return $result;
226
                }, $criterion['levels']);
227
 
228
                $nulllevel = [
229
                    'id' => null,
230
                    'criterionid' => $criterion['id'],
231
                    'score' => '-',
232
                    'definition' => get_string('notset', 'gradingform_rubric'),
233
                    'checked' => !$hasgrade,
234
                ];
235
                // Consult the grade filling to see if a level has been selected and if it is the current level.
236
                if (array_key_exists('levelid', $filling) && $filling['levelid'] == 0) {
237
                    $nulllevel['checked'] = true;
238
                }
239
 
240
                array_unshift($result['levels'], $nulllevel);
241
 
242
                return $result;
243
            }, $definition->rubric_criteria);
244
        }
245
 
246
        return [
247
            'templatename' => 'gradingform_rubric/grades/grader/gradingpanel',
248
            'hasgrade' => $hasgrade,
249
            'grade' => [
250
                'instanceid' => $instance->get_id(),
251
                'criteria' => $criterion,
252
                'rubricmode' => 'evaluate editable',
253
                'teacherdescription' => $teacherdescription,
254
                'canedit' => false,
255
                'usergrade' => $grade->usergrade,
256
                'maxgrade' => $maxgrade,
257
                'gradedby' => $gradername,
258
                'timecreated' => $grade->timecreated,
259
                'timemodified' => $grade->timemodified,
260
            ],
261
            'warnings' => [],
262
        ];
263
    }
264
 
265
    /**
266
     * Describes the data returned from the external function.
267
     *
268
     * @return external_single_structure
269
     * @since Moodle 3.8
270
     */
271
    public static function execute_returns(): external_single_structure {
272
        return new external_single_structure([
273
            'templatename' => new external_value(PARAM_SAFEPATH, 'The template to use when rendering this data'),
274
            'hasgrade' => new external_value(PARAM_BOOL, 'Does the user have a grade?'),
275
            'grade' => new external_single_structure([
276
                'instanceid' => new external_value(PARAM_INT, 'The id of the current grading instance'),
277
                'rubricmode' => new external_value(PARAM_RAW, 'The mode i.e. evaluate editable'),
278
                'canedit' => new external_value(PARAM_BOOL, 'Can the user edit this'),
279
                'criteria' => new external_multiple_structure(
280
                    new external_single_structure([
281
                        'id' => new external_value(PARAM_INT, 'ID of the Criteria'),
282
                        'description' => new external_value(PARAM_RAW, 'Description of the Criteria'),
283
                        'remark' => new external_value(PARAM_RAW, 'Any remarks for this criterion for the user being assessed', VALUE_OPTIONAL),
284
                        'levels' => new external_multiple_structure(new external_single_structure([
285
                            'id' => new external_value(PARAM_INT, 'ID of level'),
286
                            'criterionid' => new external_value(PARAM_INT, 'ID of the criterion this matches to'),
287
                            'score' => new external_value(PARAM_RAW, 'What this level is worth'),
288
                            'definition' => new external_value(PARAM_RAW, 'Definition of the level'),
289
                            'checked' => new external_value(PARAM_BOOL, 'Selected flag'),
290
                        ])),
291
                    ])
292
                ),
293
                'timecreated' => new external_value(PARAM_INT, 'The time that the grade was created'),
294
                'usergrade' => new external_value(PARAM_RAW, 'Current user grade'),
295
                'maxgrade' => new external_value(PARAM_RAW, 'Max possible grade'),
296
                'gradedby' => new external_value(PARAM_RAW, 'The assumed grader of this grading instance'),
297
                'timemodified' => new external_value(PARAM_INT, 'The time that the grade was last updated'),
298
            ]),
299
            'warnings' => new external_warnings(),
300
        ]);
301
    }
302
 
303
    /**
304
     * Get a formatted version of the remark/description/etc.
305
     *
306
     * @param context $context
307
     * @param int $definitionid
308
     * @param string $filearea The file area of the field
309
     * @param string $text The text to be formatted
310
     * @param int $format The input format of the string
311
     * @return string
312
     */
313
    protected static function get_formatted_text(context $context, int $definitionid, string $filearea, string $text, int $format): string {
314
        $formatoptions = [
315
            'noclean' => false,
316
            'trusted' => false,
317
            'filter' => true,
318
        ];
319
        [$newtext] = \core_external\util::format_text(
320
            $text,
321
            $format,
322
            $context,
323
            'grading',
324
            $filearea,
325
            $definitionid,
326
            $formatoptions
327
        );
328
        return $newtext;
329
    }
330
}