Merge branch 'MDL-29320-master' of git://github.com/junpataleta/moodle
[moodle.git] / completion / classes / external.php
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/>.
17 /**
18  * Completion external API
19  *
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
25  */
27 defined('MOODLE_INTERNAL') || die;
29 require_once("$CFG->libdir/externallib.php");
30 require_once("$CFG->libdir/completionlib.php");
32 /**
33  * Completion external functions
34  *
35  * @package    core_completion
36  * @category   external
37  * @copyright  2015 Juan Leyva <juan@moodle.com>
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since      Moodle 2.9
40  */
41 class core_completion_external extends external_api {
43     /**
44      * Describes the parameters for update_activity_completion_status_manually.
45      *
46      * @return external_function_parameters
47      * @since Moodle 2.9
48      */
49     public static function update_activity_completion_status_manually_parameters() {
50         return new external_function_parameters (
51             array(
52                 'cmid' => new external_value(PARAM_INT, 'course module id'),
53                 'completed' => new external_value(PARAM_BOOL, 'activity completed or not'),
54             )
55         );
56     }
58     /**
59      * Update completion status for the current user in an activity, only for activities with manual tracking.
60      * @param  int $cmid      Course module id
61      * @param  bool $completed Activity completed or not
62      * @return array            Result and possible warnings
63      * @since Moodle 2.9
64      * @throws moodle_exception
65      */
66     public static function update_activity_completion_status_manually($cmid,  $completed) {
68         // Validate and normalize parameters.
69         $params = self::validate_parameters(self::update_activity_completion_status_manually_parameters(),
70             array('cmid' => $cmid, 'completed' => $completed));
71         $cmid = $params['cmid'];
72         $completed = $params['completed'];
74         $warnings = array();
76         $context = context_module::instance($cmid);
77         self::validate_context($context);
78         require_capability('moodle/course:togglecompletion', $context);
80         list($course, $cm) = get_course_and_cm_from_cmid($cmid);
82         // Set up completion object and check it is enabled.
83         $completion = new completion_info($course);
84         if (!$completion->is_enabled()) {
85             throw new moodle_exception('completionnotenabled', 'completion');
86         }
88         // Check completion state is manual.
89         if ($cm->completion != COMPLETION_TRACKING_MANUAL) {
90             throw new moodle_exception('cannotmanualctrack', 'error');
91         }
93         $targetstate = ($completed) ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
94         $completion->update_state($cm, $targetstate);
96         $result = array();
97         $result['status'] = true;
98         $result['warnings'] = $warnings;
99         return $result;
100     }
102     /**
103      * Describes the update_activity_completion_status_manually return value.
104      *
105      * @return external_single_structure
106      * @since Moodle 2.9
107      */
108     public static function update_activity_completion_status_manually_returns() {
110         return new external_single_structure(
111             array(
112                 'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
113                 'warnings'  => new external_warnings(),
114             )
115         );
116     }
118     /**
119      * Describes the parameters for override_activity_completion_status.
120      *
121      * @return external_external_function_parameters
122      * @since Moodle 3.4
123      */
124     public static function override_activity_completion_status_parameters() {
125         return new external_function_parameters (
126             array(
127                 'userid' => new external_value(PARAM_INT, 'user id'),
128                 'cmid' => new external_value(PARAM_INT, 'course module id'),
129                 'newstate' => new external_value(PARAM_INT, 'the new activity completion state'),
130             )
131         );
132     }
134     /**
135      * Update completion status for a user in an activity.
136      * @param  int $userid    User id
137      * @param  int $cmid      Course module id
138      * @param  int $newstate  Activity completion
139      * @return array          Array containing the current (updated) completion status.
140      * @since Moodle 3.4
141      * @throws moodle_exception
142      */
143     public static function override_activity_completion_status($userid, $cmid, $newstate) {
144         // Validate and normalize parameters.
145         $params = self::validate_parameters(self::override_activity_completion_status_parameters(),
146             array('userid' => $userid, 'cmid' => $cmid, 'newstate' => $newstate));
147         $userid = $params['userid'];
148         $cmid = $params['cmid'];
149         $newstate = $params['newstate'];
151         $context = context_module::instance($cmid);
152         self::validate_context($context);
154         list($course, $cm) = get_course_and_cm_from_cmid($cmid);
156         // Set up completion object and check it is enabled.
157         $completion = new completion_info($course);
158         if (!$completion->is_enabled()) {
159             throw new moodle_exception('completionnotenabled', 'completion');
160         }
162         // Update completion state and get the new state back.
163         $completion->update_state($cm, $newstate, $userid, true);
164         $completiondata = $completion->get_data($cm, false, $userid);
166         // Return the current state of completion.
167         return [
168             'cmid' => $completiondata->coursemoduleid,
169             'userid' => $completiondata->userid,
170             'state' => $completiondata->completionstate,
171             'timecompleted' => $completiondata->timemodified,
172             'overrideby' => $completiondata->overrideby,
173             'tracking' => $completion->is_enabled($cm)
174         ];
175     }
177     /**
178      * Describes the override_activity_completion_status return value.
179      *
180      * @return external_single_structure
181      * @since Moodle 3.4
182      */
183     public static function override_activity_completion_status_returns() {
185         return new external_single_structure(
186             array(
187                 'cmid' => new external_value(PARAM_INT, 'The course module id'),
188                 'userid' => new external_value(PARAM_INT, 'The user id to which the completion info belongs'),
189                 'state'   => new external_value(PARAM_INT, 'The current completion state.'),
190                 'timecompleted' => new external_value(PARAM_INT, 'time of completion'),
191                 'overrideby' => new external_value(PARAM_INT, 'The user id who has overriden the status, or null'),
192                 'tracking'      => new external_value(PARAM_INT, 'type of tracking:
193                                                                     0 means none, 1 manual, 2 automatic'),
194             )
195         );
196     }
198     /**
199      * Returns description of method parameters
200      *
201      * @return external_function_parameters
202      * @since Moodle 2.9
203      */
204     public static function get_activities_completion_status_parameters() {
205         return new external_function_parameters(
206             array(
207                 'courseid' => new external_value(PARAM_INT, 'Course ID'),
208                 'userid'   => new external_value(PARAM_INT, 'User ID'),
209             )
210         );
211     }
213     /**
214      * Get Activities completion status
215      *
216      * @param int $courseid ID of the Course
217      * @param int $userid ID of the User
218      * @return array of activities progress and warnings
219      * @throws moodle_exception
220      * @since Moodle 2.9
221      * @throws moodle_exception
222      */
223     public static function get_activities_completion_status($courseid, $userid) {
224         global $CFG, $USER;
225         require_once($CFG->libdir . '/grouplib.php');
227         $warnings = array();
228         $arrayparams = array(
229             'courseid' => $courseid,
230             'userid'   => $userid,
231         );
233         $params = self::validate_parameters(self::get_activities_completion_status_parameters(), $arrayparams);
235         $course = get_course($params['courseid']);
236         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
237         core_user::require_active_user($user);
239         $context = context_course::instance($course->id);
240         self::validate_context($context);
242         // Check that current user have permissions to see this user's activities.
243         if ($user->id != $USER->id) {
244             require_capability('report/progress:view', $context);
245             if (!groups_user_groups_visible($course, $user->id)) {
246                 // We are not in the same group!
247                 throw new moodle_exception('accessdenied', 'admin');
248             }
249         }
251         $completion = new completion_info($course);
252         $activities = $completion->get_activities();
254         $results = array();
255         foreach ($activities as $activity) {
257             // Check if current user has visibility on this activity.
258             if (!$activity->uservisible) {
259                 continue;
260             }
262             // Get progress information and state (we must use get_data because it works for all user roles in course).
263             $activitycompletiondata = $completion->get_data($activity, true, $user->id);
265             $results[] = array(
266                        'cmid'          => $activity->id,
267                        'modname'       => $activity->modname,
268                        'instance'      => $activity->instance,
269                        'state'         => $activitycompletiondata->completionstate,
270                        'timecompleted' => $activitycompletiondata->timemodified,
271                        'tracking'      => $activity->completion,
272                        'overrideby'    => $activitycompletiondata->overrideby,
273                        'valueused'     => core_availability\info::completion_value_used($course, $activity->id)
274             );
275         }
277         $results = array(
278             'statuses' => $results,
279             'warnings' => $warnings
280         );
281         return $results;
282     }
284     /**
285      * Returns description of method result value
286      *
287      * @return external_description
288      * @since Moodle 2.9
289      */
290     public static function get_activities_completion_status_returns() {
291         return new external_single_structure(
292             array(
293                 'statuses' => new external_multiple_structure(
294                     new external_single_structure(
295                         array(
296                             'cmid'          => new external_value(PARAM_INT, 'comment ID'),
297                             'modname'       => new external_value(PARAM_PLUGIN, 'activity module name'),
298                             'instance'      => new external_value(PARAM_INT, 'instance ID'),
299                             'state'         => new external_value(PARAM_INT, 'completion state value:
300                                                                     0 means incomplete, 1 complete,
301                                                                     2 complete pass, 3 complete fail'),
302                             'timecompleted' => new external_value(PARAM_INT, 'timestamp for completed activity'),
303                             'tracking'      => new external_value(PARAM_INT, 'type of tracking:
304                                                                     0 means none, 1 manual, 2 automatic'),
305                             'overrideby' => new external_value(PARAM_INT, 'The user id who has overriden the status, or null',
306                                 VALUE_OPTIONAL),
307                             'valueused' => new external_value(PARAM_BOOL, 'Whether the completion status affects the availability
308                                     of another activity.', VALUE_OPTIONAL),
309                         ), 'Activity'
310                     ), 'List of activities status'
311                 ),
312                 'warnings' => new external_warnings()
313             )
314         );
315     }
317     /**
318      * Returns description of method parameters
319      *
320      * @return external_function_parameters
321      * @since Moodle 2.9
322      */
323     public static function get_course_completion_status_parameters() {
324         return new external_function_parameters(
325             array(
326                 'courseid' => new external_value(PARAM_INT, 'Course ID'),
327                 'userid'   => new external_value(PARAM_INT, 'User ID'),
328             )
329         );
330     }
331     /**
332      * Get Course completion status
333      *
334      * @param int $courseid ID of the Course
335      * @param int $userid ID of the User
336      * @return array of course completion status and warnings
337      * @since Moodle 2.9
338      * @throws moodle_exception
339      */
340     public static function get_course_completion_status($courseid, $userid) {
341         global $CFG, $USER;
342         require_once($CFG->libdir . '/grouplib.php');
344         $warnings = array();
345         $arrayparams = array(
346             'courseid' => $courseid,
347             'userid'   => $userid,
348         );
349         $params = self::validate_parameters(self::get_course_completion_status_parameters(), $arrayparams);
351         $course = get_course($params['courseid']);
352         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
353         core_user::require_active_user($user);
355         $context = context_course::instance($course->id);
356         self::validate_context($context);
358         // Can current user see user's course completion status?
359         // This check verifies if completion is enabled because $course is mandatory.
360         if (!completion_can_view_data($user->id, $course)) {
361             throw new moodle_exception('cannotviewreport');
362         }
364         // The previous function doesn't check groups.
365         if ($user->id != $USER->id) {
366             if (!groups_user_groups_visible($course, $user->id)) {
367                 // We are not in the same group!
368                 throw new moodle_exception('accessdenied', 'admin');
369             }
370         }
372         $info = new completion_info($course);
374         // Check this user is enroled.
375         if (!$info->is_tracked_user($user->id)) {
376             if ($USER->id == $user->id) {
377                 throw new moodle_exception('notenroled', 'completion');
378             } else {
379                 throw new moodle_exception('usernotenroled', 'completion');
380             }
381         }
383         $completions = $info->get_completions($user->id);
384         if (empty($completions)) {
385             throw new moodle_exception('nocriteriaset', 'completion');
386         }
388         // Load course completion.
389         $completionparams = array(
390             'userid' => $user->id,
391             'course' => $course->id,
392         );
393         $ccompletion = new completion_completion($completionparams);
395         $completionrows = array();
396         // Loop through course criteria.
397         foreach ($completions as $completion) {
398             $criteria = $completion->get_criteria();
400             $completionrow = array();
401             $completionrow['type'] = $criteria->criteriatype;
402             $completionrow['title'] = $criteria->get_title();
403             $completionrow['status'] = $completion->get_status();
404             $completionrow['complete'] = $completion->is_complete();
405             $completionrow['timecompleted'] = $completion->timecompleted;
406             $completionrow['details'] = $criteria->get_details($completion);
407             $completionrows[] = $completionrow;
408         }
410         $result = array(
411                   'completed'   => $info->is_course_complete($user->id),
412                   'aggregation' => $info->get_aggregation_method(),
413                   'completions' => $completionrows
414         );
416         $results = array(
417             'completionstatus' => $result,
418             'warnings' => $warnings
419         );
420         return $results;
422     }
423     /**
424      * Returns description of method result value
425      *
426      * @return external_description
427      * @since Moodle 2.9
428      */
429     public static function get_course_completion_status_returns() {
430         return new external_single_structure(
431             array(
432                 'completionstatus' => new external_single_structure(
433                     array(
434                         'completed'     => new external_value(PARAM_BOOL, 'true if the course is complete, false otherwise'),
435                         'aggregation'   => new external_value(PARAM_INT, 'aggregation method 1 means all, 2 means any'),
436                         'completions'   => new external_multiple_structure(
437                             new external_single_structure(
438                             array(
439                                  'type'          => new external_value(PARAM_INT,   'Completion criteria type'),
440                                  'title'         => new external_value(PARAM_TEXT,  'Completion criteria Title'),
441                                  'status'        => new external_value(PARAM_NOTAGS, 'Completion status (Yes/No) a % or number'),
442                                  'complete'      => new external_value(PARAM_BOOL,   'Completion status (true/false)'),
443                                  'timecompleted' => new external_value(PARAM_INT,   'Timestamp for criteria completetion'),
444                                  'details' => new external_single_structure(
445                                      array(
446                                          'type' => new external_value(PARAM_TEXT, 'Type description'),
447                                          'criteria' => new external_value(PARAM_RAW, 'Criteria description'),
448                                          'requirement' => new external_value(PARAM_TEXT, 'Requirement description'),
449                                          'status' => new external_value(PARAM_RAW, 'Status description, can be anything'),
450                                          ), 'details'),
451                                  ), 'Completions'
452                             ), ''
453                          )
454                     ), 'Course status'
455                 ),
456                 'warnings' => new external_warnings()
457             ), 'Course completion status'
458         );
459     }
461     /**
462      * Describes the parameters for mark_course_self_completed.
463      *
464      * @return external_function_parameters
465      * @since Moodle 3.0
466      */
467     public static function mark_course_self_completed_parameters() {
468         return new external_function_parameters (
469             array(
470                 'courseid' => new external_value(PARAM_INT, 'Course ID')
471             )
472         );
473     }
475     /**
476      * Update the course completion status for the current user (if course self-completion is enabled).
477      *
478      * @param  int $courseid    Course id
479      * @return array            Result and possible warnings
480      * @since Moodle 3.0
481      * @throws moodle_exception
482      */
483     public static function mark_course_self_completed($courseid) {
484         global $USER;
486         $warnings = array();
487         $params = self::validate_parameters(self::mark_course_self_completed_parameters(),
488                                             array('courseid' => $courseid));
490         $course = get_course($params['courseid']);
491         $context = context_course::instance($course->id);
492         self::validate_context($context);
494         // Set up completion object and check it is enabled.
495         $completion = new completion_info($course);
496         if (!$completion->is_enabled()) {
497             throw new moodle_exception('completionnotenabled', 'completion');
498         }
500         if (!$completion->is_tracked_user($USER->id)) {
501             throw new moodle_exception('nottracked', 'completion');
502         }
504         $completion = $completion->get_completion($USER->id, COMPLETION_CRITERIA_TYPE_SELF);
506         // Self completion criteria not enabled.
507         if (!$completion) {
508             throw new moodle_exception('noselfcompletioncriteria', 'completion');
509         }
511         // Check if the user has already marked himself as complete.
512         if ($completion->is_complete()) {
513             throw new moodle_exception('useralreadymarkedcomplete', 'completion');
514         }
516         // Mark the course complete.
517         $completion->mark_complete();
519         $result = array();
520         $result['status'] = true;
521         $result['warnings'] = $warnings;
522         return $result;
523     }
525     /**
526      * Describes the mark_course_self_completed return value.
527      *
528      * @return external_single_structure
529      * @since Moodle 3.0
530      */
531     public static function mark_course_self_completed_returns() {
533         return new external_single_structure(
534             array(
535                 'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
536                 'warnings'  => new external_warnings(),
537             )
538         );
539     }