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
use mod_feedback\external\feedback_summary_exporter;
18
use mod_feedback\external\feedback_completedtmp_exporter;
19
use mod_feedback\external\feedback_item_exporter;
20
use mod_feedback\external\feedback_valuetmp_exporter;
21
use mod_feedback\external\feedback_value_exporter;
22
use mod_feedback\external\feedback_completed_exporter;
23
use core_external\external_api;
24
use core_external\external_function_parameters;
25
use core_external\external_multiple_structure;
26
use core_external\external_single_structure;
27
use core_external\external_value;
28
use core_external\external_warnings;
29
use core_external\util;
30
 
31
/**
32
 * Feedback external functions
33
 *
34
 * @package    mod_feedback
35
 * @category   external
36
 * @copyright  2017 Juan Leyva <juan@moodle.com>
37
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38
 * @since      Moodle 3.3
39
 */
40
class mod_feedback_external extends external_api {
41
 
42
    /**
43
     * Describes the parameters for get_feedbacks_by_courses.
44
     *
45
     * @return external_function_parameters
46
     * @since Moodle 3.3
47
     */
48
    public static function get_feedbacks_by_courses_parameters() {
49
        return new external_function_parameters (
50
            array(
51
                'courseids' => new external_multiple_structure(
52
                    new external_value(PARAM_INT, 'Course id'), 'Array of course ids', VALUE_DEFAULT, array()
53
                ),
54
            )
55
        );
56
    }
57
 
58
    /**
59
     * Returns a list of feedbacks in a provided list of courses.
60
     * If no list is provided all feedbacks that the user can view will be returned.
61
     *
62
     * @param array $courseids course ids
63
     * @return array of warnings and feedbacks
64
     * @since Moodle 3.3
65
     */
66
    public static function get_feedbacks_by_courses($courseids = array()) {
67
        global $PAGE;
68
 
69
        $warnings = array();
70
        $returnedfeedbacks = array();
71
 
72
        $params = array(
73
            'courseids' => $courseids,
74
        );
75
        $params = self::validate_parameters(self::get_feedbacks_by_courses_parameters(), $params);
76
 
77
        $mycourses = array();
78
        if (empty($params['courseids'])) {
79
            $mycourses = enrol_get_my_courses();
80
            $params['courseids'] = array_keys($mycourses);
81
        }
82
 
83
        // Ensure there are courseids to loop through.
84
        if (!empty($params['courseids'])) {
85
 
86
            list($courses, $warnings) = util::validate_courses($params['courseids'], $mycourses);
87
            $output = $PAGE->get_renderer('core');
88
 
89
            // Get the feedbacks in this course, this function checks users visibility permissions.
90
            // We can avoid then additional validate_context calls.
91
            $feedbacks = get_all_instances_in_courses("feedback", $courses);
92
            foreach ($feedbacks as $feedback) {
93
 
94
                $context = context_module::instance($feedback->coursemodule);
95
 
96
                // Remove fields that are not from the feedback (added by get_all_instances_in_courses).
97
                unset($feedback->coursemodule, $feedback->context, $feedback->visible, $feedback->section, $feedback->groupmode,
98
                        $feedback->groupingid);
99
 
100
                // Check permissions.
101
                if (!has_capability('mod/feedback:edititems', $context)) {
102
                    // Don't return the optional properties.
103
                    $properties = feedback_summary_exporter::properties_definition();
104
                    foreach ($properties as $property => $config) {
105
                        if (!empty($config['optional'])) {
106
                            unset($feedback->{$property});
107
                        }
108
                    }
109
                }
110
                $exporter = new feedback_summary_exporter($feedback, array('context' => $context));
111
                $returnedfeedbacks[] = $exporter->export($output);
112
            }
113
        }
114
 
115
        $result = array(
116
            'feedbacks' => $returnedfeedbacks,
117
            'warnings' => $warnings
118
        );
119
        return $result;
120
    }
121
 
122
    /**
123
     * Describes the get_feedbacks_by_courses return value.
124
     *
125
     * @return external_single_structure
126
     * @since Moodle 3.3
127
     */
128
    public static function get_feedbacks_by_courses_returns() {
129
        return new external_single_structure(
130
            array(
131
                'feedbacks' => new external_multiple_structure(
132
                    feedback_summary_exporter::get_read_structure()
133
                ),
134
                'warnings' => new external_warnings(),
135
            )
136
        );
137
    }
138
 
139
    /**
140
     * Utility function for validating a feedback.
141
     *
142
     * @param int $feedbackid feedback instance id
143
     * @param int $courseid courseid course where user completes the feedback (for site feedbacks only)
144
     * @return array containing the feedback, feedback course, context, course module and the course where is being completed.
145
     * @throws moodle_exception
146
     * @since  Moodle 3.3
147
     */
148
    protected static function validate_feedback($feedbackid, $courseid = 0) {
149
        global $DB, $USER;
150
 
151
        // Request and permission validation.
152
        $feedback = $DB->get_record('feedback', array('id' => $feedbackid), '*', MUST_EXIST);
153
        list($feedbackcourse, $cm) = get_course_and_cm_from_instance($feedback, 'feedback');
154
 
155
        $context = context_module::instance($cm->id);
156
        self::validate_context($context);
157
 
158
        // Set default completion course.
159
        $completioncourse = (object) array('id' => 0);
160
        if ($feedbackcourse->id == SITEID && $courseid) {
161
            $completioncourse = get_course($courseid);
162
            self::validate_context(context_course::instance($courseid));
163
 
164
            $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $courseid);
165
            if (!$feedbackcompletion->check_course_is_mapped()) {
166
                throw new moodle_exception('cannotaccess', 'mod_feedback');
167
            }
168
        }
169
 
170
        return array($feedback, $feedbackcourse, $cm, $context, $completioncourse);
171
    }
172
 
173
    /**
174
     * Utility function for validating access to feedback.
175
     *
176
     * @param  stdClass   $feedback feedback object
177
     * @param  stdClass   $course   course where user completes the feedback (for site feedbacks only)
178
     * @param  stdClass   $cm       course module
179
     * @param  stdClass   $context  context object
180
     * @throws moodle_exception
181
     * @return mod_feedback_completion feedback completion instance
182
     * @since  Moodle 3.3
183
     */
