Merge branch 'MDL-55267-master-deprecation' of https://github.com/marcusgreen/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);
79         list($course, $cm) = get_course_and_cm_from_cmid($cmid);
81         // Set up completion object and check it is enabled.
82         $completion = new completion_info($course);
83         if (!$completion->is_enabled()) {
84             throw new moodle_exception('completionnotenabled', 'completion');
85         }
87         // Check completion state is manual.
88         if ($cm->completion != COMPLETION_TRACKING_MANUAL) {
89             throw new moodle_exception('cannotmanualctrack', 'error');
90         }
92         $targetstate = ($completed) ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
93         $completion->update_state($cm, $targetstate);
95         $result = array();
96         $result['status'] = true;
97         $result['warnings'] = $warnings;
98         return $result;
99     }
101     /**
102      * Describes the update_activity_completion_status_manually return value.
103      *
104      * @return external_single_structure
105      * @since Moodle 2.9
106      */
107     public static function update_activity_completion_status_manually_returns() {
109         return new external_single_structure(
110             array(
111                 'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
112                 'warnings'  => new external_warnings(),
113             )
114         );
115     }
117     /**
118      * Returns description of method parameters
119      *
120      * @return external_function_parameters
121      * @since Moodle 2.9
122      */
123     public static function get_activities_completion_status_parameters() {
124         return new external_function_parameters(
125             array(
126                 'courseid' => new external_value(PARAM_INT, 'Course ID'),
127                 'userid'   => new external_value(PARAM_INT, 'User ID'),
128             )
129         );
130     }
132     /**
133      * Get Activities completion status
134      *
135      * @param int $courseid ID of the Course
136      * @param int $userid ID of the User
137      * @return array of activities progress and warnings
138      * @throws moodle_exception
139      * @since Moodle 2.9
140      * @throws moodle_exception
141      */
142     public static function get_activities_completion_status($courseid, $userid) {
143         global $CFG, $USER;
144         require_once($CFG->libdir . '/grouplib.php');
146         $warnings = array();
147         $arrayparams = array(
148             'courseid' => $courseid,
149             'userid'   => $userid,
150         );
152         $params = self::validate_parameters(self::get_activities_completion_status_parameters(), $arrayparams);
154         $course = get_course($params['courseid']);
155         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
156         core_user::require_active_user($user);
158         $context = context_course::instance($course->id);
159         self::validate_context($context);
161         // Check that current user have permissions to see this user's activities.
162         if ($user->id != $USER->id) {
163             require_capability('report/progress:view', $context);
164             if (!groups_user_groups_visible($course, $user->id)) {
165                 // We are not in the same group!
166                 throw new moodle_exception('accessdenied', 'admin');
167             }
168         }
170         $completion = new completion_info($course);
171         $activities = $completion->get_activities();
172         $progresses = $completion->get_progress_all();
173         $userprogress = $progresses[$user->id];
175         $results = array();
176         foreach ($activities as $activity) {
178             // Check if current user has visibility on this activity.
179             if (!$activity->uservisible) {
180                 continue;
181             }
183             // Get progress information and state.
184             if (array_key_exists($activity->id, $userprogress->progress)) {
185                 $thisprogress  = $userprogress->progress[$activity->id];
186                 $state         = $thisprogress->completionstate;
187                 $timecompleted = $thisprogress->timemodified;
188             } else {
189                 $state = COMPLETION_INCOMPLETE;
190                 $timecompleted = 0;
191             }
193             $results[] = array(
194                        'cmid'          => $activity->id,
195                        'modname'       => $activity->modname,
196                        'instance'      => $activity->instance,
197                        'state'         => $state,
198                        'timecompleted' => $timecompleted,
199                        'tracking'      => $activity->completion
200             );
201         }
203         $results = array(
204             'statuses' => $results,
205             'warnings' => $warnings
206         );
207         return $results;
208     }
210     /**
211      * Returns description of method result value
212      *
213      * @return external_description
214      * @since Moodle 2.9
215      */
216     public static function get_activities_completion_status_returns() {
217         return new external_single_structure(
218             array(
219                 'statuses' => new external_multiple_structure(
220                     new external_single_structure(
221                         array(
222                             'cmid'          => new external_value(PARAM_INT, 'comment ID'),
223                             'modname'       => new external_value(PARAM_PLUGIN, 'activity module name'),
224                             'instance'      => new external_value(PARAM_INT, 'instance ID'),
225                             'state'         => new external_value(PARAM_INT, 'completion state value:
226                                                                     0 means incomplete, 1 complete,
227                                                                     2 complete pass, 3 complete fail'),
228                             'timecompleted' => new external_value(PARAM_INT, 'timestamp for completed activity'),
229                             'tracking'      => new external_value(PARAM_INT, 'type of tracking:
230                                                                     0 means none, 1 manual, 2 automatic'),
231                         ), 'Activity'
232                     ), 'List of activities status'
233                 ),
234                 'warnings' => new external_warnings()
235             )
236         );
237     }
239     /**
240      * Returns description of method parameters
241      *
242      * @return external_function_parameters
243      * @since Moodle 2.9
244      */
245     public static function get_course_completion_status_parameters() {
246         return new external_function_parameters(
247             array(
248                 'courseid' => new external_value(PARAM_INT, 'Course ID'),
249                 'userid'   => new external_value(PARAM_INT, 'User ID'),
250             )
251         );
252     }
253     /**
254      * Get Course completion status
255      *
256      * @param int $courseid ID of the Course
257      * @param int $userid ID of the User
258      * @return array of course completion status and warnings
259      * @since Moodle 2.9
260      * @throws moodle_exception
261      */
262     public static function get_course_completion_status($courseid, $userid) {
263         global $CFG, $USER;
264         require_once($CFG->libdir . '/grouplib.php');
266         $warnings = array();
267         $arrayparams = array(
268             'courseid' => $courseid,
269             'userid'   => $userid,
270         );
271         $params = self::validate_parameters(self::get_course_completion_status_parameters(), $arrayparams);
273         $course = get_course($params['courseid']);
274         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
275         core_user::require_active_user($user);
277         $context = context_course::instance($course->id);
278         self::validate_context($context);
280         // Can current user see user's course completion status?
281         // This check verifies if completion is enabled because $course is mandatory.
282         if (!completion_can_view_data($user->id, $course)) {
283             throw new moodle_exception('cannotviewreport');
284         }
286         // The previous function doesn't check groups.
287         if ($user->id != $USER->id) {
288             if (!groups_user_groups_visible($course, $user->id)) {
289                 // We are not in the same group!
290                 throw new moodle_exception('accessdenied', 'admin');
291             }
292         }
294         $info = new completion_info($course);
296         // Check this user is enroled.
297         if (!$info->is_tracked_user($user->id)) {
298             if ($USER->id == $user->id) {
299                 throw new moodle_exception('notenroled', 'completion');
300             } else {
301                 throw new moodle_exception('usernotenroled', 'completion');
302             }
303         }
305         $completions = $info->get_completions($user->id);
306         if (empty($completions)) {
307             throw new moodle_exception('nocriteriaset', 'completion');
308         }
310         // Load course completion.
311         $completionparams = array(
312             'userid' => $user->id,
313             'course' => $course->id,
314         );
315         $ccompletion = new completion_completion($completionparams);
317         $completionrows = array();
318         // Loop through course criteria.
319         foreach ($completions as $completion) {
320             $criteria = $completion->get_criteria();
322             $completionrow = array();
323             $completionrow['type'] = $criteria->criteriatype;
324             $completionrow['title'] = $criteria->get_title();
325             $completionrow['status'] = $completion->get_status();
326             $completionrow['complete'] = $completion->is_complete();
327             $completionrow['timecompleted'] = $completion->timecompleted;
328             $completionrow['details'] = $criteria->get_details($completion);
329             $completionrows[] = $completionrow;
330         }
332         $result = array(
333                   'completed'   => $info->is_course_complete($user->id),
334                   'aggregation' => $info->get_aggregation_method(),
335                   'completions' => $completionrows
336         );
338         $results = array(
339             'completionstatus' => $result,
340             'warnings' => $warnings
341         );
342         return $results;
344     }
345     /**
346      * Returns description of method result value
347      *
348      * @return external_description
349      * @since Moodle 2.9
350      */
351     public static function get_course_completion_status_returns() {
352         return new external_single_structure(
353             array(
354                 'completionstatus' => new external_single_structure(
355                     array(
356                         'completed'     => new external_value(PARAM_BOOL, 'true if the course is complete, false otherwise'),
357                         'aggregation'   => new external_value(PARAM_INT, 'aggregation method 1 means all, 2 means any'),
358                         'completions'   => new external_multiple_structure(
359                             new external_single_structure(
360                             array(
361                                  'type'          => new external_value(PARAM_INT,   'Completion criteria type'),
362                                  'title'         => new external_value(PARAM_TEXT,  'Completion criteria Title'),
363                                  'status'        => new external_value(PARAM_NOTAGS, 'Completion status (Yes/No) a % or number'),
364                                  'complete'      => new external_value(PARAM_BOOL,   'Completion status (true/false)'),
365                                  'timecompleted' => new external_value(PARAM_INT,   'Timestamp for criteria completetion'),
366                                  'details' => new external_single_structure(
367                                      array(
368                                          'type' => new external_value(PARAM_TEXT, 'Type description'),
369                                          'criteria' => new external_value(PARAM_RAW, 'Criteria description'),
370                                          'requirement' => new external_value(PARAM_TEXT, 'Requirement description'),
371                                          'status' => new external_value(PARAM_RAW, 'Status description, can be anything'),
372                                          ), 'details'),
373                                  ), 'Completions'
374                             ), ''
375                          )
376                     ), 'Course status'
377                 ),
378                 'warnings' => new external_warnings()
379             ), 'Course completion status'
380         );
381     }
383     /**
384      * Describes the parameters for mark_course_self_completed.
385      *
386      * @return external_function_parameters
387      * @since Moodle 3.0
388      */
389     public static function mark_course_self_completed_parameters() {
390         return new external_function_parameters (
391             array(
392                 'courseid' => new external_value(PARAM_INT, 'Course ID')
393             )
394         );
395     }
397     /**
398      * Update the course completion status for the current user (if course self-completion is enabled).
399      *
400      * @param  int $courseid    Course id
401      * @return array            Result and possible warnings
402      * @since Moodle 3.0
403      * @throws moodle_exception
404      */
405     public static function mark_course_self_completed($courseid) {
406         global $USER;
408         $warnings = array();
409         $params = self::validate_parameters(self::mark_course_self_completed_parameters(),
410                                             array('courseid' => $courseid));
412         $course = get_course($params['courseid']);
413         $context = context_course::instance($course->id);
414         self::validate_context($context);
416         // Set up completion object and check it is enabled.
417         $completion = new completion_info($course);
418         if (!$completion->is_enabled()) {
419             throw new moodle_exception('completionnotenabled', 'completion');
420         }
422         if (!$completion->is_tracked_user($USER->id)) {
423             throw new moodle_exception('nottracked', 'completion');
424         }
426         $completion = $completion->get_completion($USER->id, COMPLETION_CRITERIA_TYPE_SELF);
428         // Self completion criteria not enabled.
429         if (!$completion) {
430             throw new moodle_exception('noselfcompletioncriteria', 'completion');
431         }
433         // Check if the user has already marked himself as complete.
434         if ($completion->is_complete()) {
435             throw new moodle_exception('useralreadymarkedcomplete', 'completion');
436         }
438         // Mark the course complete.
439         $completion->mark_complete();
441         $result = array();
442         $result['status'] = true;
443         $result['warnings'] = $warnings;
444         return $result;
445     }
447     /**
448      * Describes the mark_course_self_completed return value.
449      *
450      * @return external_single_structure
451      * @since Moodle 3.0
452      */
453     public static function mark_course_self_completed_returns() {
455         return new external_single_structure(
456             array(
457                 'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
458                 'warnings'  => new external_warnings(),
459             )
460         );
461     }