Merge branch 'MDL-79003-402' of https://github.com/andrewnicols/moodle into MOODLE_40...
[moodle.git] / completion / classes / external.php
blob2243510996a65f16d561f70e25d568e6689af3a7
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.
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/>.
17 /**
18 * Completion external API
20 * @package core_completion
21 * @category external
22 * @copyright 2015 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 * @since Moodle 2.9
27 use core_external\external_api;
28 use core_external\external_function_parameters;
29 use core_external\external_multiple_structure;
30 use core_external\external_single_structure;
31 use core_external\external_value;
32 use core_external\external_warnings;
34 defined('MOODLE_INTERNAL') || die;
36 require_once("$CFG->libdir/completionlib.php");
38 /**
39 * Completion external functions
41 * @package core_completion
42 * @category external
43 * @copyright 2015 Juan Leyva <juan@moodle.com>
44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 * @since Moodle 2.9
47 class core_completion_external extends external_api {
49 /**
50 * Describes the parameters for update_activity_completion_status_manually.
52 * @return external_function_parameters
53 * @since Moodle 2.9
55 public static function update_activity_completion_status_manually_parameters() {
56 return new external_function_parameters (
57 array(
58 'cmid' => new external_value(PARAM_INT, 'course module id'),
59 'completed' => new external_value(PARAM_BOOL, 'activity completed or not'),
64 /**
65 * Update completion status for the current user in an activity, only for activities with manual tracking.
66 * @param int $cmid Course module id
67 * @param bool $completed Activity completed or not
68 * @return array Result and possible warnings
69 * @since Moodle 2.9
70 * @throws moodle_exception
72 public static function update_activity_completion_status_manually($cmid, $completed) {
74 // Validate and normalize parameters.
75 $params = self::validate_parameters(self::update_activity_completion_status_manually_parameters(),
76 array('cmid' => $cmid, 'completed' => $completed));
77 $cmid = $params['cmid'];
78 $completed = $params['completed'];
80 $warnings = array();
82 $context = context_module::instance($cmid);
83 self::validate_context($context);
84 require_capability('moodle/course:togglecompletion', $context);
86 list($course, $cm) = get_course_and_cm_from_cmid($cmid);
88 // Set up completion object and check it is enabled.
89 $completion = new completion_info($course);
90 if (!$completion->is_enabled()) {
91 throw new moodle_exception('completionnotenabled', 'completion');
94 // Check completion state is manual.
95 if ($cm->completion != COMPLETION_TRACKING_MANUAL) {
96 throw new moodle_exception('cannotmanualctrack', 'error');
99 $targetstate = ($completed) ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
100 $completion->update_state($cm, $targetstate);
102 $result = array();
103 $result['status'] = true;
104 $result['warnings'] = $warnings;
105 return $result;
109 * Describes the update_activity_completion_status_manually return value.
111 * @return external_single_structure
112 * @since Moodle 2.9
114 public static function update_activity_completion_status_manually_returns() {
116 return new external_single_structure(
117 array(
118 'status' => new external_value(PARAM_BOOL, 'status, true if success'),
119 'warnings' => new external_warnings(),
125 * Describes the parameters for override_activity_completion_status.
127 * @return external_external_function_parameters
128 * @since Moodle 3.4
130 public static function override_activity_completion_status_parameters() {
131 return new external_function_parameters (
132 array(
133 'userid' => new external_value(PARAM_INT, 'user id'),
134 'cmid' => new external_value(PARAM_INT, 'course module id'),
135 'newstate' => new external_value(PARAM_INT, 'the new activity completion state'),
141 * Update completion status for a user in an activity.
142 * @param int $userid User id
143 * @param int $cmid Course module id
144 * @param int $newstate Activity completion
145 * @return array Array containing the current (updated) completion status.
146 * @since Moodle 3.4
147 * @throws moodle_exception
149 public static function override_activity_completion_status($userid, $cmid, $newstate) {
150 // Validate and normalize parameters.
151 $params = self::validate_parameters(self::override_activity_completion_status_parameters(),
152 array('userid' => $userid, 'cmid' => $cmid, 'newstate' => $newstate));
153 $userid = $params['userid'];
154 $cmid = $params['cmid'];
155 $newstate = $params['newstate'];
157 $context = context_module::instance($cmid);
158 self::validate_context($context);
160 list($course, $cm) = get_course_and_cm_from_cmid($cmid);
162 // Set up completion object and check it is enabled.
163 $completion = new completion_info($course);
164 if (!$completion->is_enabled()) {
165 throw new moodle_exception('completionnotenabled', 'completion');
168 // Update completion state and get the new state back.
169 $completion->update_state($cm, $newstate, $userid, true);
170 $completiondata = $completion->get_data($cm, false, $userid);
172 // Return the current state of completion.
173 return [
174 'cmid' => $completiondata->coursemoduleid,
175 'userid' => $completiondata->userid,
176 'state' => $completiondata->completionstate,
177 'timecompleted' => $completiondata->timemodified,
178 'overrideby' => $completiondata->overrideby,
179 'tracking' => $completion->is_enabled($cm)
184 * Describes the override_activity_completion_status return value.
186 * @return external_single_structure
187 * @since Moodle 3.4
189 public static function override_activity_completion_status_returns() {
191 return new external_single_structure(
192 array(
193 'cmid' => new external_value(PARAM_INT, 'The course module id'),
194 'userid' => new external_value(PARAM_INT, 'The user id to which the completion info belongs'),
195 'state' => new external_value(PARAM_INT, 'The current completion state.'),
196 'timecompleted' => new external_value(PARAM_INT, 'time of completion'),
197 'overrideby' => new external_value(PARAM_INT, 'The user id who has overriden the status, or null'),
198 'tracking' => new external_value(PARAM_INT, 'type of tracking:
199 0 means none, 1 manual, 2 automatic'),
205 * Returns description of method parameters
207 * @return external_function_parameters
208 * @since Moodle 2.9
210 public static function get_activities_completion_status_parameters() {
211 return new external_function_parameters(
212 array(
213 'courseid' => new external_value(PARAM_INT, 'Course ID'),
214 'userid' => new external_value(PARAM_INT, 'User ID'),
220 * Get Activities completion status
222 * @param int $courseid ID of the Course
223 * @param int $userid ID of the User
224 * @return array of activities progress and warnings
225 * @throws moodle_exception
226 * @since Moodle 2.9
227 * @throws moodle_exception
229 public static function get_activities_completion_status($courseid, $userid) {
230 global $CFG, $USER, $PAGE;
231 require_once($CFG->libdir . '/grouplib.php');
233 $warnings = array();
234 $arrayparams = array(
235 'courseid' => $courseid,
236 'userid' => $userid,
239 $params = self::validate_parameters(self::get_activities_completion_status_parameters(), $arrayparams);
241 $course = get_course($params['courseid']);
242 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
243 core_user::require_active_user($user);
245 $context = context_course::instance($course->id);
246 self::validate_context($context);
248 // Check that current user have permissions to see this user's activities.
249 if ($user->id != $USER->id) {
250 require_capability('report/progress:view', $context);
251 if (!groups_user_groups_visible($course, $user->id)) {
252 // We are not in the same group!
253 throw new moodle_exception('accessdenied', 'admin');
257 $completion = new completion_info($course);
258 $activities = $completion->get_activities();
260 $results = array();
261 foreach ($activities as $activity) {
262 // Check if current user has visibility on this activity.
263 if (!$activity->uservisible) {
264 continue;
266 // Get progress information and state (we must use get_data because it works for all user roles in course).
267 $exporter = new \core_completion\external\completion_info_exporter(
268 $course,
269 $activity,
270 $userid,
272 $renderer = $PAGE->get_renderer('core');
273 $data = (array)$exporter->export($renderer);
274 $results[] = array_merge([
275 'cmid' => $activity->id,
276 'modname' => $activity->modname,
277 'instance' => $activity->instance,
278 'tracking' => $activity->completion,
279 ], $data);
282 $results = array(
283 'statuses' => $results,
284 'warnings' => $warnings
286 return $results;
290 * Returns description of method result value
292 * @return \core_external\external_description
293 * @since Moodle 2.9
295 public static function get_activities_completion_status_returns() {
296 return new external_single_structure(
297 array(
298 'statuses' => new external_multiple_structure(
299 new external_single_structure(
301 'cmid' => new external_value(PARAM_INT, 'course module ID'),
302 'modname' => new external_value(PARAM_PLUGIN, 'activity module name'),
303 'instance' => new external_value(PARAM_INT, 'instance ID'),
304 'state' => new external_value(PARAM_INT,
305 "Completion state value:
306 0 means incomplete,
307 1 complete,
308 2 complete pass,
309 3 complete fail"
311 'timecompleted' => new external_value(PARAM_INT,
312 'timestamp for completed activity'),
313 'tracking' => new external_value(PARAM_INT,
314 "type of tracking:
315 0 means none,
316 1 manual,
317 2 automatic"
319 'overrideby' => new external_value(PARAM_INT,
320 'The user id who has overriden the status, or null', VALUE_OPTIONAL),
321 'valueused' => new external_value(PARAM_BOOL,
322 'Whether the completion status affects the availability of another activity.',
323 VALUE_OPTIONAL),
324 'hascompletion' => new external_value(PARAM_BOOL,
325 'Whether this activity module has completion enabled',
326 VALUE_OPTIONAL),
327 'isautomatic' => new external_value(PARAM_BOOL,
328 'Whether this activity module instance tracks completion automatically.',
329 VALUE_OPTIONAL),
330 'istrackeduser' => new external_value(PARAM_BOOL,
331 'Whether completion is being tracked for this user.',
332 VALUE_OPTIONAL),
333 'uservisible' => new external_value(PARAM_BOOL,
334 'Whether this activity is visible to the user.',
335 VALUE_OPTIONAL),
336 'details' => new external_multiple_structure(
337 new external_single_structure(
339 'rulename' => new external_value(PARAM_TEXT, 'Rule name'),
340 'rulevalue' => new external_single_structure(
342 'status' => new external_value(PARAM_INT, 'Completion status'),
343 'description' => new external_value(PARAM_TEXT, 'Completion description'),
348 'Completion status details',
349 VALUE_DEFAULT,
353 ], 'Activity'
354 ), 'List of activities status'
356 'warnings' => new external_warnings()
362 * Returns description of method parameters
364 * @return external_function_parameters
365 * @since Moodle 2.9
367 public static function get_course_completion_status_parameters() {
368 return new external_function_parameters(
369 array(
370 'courseid' => new external_value(PARAM_INT, 'Course ID'),
371 'userid' => new external_value(PARAM_INT, 'User ID'),
376 * Get Course completion status
378 * @param int $courseid ID of the Course
379 * @param int $userid ID of the User
380 * @return array of course completion status and warnings
381 * @since Moodle 2.9
382 * @throws moodle_exception
384 public static function get_course_completion_status($courseid, $userid) {
385 global $CFG, $USER;
386 require_once($CFG->libdir . '/grouplib.php');
388 $warnings = array();
389 $arrayparams = array(
390 'courseid' => $courseid,
391 'userid' => $userid,
393 $params = self::validate_parameters(self::get_course_completion_status_parameters(), $arrayparams);
395 $course = get_course($params['courseid']);
396 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
397 core_user::require_active_user($user);
399 $context = context_course::instance($course->id);
400 self::validate_context($context);
402 // Can current user see user's course completion status?
403 // This check verifies if completion is enabled because $course is mandatory.
404 if (!completion_can_view_data($user->id, $course)) {
405 throw new moodle_exception('cannotviewreport');
408 // The previous function doesn't check groups.
409 if ($user->id != $USER->id) {
410 if (!groups_user_groups_visible($course, $user->id)) {
411 // We are not in the same group!
412 throw new moodle_exception('accessdenied', 'admin');
416 $info = new completion_info($course);
418 // Check this user is enroled.
419 if (!$info->is_tracked_user($user->id)) {
420 if ($USER->id == $user->id) {
421 throw new moodle_exception('notenroled', 'completion');
422 } else {
423 throw new moodle_exception('usernotenroled', 'completion');
427 $completions = $info->get_completions($user->id);
428 if (empty($completions)) {
429 throw new moodle_exception('nocriteriaset', 'completion');
432 // Load course completion.
433 $completionparams = array(
434 'userid' => $user->id,
435 'course' => $course->id,
437 $ccompletion = new completion_completion($completionparams);
439 $completionrows = array();
440 // Loop through course criteria.
441 foreach ($completions as $completion) {
442 $criteria = $completion->get_criteria();
444 $completionrow = array();
445 $completionrow['type'] = $criteria->criteriatype;
446 $completionrow['title'] = $criteria->get_title();
447 $completionrow['status'] = $completion->get_status();
448 $completionrow['complete'] = $completion->is_complete();
449 $completionrow['timecompleted'] = $completion->timecompleted;
450 $completionrow['details'] = $criteria->get_details($completion);
451 $completionrows[] = $completionrow;
454 $result = array(
455 'completed' => $info->is_course_complete($user->id),
456 'aggregation' => $info->get_aggregation_method(),
457 'completions' => $completionrows
460 $results = array(
461 'completionstatus' => $result,
462 'warnings' => $warnings
464 return $results;
468 * Returns description of method result value
470 * @return \core_external\external_description
471 * @since Moodle 2.9
473 public static function get_course_completion_status_returns() {
474 return new external_single_structure(
475 array(
476 'completionstatus' => new external_single_structure(
477 array(
478 'completed' => new external_value(PARAM_BOOL, 'true if the course is complete, false otherwise'),
479 'aggregation' => new external_value(PARAM_INT, 'aggregation method 1 means all, 2 means any'),
480 'completions' => new external_multiple_structure(
481 new external_single_structure(
482 array(
483 'type' => new external_value(PARAM_INT, 'Completion criteria type'),
484 'title' => new external_value(PARAM_TEXT, 'Completion criteria Title'),
485 'status' => new external_value(PARAM_NOTAGS, 'Completion status (Yes/No) a % or number'),
486 'complete' => new external_value(PARAM_BOOL, 'Completion status (true/false)'),
487 'timecompleted' => new external_value(PARAM_INT, 'Timestamp for criteria completetion'),
488 'details' => new external_single_structure(
489 array(
490 'type' => new external_value(PARAM_TEXT, 'Type description'),
491 'criteria' => new external_value(PARAM_RAW, 'Criteria description'),
492 'requirement' => new external_value(PARAM_TEXT, 'Requirement description'),
493 'status' => new external_value(PARAM_RAW, 'Status description, can be anything'),
494 ), 'details'),
495 ), 'Completions'
496 ), ''
498 ), 'Course status'
500 'warnings' => new external_warnings()
501 ), 'Course completion status'
506 * Describes the parameters for mark_course_self_completed.
508 * @return external_function_parameters
509 * @since Moodle 3.0
511 public static function mark_course_self_completed_parameters() {
512 return new external_function_parameters (
513 array(
514 'courseid' => new external_value(PARAM_INT, 'Course ID')
520 * Update the course completion status for the current user (if course self-completion is enabled).
522 * @param int $courseid Course id
523 * @return array Result and possible warnings
524 * @since Moodle 3.0
525 * @throws moodle_exception
527 public static function mark_course_self_completed($courseid) {
528 global $USER;
530 $warnings = array();
531 $params = self::validate_parameters(self::mark_course_self_completed_parameters(),
532 array('courseid' => $courseid));
534 $course = get_course($params['courseid']);
535 $context = context_course::instance($course->id);
536 self::validate_context($context);
538 // Set up completion object and check it is enabled.
539 $completion = new completion_info($course);
540 if (!$completion->is_enabled()) {
541 throw new moodle_exception('completionnotenabled', 'completion');
544 if (!$completion->is_tracked_user($USER->id)) {
545 throw new moodle_exception('nottracked', 'completion');
548 $completion = $completion->get_completion($USER->id, COMPLETION_CRITERIA_TYPE_SELF);
550 // Self completion criteria not enabled.
551 if (!$completion) {
552 throw new moodle_exception('noselfcompletioncriteria', 'completion');
555 // Check if the user has already marked himself as complete.
556 if ($completion->is_complete()) {
557 throw new moodle_exception('useralreadymarkedcomplete', 'completion');
560 // Mark the course complete.
561 $completion->mark_complete();
563 $result = array();
564 $result['status'] = true;
565 $result['warnings'] = $warnings;
566 return $result;
570 * Describes the mark_course_self_completed return value.
572 * @return external_single_structure
573 * @since Moodle 3.0
575 public static function mark_course_self_completed_returns() {
577 return new external_single_structure(
578 array(
579 'status' => new external_value(PARAM_BOOL, 'status, true if success'),
580 'warnings' => new external_warnings(),