184
    protected static function validate_feedback_access($feedback, $course, $cm, $context, $checksubmit = false) {
185
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id);
186
 
187
        if (!$feedbackcompletion->can_complete()) {
188
            throw new required_capability_exception($context, 'mod/feedback:complete', 'nopermission', '');
189
        }
190
 
191
        if (!$feedbackcompletion->is_open()) {
192
            throw new moodle_exception('feedback_is_not_open', 'feedback');
193
        }
194
 
195
        if ($feedbackcompletion->is_empty()) {
196
            throw new moodle_exception('no_items_available_yet', 'feedback');
197
        }
198
 
199
        if ($checksubmit && !$feedbackcompletion->can_submit()) {
200
            throw new moodle_exception('this_feedback_is_already_submitted', 'feedback');
201
        }
202
        return $feedbackcompletion;
203
    }
204
 
205
    /**
206
     * Describes the parameters for get_feedback_access_information.
207
     *
208
     * @return external_external_function_parameters
209
     * @since Moodle 3.3
210
     */
211
    public static function get_feedback_access_information_parameters() {
212
        return new external_function_parameters (
213
            array(
214
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
215
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
216
                    VALUE_DEFAULT, 0),
217
            )
218
        );
219
    }
220
 
221
    /**
222
     * Return access information for a given feedback.
223
     *
224
     * @param int $feedbackid feedback instance id
225
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
226
     * @return array of warnings and the access information
227
     * @since Moodle 3.3
228
     * @throws  moodle_exception
229
     */
230
    public static function get_feedback_access_information($feedbackid, $courseid = 0) {
231
        global $PAGE;
232
 
233
        $params = array(
234
            'feedbackid' => $feedbackid,
235
            'courseid' => $courseid,
236
        );
237
        $params = self::validate_parameters(self::get_feedback_access_information_parameters(), $params);
238
 
239
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
240
            $params['courseid']);
241
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
242
 
243
        $result = array();
244
        // Capabilities first.
245
        $result['canviewanalysis'] = $feedbackcompletion->can_view_analysis();
246
        $result['cancomplete'] = $feedbackcompletion->can_complete();
247
        $result['cansubmit'] = $feedbackcompletion->can_submit();
248
        $result['candeletesubmissions'] = has_capability('mod/feedback:deletesubmissions', $context);
249
        $result['canviewreports'] = has_capability('mod/feedback:viewreports', $context);
250
        $result['canedititems'] = has_capability('mod/feedback:edititems', $context);
251
 
252
        // Status information.
253
        $result['isempty'] = $feedbackcompletion->is_empty();
254
        $result['isopen'] = $feedbackcompletion->is_open();
255
        $anycourse = ($course->id == SITEID);
256
        $result['isalreadysubmitted'] = $feedbackcompletion->is_already_submitted($anycourse);
257
        $result['isanonymous'] = $feedbackcompletion->is_anonymous();
258
 
259
        $result['warnings'] = [];
260
        return $result;
261
    }
262
 
263
    /**
264
     * Describes the get_feedback_access_information return value.
265
     *
266
     * @return external_single_structure
267
     * @since Moodle 3.3
268
     */
269
    public static function get_feedback_access_information_returns() {
270
        return new external_single_structure(
271
            array(
272
                'canviewanalysis' => new external_value(PARAM_BOOL, 'Whether the user can view the analysis or not.'),
273
                'cancomplete' => new external_value(PARAM_BOOL, 'Whether the user can complete the feedback or not.'),
274
                'cansubmit' => new external_value(PARAM_BOOL, 'Whether the user can submit the feedback or not.'),
275
                'candeletesubmissions' => new external_value(PARAM_BOOL, 'Whether the user can delete submissions or not.'),
276
                'canviewreports' => new external_value(PARAM_BOOL, 'Whether the user can view the feedback reports or not.'),
277
                'canedititems' => new external_value(PARAM_BOOL, 'Whether the user can edit feedback items or not.'),
278
                'isempty' => new external_value(PARAM_BOOL, 'Whether the feedback has questions or not.'),
279
                'isopen' => new external_value(PARAM_BOOL, 'Whether the feedback has active access time restrictions or not.'),
280
                'isalreadysubmitted' => new external_value(PARAM_BOOL, 'Whether the feedback is already submitted or not.'),
281
                'isanonymous' => new external_value(PARAM_BOOL, 'Whether the feedback is anonymous or not.'),
282
                'warnings' => new external_warnings(),
283
            )
284
        );
285
    }
286
 
287
    /**
288
     * Describes the parameters for view_feedback.
289
     *
290
     * @return external_function_parameters
291
     * @since Moodle 3.3
292
     */
293
    public static function view_feedback_parameters() {
294
        return new external_function_parameters (
295
            array(
296
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
297
                'moduleviewed' => new external_value(PARAM_BOOL, 'If we need to mark the module as viewed for completion',
298
                    VALUE_DEFAULT, false),
299
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
300
                    VALUE_DEFAULT, 0),
301
            )
302
        );
303
    }
304
 
305
    /**
306
     * Trigger the course module viewed event and update the module completion status.
307
     *
308
     * @param int $feedbackid feedback instance id
309
     * @param bool $moduleviewed If we need to mark the module as viewed for completion
310
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
311
     * @return array of warnings and status result
312
     * @since Moodle 3.3
313
     * @throws moodle_exception
314
     */
315
    public static function view_feedback($feedbackid, $moduleviewed = false, $courseid = 0) {
316
 
317
        $params = array('feedbackid' => $feedbackid, 'moduleviewed' => $moduleviewed, 'courseid' => $courseid);
318
        $params = self::validate_parameters(self::view_feedback_parameters(), $params);
319
        $warnings = array();
320
 
321
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
322
            $params['courseid']);
323
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
324
 
325
        // Trigger module viewed event.
326
        $feedbackcompletion->trigger_module_viewed();
327
        if ($params['moduleviewed']) {
328
            if (!$feedbackcompletion->is_open()) {
329
                throw new moodle_exception('feedback_is_not_open', 'feedback');
330
            }
331
            // Mark activity viewed for completion-tracking.
332
            $feedbackcompletion->set_module_viewed();
333
        }
334
 
335
        $result = array(
336
            'status' => true,
337
            'warnings' => $warnings,
338
        );
339
        return $result;
340
    }
341
 
342
    /**
343
     * Describes the view_feedback return value.
344
     *
345
     * @return external_single_structure
346
     * @since Moodle 3.3
347
     */
348
    public static function view_feedback_returns() {
349
        return new external_single_structure(
350
            array(
351
                'status' => new external_value(PARAM_BOOL, 'status: true if success'),
352
                'warnings' => new external_warnings(),
353
            )
354
        );
355
    }
356
 
357
    /**
358
     * Describes the parameters for get_current_completed_tmp.
359
     *
360
     * @return external_function_parameters
361
     * @since Moodle 3.3
362
     */
363
    public static function get_current_completed_tmp_parameters() {
364
        return new external_function_parameters (
365
            array(
366
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
367
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
368
                    VALUE_DEFAULT, 0),
369
            )
370
        );
371
    }
372
 
373
    /**
374
     * Returns the temporary completion record for the current user.
375
     *
376
     * @param int $feedbackid feedback instance id
377
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
378
     * @return array of warnings and status result
379
     * @since Moodle 3.3
380
     * @throws moodle_exception
381
     */
382
    public static function get_current_completed_tmp($feedbackid, $courseid = 0) {
383
        global $PAGE;
384
 
385
        $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid);
386
        $params = self::validate_parameters(self::get_current_completed_tmp_parameters(), $params);
387
        $warnings = array();
388
 
389
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
390
            $params['courseid']);
391
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
392
 
393
        if ($completed = $feedbackcompletion->get_current_completed_tmp()) {
394
            $exporter = new feedback_completedtmp_exporter($completed);
395
            return array(
396
                'feedback' => $exporter->export($PAGE->get_renderer('core')),
397
                'warnings' => $warnings,
398
            );
399
        }
400
        throw new moodle_exception('not_started', 'feedback');
401
    }
402
 
403
    /**
404
     * Describes the get_current_completed_tmp return value.
405
     *
406
     * @return external_single_structure
407
     * @since Moodle 3.3
408
     */
409
    public static function get_current_completed_tmp_returns() {
410
        return new external_single_structure(
411
            array(
412
                'feedback' => feedback_completedtmp_exporter::get_read_structure(),
413
                'warnings' => new external_warnings(),
414
            )
415
        );
416
    }
417
 
418
    /**
419
     * Describes the parameters for get_items.
420
     *
421
     * @return external_function_parameters
422
     * @since Moodle 3.3
423
     */
424
    public static function get_items_parameters() {
425
        return new external_function_parameters (
426
            array(
427
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
428
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
429
                    VALUE_DEFAULT, 0),
430
            )
431
        );
432
    }
433
 
434
    /**
435
     * Returns the items (questions) in the given feedback.
436
     *
437
     * @param int $feedbackid feedback instance id
438
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
439
     * @return array of warnings and feedbacks
440
     * @since Moodle 3.3
441
     */
442
    public static function get_items($feedbackid, $courseid = 0) {
443
        global $PAGE;
444
 
445
        $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid);
446
        $params = self::validate_parameters(self::get_items_parameters(), $params);
447
        $warnings = array();
448
        $returneditems = array();
449
 
450
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
451
            $params['courseid']);
452
 
453
        $userhasaccess = true;
454
        try {
455
            // Check the user has access to the feedback.
456
            self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true);
457
        } catch (moodle_exception $e) {
458
            $userhasaccess = false;
459
            $warnings[] = [
460
                'item' => $feedback->id,
461
                'warningcode' => clean_param($e->errorcode, PARAM_ALPHANUM),
462
                'message' => $e->getMessage(),
463
            ];
464
        }
465
 
466
        // For consistency with the web behaviour, the items should be returned only when the user can edit or view reports (to
467
        // include non-editing teachers too).
468
        $capabilities = [
469
            'mod/feedback:edititems',
470
            'mod/feedback:viewreports',
471
        ];
472
        if ($userhasaccess || has_any_capability($capabilities, $context)) {
473
            // Remove previous warnings because, although the user might not have access, they have the proper capability.
474
            $warnings = [];
475
            $feedbackstructure = new mod_feedback_structure($feedback, $cm, $completioncourse->id);
476
            if ($items = $feedbackstructure->get_items()) {
477
                foreach ($items as $item) {
478
                    $itemnumber = empty($item->itemnr) ? null : $item->itemnr;
479
                    unset($item->itemnr);   // Added by the function, not part of the record.
480
                    $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber));
481
                    $returneditems[] = $exporter->export($PAGE->get_renderer('core'));
482
                }
483
            }
484
        } else if ($userhasaccess) {
485
            $warnings[] = [
486
                'item' => $feedback->id,
487
                'warningcode' => 'nopermission',
488
                'message' => 'nopermission',
489
            ];
490
        }
491
 
492
        $result = array(
493
            'items' => $returneditems,
494
            'warnings' => $warnings
495
        );
496
        return $result;
497
    }
498
 
499
    /**
500
     * Describes the get_items return value.
501
     *
502
     * @return external_single_structure
503
     * @since Moodle 3.3
504
     */
505
    public static function get_items_returns() {
506
        return new external_single_structure(
507
            array(
508
                'items' => new external_multiple_structure(
509
                    feedback_item_exporter::get_read_structure()
510
                ),
511
                'warnings' => new external_warnings(),
512
            )
513
        );
514
    }
515
 
516
    /**
517
     * Describes the parameters for launch_feedback.
518
     *
519
     * @return external_function_parameters
520
     * @since Moodle 3.3
521
     */
522
    public static function launch_feedback_parameters() {
523
        return new external_function_parameters (
524
            array(
525
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
526
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
527
                    VALUE_DEFAULT, 0),
528
            )
529
        );
530
    }
531
 
532
    /**
533
     * Starts or continues a feedback submission
534
     *
535
     * @param array $feedbackid feedback instance id
536
     * @param int $courseid course where user completes a feedback (for site feedbacks only).
537
     * @return array of warnings and launch information
538
     * @since Moodle 3.3
539
     */
540
    public static function launch_feedback($feedbackid, $courseid = 0) {
541
        global $PAGE;
542
 
543
        $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid);
544
        $params = self::validate_parameters(self::launch_feedback_parameters(), $params);
545
        $warnings = array();
546
 
547
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
548
            $params['courseid']);
549
        // Check we can do a new submission (or continue an existing).
550
        $feedbackcompletion = self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true);
551
 
552
        $gopage = $feedbackcompletion->get_resume_page();
553
        if ($gopage === null) {
554
            $gopage = -1; // Last page.
555
        }
556
 
557
        $result = array(
558
            'gopage' => $gopage,
559
            'warnings' => $warnings
560
        );
561
        return $result;
562
    }
563
 
564
    /**
565
     * Describes the launch_feedback return value.
566
     *
567
     * @return external_single_structure
568
     * @since Moodle 3.3
569
     */
570
    public static function launch_feedback_returns() {
571
        return new external_single_structure(
572
            array(
573
                'gopage' => new external_value(PARAM_INT, 'The next page to go (-1 if we were already in the last page). 0 for first page.'),
574
                'warnings' => new external_warnings(),
575
            )
576
        );
577
    }
578
 
579
    /**
580
     * Describes the parameters for get_page_items.
581
     *
582
     * @return external_function_parameters
583
     * @since Moodle 3.3
584
     */
585
    public static function get_page_items_parameters() {
586
        return new external_function_parameters (
587
            array(
588
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
589
                'page' => new external_value(PARAM_INT, 'The page to get starting by 0'),
590
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
591
                    VALUE_DEFAULT, 0),
592
            )
593
        );
594
    }
595
 
596
    /**
597
     * Get a single feedback page items.
598
     *
599
     * @param int $feedbackid feedback instance id
600
     * @param int $page the page to get starting by 0
601
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
602
     * @return array of warnings and launch information
603
     * @since Moodle 3.3
604
     */
605
    public static function get_page_items($feedbackid, $page, $courseid = 0) {
606
        global $PAGE;
607
 
608
        $params = array('feedbackid' => $feedbackid, 'page' => $page, 'courseid' => $courseid);
609
        $params = self::validate_parameters(self::get_page_items_parameters(), $params);
610
        $warnings = array();
611
        $returneditems = array();
612
        $hasprevpage = false;
613
        $hasnextpage = false;
614
 
615
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
616
            $params['courseid']);
617
 
618
        $userhasaccess = true;
619
        $feedbackcompletion = null;
620
        try {
621
            // Check the user has access to the feedback.
622
            $feedbackcompletion = self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true);
623
        } catch (moodle_exception $e) {
624
            $userhasaccess = false;
625
            $warnings[] = [
626
                'item' => $feedback->id,
627
                'warningcode' => str_replace('_', '', $e->errorcode),
628
                'message' => $e->getMessage(),
629
            ];
630
        }
631
 
632
        // For consistency with the web behaviour, the items should be returned only when the user can edit or view reports (to
633
        // include non-editing teachers too).
634
        $capabilities = [
635
            'mod/feedback:edititems',
636
            'mod/feedback:viewreports',
637
        ];
638
        if ($userhasaccess || has_any_capability($capabilities, $context)) {
639
            // Remove previous warnings because, although the user might not have access, they have the proper capability.
640
            $warnings = [];
641
 
642
            if ($feedbackcompletion == null) {
643
                $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
644
            }
645
 
646
            $page = $params['page'];
647
            $pages = $feedbackcompletion->get_pages();
648
            $pageitems = $pages[$page];
649
            $hasnextpage = $page < count($pages) - 1; // Until we complete this page we can not trust get_next_page().
650
            $hasprevpage = $page && ($feedbackcompletion->get_previous_page($page, false) !== null);
651
 
652
            foreach ($pageitems as $item) {
653
                $itemnumber = empty($item->itemnr) ? null : $item->itemnr;
654
                unset($item->itemnr);   // Added by the function, not part of the record.
655
                $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber));
656
                $returneditems[] = $exporter->export($PAGE->get_renderer('core'));
657
            }
658
        } else if ($userhasaccess) {
659
            $warnings[] = [
660
                'item' => $feedback->id,
661
                'warningcode' => 'nopermission',
662
                'message' => get_string('nopermission', 'mod_feedback'),
663
            ];
664
        }
665
 
666
        $result = array(
667
            'items' => $returneditems,
668
            'hasprevpage' => $hasprevpage,
669
            'hasnextpage' => $hasnextpage,
670
            'warnings' => $warnings
671
        );
672
        return $result;
673
    }
674
 
675
    /**
676
     * Describes the get_page_items return value.
677
     *
678
     * @return external_single_structure
679
     * @since Moodle 3.3
680
     */
681
    public static function get_page_items_returns() {
682
        return new external_single_structure(
683
            array(
684
                'items' => new external_multiple_structure(
685
                    feedback_item_exporter::get_read_structure()
686
                ),
687
                'hasprevpage' => new external_value(PARAM_BOOL, 'Whether is a previous page.'),
688
                'hasnextpage' => new external_value(PARAM_BOOL, 'Whether there are more pages.'),
689
                'warnings' => new external_warnings(),
690
            )
691
        );
692
    }
693
 
694
    /**
695
     * Describes the parameters for process_page.
696
     *
697
     * @return external_function_parameters
698
     * @since Moodle 3.3
699
     */
700
    public static function process_page_parameters() {
701
        return new external_function_parameters (
702
            array(
703
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
704
                'page' => new external_value(PARAM_INT, 'The page being processed.'),
705
                'responses' => new external_multiple_structure(
706
                    new external_single_structure(
707
                        array(
708
                            'name' => new external_value(PARAM_NOTAGS, 'The response name (usually type[index]_id).'),
709
                            'value' => new external_value(PARAM_RAW, 'The response value.'),
710
                        )
711
                    ), 'The data to be processed.', VALUE_DEFAULT, array()
712
                ),
713
                'goprevious' => new external_value(PARAM_BOOL, 'Whether we want to jump to previous page.', VALUE_DEFAULT, false),
714
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
715
                    VALUE_DEFAULT, 0),
716
            )
717
        );
718
    }
719
 
720
    /**
721
     * Process a jump between pages.
722
     *
723
     * @param array $feedbackid feedback instance id
724
     * @param array $page the page being processed
725
     * @param array $responses the responses to be processed
726
     * @param bool $goprevious whether we want to jump to previous page
727
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
728
     * @return array of warnings and launch information
729
     * @since Moodle 3.3
730
     */
731
    public static function process_page($feedbackid, $page, $responses = [], $goprevious = false, $courseid = 0) {
732
        global $USER, $SESSION;
733
 
734
        $params = array('feedbackid' => $feedbackid, 'page' => $page, 'responses' => $responses, 'goprevious' => $goprevious,
735
            'courseid' => $courseid);
736
        $params = self::validate_parameters(self::process_page_parameters(), $params);
737
        $warnings = array();
738
        $siteaftersubmit = $completionpagecontents = '';
739
 
740
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
741
            $params['courseid']);
742
        // Check we can do a new submission (or continue an existing).
743
        $feedbackcompletion = self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true);
744
 
745
        // Create the $_POST object required by the feedback question engine.
746
        $_POST = array();
747
        foreach ($responses as $response) {
748
            // First check if we are handling array parameters.
749
            if (preg_match('/(.+)\[(.+)\]$/', $response['name'], $matches)) {
750
                $_POST[$matches[1]][$matches[2]] = $response['value'];
751
            } else {
752
                $_POST[$response['name']] = $response['value'];
753
            }
754
        }
755
        // Force fields.
756
        $_POST['id'] = $cm->id;
757
        $_POST['courseid'] = $courseid;
758
        $_POST['gopage'] = $params['page'];
759
        $_POST['_qf__mod_feedback_complete_form'] = 1;
760
 
761
        // Determine where to go, backwards or forward.
762
        if (!$params['goprevious']) {
763
            $_POST['gonextpage'] = 1;   // Even if we are saving values we need this set.
764
            if ($feedbackcompletion->get_next_page($params['page'], false) === null) {
765
                $_POST['savevalues'] = 1;   // If there is no next page, it means we are finishing the feedback.
766
            }
767
        }
768
 
769
        // Ignore sesskey (deep in some APIs), the request is already validated.
770
        $USER->ignoresesskey = true;
771
        feedback_init_feedback_session();
772
        $SESSION->feedback->is_started = true;
773
 
774
        $feedbackcompletion->process_page($params['page'], $params['goprevious']);
775
        $completed = $feedbackcompletion->just_completed();
776
        if ($completed) {
777
            $jumpto = 0;
778
            if ($feedback->page_after_submit) {
779
                $completionpagecontents = $feedbackcompletion->page_after_submit();
780
            }
781
 
782
            if ($feedback->site_after_submit) {
783
                $siteaftersubmit = feedback_encode_target_url($feedback->site_after_submit);
784
            }
785
        } else {
786
            $jumpto = $feedbackcompletion->get_jumpto();
787
        }
788
 
789
        $result = array(
790
            'jumpto' => $jumpto,
791
            'completed' => $completed,
792
            'completionpagecontents' => $completionpagecontents,
793
            'siteaftersubmit' => $siteaftersubmit,
794
            'warnings' => $warnings
795
        );
796
        return $result;
797
    }
798
 
799
    /**
800
     * Describes the process_page return value.
801
     *
802
     * @return external_single_structure
803
     * @since Moodle 3.3
804
     */
805
    public static function process_page_returns() {
806
        return new external_single_structure(
807
            array(
808
                'jumpto' => new external_value(PARAM_INT, 'The page to jump to.'),
809
                'completed' => new external_value(PARAM_BOOL, 'If the user completed the feedback.'),
810
                'completionpagecontents' => new external_value(PARAM_RAW, 'The completion page contents.'),
811
                'siteaftersubmit' => new external_value(PARAM_RAW, 'The link (could be relative) to show after submit.'),
812
                'warnings' => new external_warnings(),
813
            )
814
        );
815
    }
816
 
817
    /**
818
     * Describes the parameters for get_analysis.
819
     *
820
     * @return external_function_parameters
821
     * @since Moodle 3.3
822
     */
823
    public static function get_analysis_parameters() {
824
        return new external_function_parameters (
825
            array(
826
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
827
                'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
828
                                                VALUE_DEFAULT, 0),
829
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
830
                    VALUE_DEFAULT, 0),
831
            )
832
        );
833
    }
834
 
835
    /**
836
     * Retrieves the feedback analysis.
837
     *
838
     * @param array $feedbackid feedback instance id
839
     * @param int $groupid group id, 0 means that the function will determine the user group
840
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
841
     * @return array of warnings and launch information
842
     * @since Moodle 3.3
843
     */
844
    public static function get_analysis($feedbackid, $groupid = 0, $courseid = 0) {
845
        global $PAGE;
846
 
847
        $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'courseid' => $courseid);
848
        $params = self::validate_parameters(self::get_analysis_parameters(), $params);
849
        $warnings = $itemsdata = array();
850
 
851
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
852
            $params['courseid']);
853
 
854
        // Check permissions.
855
        $feedbackstructure = new mod_feedback_structure($feedback, $cm, $completioncourse->id);
856
        if (!$feedbackstructure->can_view_analysis()) {
857
            throw new required_capability_exception($context, 'mod/feedback:viewanalysepage', 'nopermission', '');
858
        }
859
 
860
        if (!empty($params['groupid'])) {
861
            $groupid = $params['groupid'];
862
            // Determine is the group is visible to user.
863
            if (!groups_group_visible($groupid, $course, $cm)) {
864
                throw new moodle_exception('notingroup');
865
            }
866
        } else {
867
            // Check to see if groups are being used here.
868
            if ($groupmode = groups_get_activity_groupmode($cm)) {
869
                $groupid = groups_get_activity_group($cm);
870
                // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
871
                if (!groups_group_visible($groupid, $course, $cm)) {
872
                    throw new moodle_exception('notingroup');
873
                }
874
            } else {
875
                $groupid = 0;
876
            }
877
        }
878
 
879
        // Summary data.
880
        $summary = new mod_feedback\output\summary($feedbackstructure, $groupid);
881
        $summarydata = $summary->export_for_template($PAGE->get_renderer('core'));
882
 
883
        $checkanonymously = true;
884
        if ($groupid > 0 AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES) {
885
            $completedcount = $feedbackstructure->count_completed_responses($groupid);
886
            if ($completedcount < FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP) {
887
                $checkanonymously = false;
888
            }
889
        }
890
 
891
        if ($checkanonymously) {
892
            // Get the items of the feedback.
893
            $items = $feedbackstructure->get_items(true);
894
            foreach ($items as $item) {
895
                $itemobj = feedback_get_item_class($item->typ);
896
                $itemnumber = empty($item->itemnr) ? null : $item->itemnr;
897
                unset($item->itemnr);   // Added by the function, not part of the record.
898
                $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber));
899
 
900
                $itemsdata[] = array(
901
                    'item' => $exporter->export($PAGE->get_renderer('core')),
902
                    'data' => $itemobj->get_analysed_for_external($item, $groupid),
903
                );
904
            }
905
        } else {
906
            $warnings[] = array(
907
                'item' => 'feedback',
908
                'itemid' => $feedback->id,
909
                'warningcode' => 'insufficientresponsesforthisgroup',
910
                'message' => s(get_string('insufficient_responses_for_this_group', 'feedback'))
911
            );
912
        }
913
 
914
        $result = array(
915
            'completedcount' => $summarydata->completedcount,
916
            'itemscount' => $summarydata->itemscount,
917
            'itemsdata' => $itemsdata,
918
            'warnings' => $warnings
919
        );
920
        return $result;
921
    }
922
 
923
    /**
924
     * Describes the get_analysis return value.
925
     *
926
     * @return external_single_structure
927
     * @since Moodle 3.3
928
     */
929
    public static function get_analysis_returns() {
930
        return new external_single_structure(
931
            array(
932
            'completedcount' => new external_value(PARAM_INT, 'Number of completed submissions.'),
933
            'itemscount' => new external_value(PARAM_INT, 'Number of items (questions).'),
934
            'itemsdata' => new external_multiple_structure(
935
                new external_single_structure(
936
                    array(
937
                        'item' => feedback_item_exporter::get_read_structure(),
938
                        'data' => new external_multiple_structure(
939
                            new external_value(PARAM_RAW, 'The analysis data (can be json encoded)')
940
                        ),
941
                    )
942
                )
943
            ),
944
            'warnings' => new external_warnings(),
945
            )
946
        );
947
    }
948
 
949
    /**
950
     * Describes the parameters for get_unfinished_responses.
951
     *
952
     * @return external_function_parameters
953
     * @since Moodle 3.3
954
     */
955
    public static function get_unfinished_responses_parameters() {
956
        return new external_function_parameters (
957
            array(
958
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
959
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
960
                    VALUE_DEFAULT, 0),
961
            )
962
        );
963
    }
964
 
965
    /**
966
     * Retrieves responses from the current unfinished attempt.
967
     *
968
     * @param array $feedbackid feedback instance id
969
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
970
     * @return array of warnings and launch information
971
     * @since Moodle 3.3
972
     */
973
    public static function get_unfinished_responses($feedbackid, $courseid = 0) {
974
        global $PAGE;
975
 
976
        $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid);
977
        $params = self::validate_parameters(self::get_unfinished_responses_parameters(), $params);
978
        $warnings = $itemsdata = array();
979
 
980
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
981
            $params['courseid']);
982
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
983
 
984
        $responses = array();
985
        $unfinished = $feedbackcompletion->get_unfinished_responses();
986
        foreach ($unfinished as $u) {
987
            $exporter = new feedback_valuetmp_exporter($u);
988
            $responses[] = $exporter->export($PAGE->get_renderer('core'));
989
        }
990
 
991
        $result = array(
992
            'responses' => $responses,
993
            'warnings' => $warnings
994
        );
995
        return $result;
996
    }
997
 
998
    /**
999
     * Describes the get_unfinished_responses return value.
1000
     *
1001
     * @return external_single_structure
1002
     * @since Moodle 3.3
1003
     */
1004
    public static function get_unfinished_responses_returns() {
1005
        return new external_single_structure(
1006
            array(
1007
            'responses' => new external_multiple_structure(
1008
                feedback_valuetmp_exporter::get_read_structure()
1009
            ),
1010
            'warnings' => new external_warnings(),
1011
            )
1012
        );
1013
    }
1014
 
1015
    /**
1016
     * Describes the parameters for get_finished_responses.
1017
     *
1018
     * @return external_function_parameters
1019
     * @since Moodle 3.3
1020
     */
1021
    public static function get_finished_responses_parameters() {
1022
        return new external_function_parameters (
1023
            array(
1024
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'),
1025
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
1026
                    VALUE_DEFAULT, 0),
1027
            )
1028
        );
1029
    }
1030
 
1031
    /**
1032
     * Retrieves responses from the last finished attempt.
1033
     *
1034
     * @param array $feedbackid feedback instance id
1035
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
1036
     * @return array of warnings and the responses
1037
     * @since Moodle 3.3
1038
     */
1039
    public static function get_finished_responses($feedbackid, $courseid = 0) {
1040
        global $PAGE;
1041
 
1042
        $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid);
1043
        $params = self::validate_parameters(self::get_finished_responses_parameters(), $params);
1044
        $warnings = $itemsdata = array();
1045
 
1046
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
1047
            $params['courseid']);
1048
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
1049
 
1050
        $responses = array();
1051
        // Load and get the responses from the last completed feedback.
1052
        $feedbackcompletion->find_last_completed();
1053
        $unfinished = $feedbackcompletion->get_finished_responses();
1054
        foreach ($unfinished as $u) {
1055
            $exporter = new feedback_value_exporter($u);
1056
            $responses[] = $exporter->export($PAGE->get_renderer('core'));
1057
        }
1058
 
1059
        $result = array(
1060
            'responses' => $responses,
1061
            'warnings' => $warnings
1062
        );
1063
        return $result;
1064
    }
1065
 
1066
    /**
1067
     * Describes the get_finished_responses return value.
1068
     *
1069
     * @return external_single_structure
1070
     * @since Moodle 3.3
1071
     */
1072
    public static function get_finished_responses_returns() {
1073
        return new external_single_structure(
1074
            array(
1075
            'responses' => new external_multiple_structure(
1076
                feedback_value_exporter::get_read_structure()
1077
            ),
1078
            'warnings' => new external_warnings(),
1079
            )
1080
        );
1081
    }
1082
 
1083
    /**
1084
     * Describes the parameters for get_non_respondents.
1085
     *
1086
     * @return external_function_parameters
1087
     * @since Moodle 3.3
1088
     */
1089
    public static function get_non_respondents_parameters() {
1090
        return new external_function_parameters (
1091
            array(
1092
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
1093
                'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.',
1094
                                                VALUE_DEFAULT, 0),
1095
                'sort' => new external_value(PARAM_ALPHA, 'Sort param, must be firstname, lastname or lastaccess (default).',
1096
                                                VALUE_DEFAULT, 'lastaccess'),
1097
                'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
1098
                'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0),
1099
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
1100
                    VALUE_DEFAULT, 0),
1101
            )
1102
        );
1103
    }
1104
 
1105
    /**
1106
     * Retrieves a list of students who didn't submit the feedback.
1107
     *
1108
     * @param int $feedbackid feedback instance id
1109
     * @param int $groupid Group id, 0 means that the function will determine the user group'
1110
     * @param str $sort sort param, must be firstname, lastname or lastaccess (default)
1111
     * @param int $page the page of records to return
1112
     * @param int $perpage the number of records to return per page
1113
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
1114
     * @return array of warnings and users ids
1115
     * @since Moodle 3.3
1116
     */
1117
    public static function get_non_respondents($feedbackid, $groupid = 0, $sort = 'lastaccess', $page = 0, $perpage = 0,
1118
            $courseid = 0) {
1119
 
1120
        global $CFG;
1121
        require_once($CFG->dirroot . '/mod/feedback/lib.php');
1122
 
1123
        $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'sort' => $sort, 'page' => $page,
1124
            'perpage' => $perpage, 'courseid' => $courseid);
1125
        $params = self::validate_parameters(self::get_non_respondents_parameters(), $params);
1126
        $warnings = $nonrespondents = array();
1127
 
1128
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
1129
            $params['courseid']);
1130
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
1131
        $completioncourseid = $feedbackcompletion->get_courseid();
1132
 
1133
        if ($feedback->anonymous != FEEDBACK_ANONYMOUS_NO || $feedback->course == SITEID) {
1134
            throw new moodle_exception('anonymous', 'feedback');
1135
        }
1136
 
1137
        // Check permissions.
1138
        require_capability('mod/feedback:viewreports', $context);
1139
 
1140
        if (!empty($params['groupid'])) {
1141
            $groupid = $params['groupid'];
1142
            // Determine is the group is visible to user.
1143
            if (!groups_group_visible($groupid, $course, $cm)) {
1144
                throw new moodle_exception('notingroup');
1145
            }
1146
        } else {
1147
            // Check to see if groups are being used here.
1148
            if ($groupmode = groups_get_activity_groupmode($cm)) {
1149
                $groupid = groups_get_activity_group($cm);
1150
                // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1151
                if (!groups_group_visible($groupid, $course, $cm)) {
1152
                    throw new moodle_exception('notingroup');
1153
                }
1154
            } else {
1155
                $groupid = 0;
1156
            }
1157
        }
1158
 
1159
        if ($params['sort'] !== 'firstname' && $params['sort'] !== 'lastname' && $params['sort'] !== 'lastaccess') {
1160
            throw new invalid_parameter_exception('Invalid sort param, must be firstname, lastname or lastaccess.');
1161
        }
1162
 
1163
        // Check if we are page filtering.
1164
        if ($params['perpage'] == 0) {
1165
            $page = $params['page'];
1166
            $perpage = FEEDBACK_DEFAULT_PAGE_COUNT;
1167
        } else {
1168
            $perpage = $params['perpage'];
1169
            $page = $perpage * $params['page'];
1170
        }
1171
        $users = feedback_get_incomplete_users($cm, $groupid, $params['sort'], $page, $perpage, true);
1172
        foreach ($users as $user) {
1173
            $nonrespondents[] = [
1174
                'courseid' => $completioncourseid,
1175
                'userid'   => $user->id,
1176
                'fullname' => fullname($user),
1177
                'started'  => $user->feedbackstarted
1178
            ];
1179
        }
1180
 
1181
        $result = array(
1182
            'users' => $nonrespondents,
1183
            'total' => feedback_count_incomplete_users($cm, $groupid),
1184
            'warnings' => $warnings
1185
        );
1186
        return $result;
1187
    }
1188
 
1189
    /**
1190
     * Describes the get_non_respondents return value.
1191
     *
1192
     * @return external_single_structure
1193
     * @since Moodle 3.3
1194
     */
1195
    public static function get_non_respondents_returns() {
1196
        return new external_single_structure(
1197
            array(
1198
                'users' => new external_multiple_structure(
1199
                    new external_single_structure(
1200
                        array(
1201
                            'courseid' => new external_value(PARAM_INT, 'Course id'),
1202
                            'userid' => new external_value(PARAM_INT, 'The user id'),
1203
                            'fullname' => new external_value(PARAM_TEXT, 'User full name'),
1204
                            'started' => new external_value(PARAM_BOOL, 'If the user has started the attempt'),
1205
                        )
1206
                    )
1207
                ),
1208
                'total' => new external_value(PARAM_INT, 'Total number of non respondents'),
1209
                'warnings' => new external_warnings(),
1210
            )
1211
        );
1212
    }
1213
 
1214
    /**
1215
     * Describes the parameters for get_responses_analysis.
1216
     *
1217
     * @return external_function_parameters
1218
     * @since Moodle 3.3
1219
     */
1220
    public static function get_responses_analysis_parameters() {
1221
        return new external_function_parameters (
1222
            array(
1223
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
1224
                'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
1225
                                                VALUE_DEFAULT, 0),
1226
                'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
1227
                'perpage' => new external_value(PARAM_INT, 'The number of records to return per page', VALUE_DEFAULT, 0),
1228
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
1229
                    VALUE_DEFAULT, 0),
1230
            )
1231
        );
1232
    }
1233
 
1234
    /**
1235
     * Return the feedback user responses.
1236
     *
1237
     * @param int $feedbackid feedback instance id
1238
     * @param int $groupid Group id, 0 means that the function will determine the user group
1239
     * @param int $page the page of records to return
1240
     * @param int $perpage the number of records to return per page
1241
     * @param int $courseid course where user completes the feedback (for site feedbacks only)
1242
     * @return array of warnings and users attemps and responses
1243
     * @throws moodle_exception
1244
     * @since Moodle 3.3
1245
     */
1246
    public static function get_responses_analysis($feedbackid, $groupid = 0, $page = 0, $perpage = 0, $courseid = 0) {
1247
 
1248
        $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'page' => $page, 'perpage' => $perpage,
1249
            'courseid' => $courseid);
1250
        $params = self::validate_parameters(self::get_responses_analysis_parameters(), $params);
1251
        $warnings = $itemsdata = array();
1252
 
1253
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
1254
            $params['courseid']);
1255
 
1256
        // Check permissions.
1257
        require_capability('mod/feedback:viewreports', $context);
1258
 
1259
        if (!empty($params['groupid'])) {
1260
            $groupid = $params['groupid'];
1261
            // Determine is the group is visible to user.
1262
            if (!groups_group_visible($groupid, $course, $cm)) {
1263
                throw new moodle_exception('notingroup');
1264
            }
1265
        } else {
1266
            // Check to see if groups are being used here.
1267
            if ($groupmode = groups_get_activity_groupmode($cm)) {
1268
                $groupid = groups_get_activity_group($cm);
1269
                // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1270
                if (!groups_group_visible($groupid, $course, $cm)) {
1271
                    throw new moodle_exception('notingroup');
1272
                }
1273
            } else {
1274
                $groupid = 0;
1275
            }
1276
        }
1277
 
1278
        $feedbackstructure = new mod_feedback_structure($feedback, $cm, $completioncourse->id);
1279
        $responsestable = new mod_feedback_responses_table($feedbackstructure, $groupid);
1280
        // Ensure responses number is correct prior returning them.
1281
        $feedbackstructure->shuffle_anonym_responses();
1282
        $anonresponsestable = new mod_feedback_responses_anon_table($feedbackstructure, $groupid);
1283
 
1284
        $result = array(
1285
            'attempts'          => $responsestable->export_external_structure($params['page'], $params['perpage']),
1286
            'totalattempts'     => $responsestable->get_total_responses_count(),
1287
            'anonattempts'      => $anonresponsestable->export_external_structure($params['page'], $params['perpage']),
1288
            'totalanonattempts' => $anonresponsestable->get_total_responses_count(),
1289
            'warnings'       => $warnings
1290
        );
1291
        return $result;
1292
    }
1293
 
1294
    /**
1295
     * Describes the get_responses_analysis return value.
1296
     *
1297
     * @return external_single_structure
1298
     * @since Moodle 3.3
1299
     */
1300
    public static function get_responses_analysis_returns() {
1301
        $responsestructure = new external_multiple_structure(
1302
            new external_single_structure(
1303
                array(
1304
                    'id' => new external_value(PARAM_INT, 'Response id'),
1305
                    'name' => new external_value(PARAM_RAW, 'Response name'),
1306
                    'printval' => new external_value(PARAM_RAW, 'Response ready for output'),
1307
                    'rawval' => new external_value(PARAM_RAW, 'Response raw value'),
1308
                )
1309
            )
1310
        );
1311
 
1312
        return new external_single_structure(
1313
            array(
1314
                'attempts' => new external_multiple_structure(
1315
                    new external_single_structure(
1316
                        array(
1317
                            'id' => new external_value(PARAM_INT, 'Completed id'),
1318
                            'courseid' => new external_value(PARAM_INT, 'Course id'),
1319
                            'userid' => new external_value(PARAM_INT, 'User who responded'),
1320
                            'timemodified' => new external_value(PARAM_INT, 'Time modified for the response'),
1321
                            'fullname' => new external_value(PARAM_TEXT, 'User full name'),
1322
                            'responses' => $responsestructure
1323
                        )
1324
                    )
1325
                ),
1326
                'totalattempts' => new external_value(PARAM_INT, 'Total responses count.'),
1327
                'anonattempts' => new external_multiple_structure(
1328
                    new external_single_structure(
1329
                        array(
1330
                            'id' => new external_value(PARAM_INT, 'Completed id'),
1331
                            'courseid' => new external_value(PARAM_INT, 'Course id'),
1332
                            'number' => new external_value(PARAM_INT, 'Response number'),
1333
                            'responses' => $responsestructure
1334
                        )
1335
                    )
1336
                ),
1337
                'totalanonattempts' => new external_value(PARAM_INT, 'Total anonymous responses count.'),
1338
                'warnings' => new external_warnings(),
1339
            )
1340
        );
1341
    }
1342
 
1343
    /**
1344
     * Describes the parameters for get_last_completed.
1345
     *
1346
     * @return external_function_parameters
1347
     * @since Moodle 3.3
1348
     */
1349
    public static function get_last_completed_parameters() {
1350
        return new external_function_parameters (
1351
            array(
1352
                'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'),
1353
                'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).',
1354
                    VALUE_DEFAULT, 0),
1355
            )
1356
        );
1357
    }
1358
 
1359
    /**
1360
     * Retrieves the last completion record for the current user.
1361
     *
1362
     * @param int $feedbackid feedback instance id
1363
     * @return array of warnings and the last completed record
1364
     * @since Moodle 3.3
1365
     * @throws moodle_exception
1366
     */
1367
    public static function get_last_completed($feedbackid, $courseid = 0) {
1368
        global $PAGE;
1369
 
1370
        $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid);
1371
        $params = self::validate_parameters(self::get_last_completed_parameters(), $params);
1372
        $warnings = array();
1373
 
1374
        list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'],
1375
            $params['courseid']);
1376
        $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id);
1377
 
1378
        if ($feedbackcompletion->is_anonymous()) {
1379
             throw new moodle_exception('anonymous', 'feedback');
1380
        }
1381
        if ($completed = $feedbackcompletion->find_last_completed()) {
1382
            $exporter = new feedback_completed_exporter($completed);
1383
            return array(
1384
                'completed' => $exporter->export($PAGE->get_renderer('core')),
1385
                'warnings' => $warnings,
1386
            );
1387
        }
1388
        throw new moodle_exception('not_completed_yet', 'feedback');
1389
    }
1390
 
1391
    /**
1392
     * Describes the get_last_completed return value.
1393
     *
1394
     * @return external_single_structure
1395
     * @since Moodle 3.3
1396
     */
1397
    public static function get_last_completed_returns() {
1398
        return new external_single_structure(
1399
            array(
1400
                'completed' => feedback_completed_exporter::get_read_structure(),
1401
                'warnings' => new external_warnings(),
1402
            )
1403
        );
1404
    }
1405
}