MDL-50353 scorm: New Web Service mod_scorm_insert_scorm_tracks
[moodle.git] / mod / scorm / 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  * SCORM module external API
19  *
20  * @package    mod_scorm
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 3.0
25  */
27 defined('MOODLE_INTERNAL') || die;
29 require_once($CFG->libdir . '/externallib.php');
30 require_once($CFG->dirroot . '/mod/scorm/lib.php');
31 require_once($CFG->dirroot . '/mod/scorm/locallib.php');
33 /**
34  * SCORM module external functions
35  *
36  * @package    mod_scorm
37  * @category   external
38  * @copyright  2015 Juan Leyva <juan@moodle.com>
39  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40  * @since      Moodle 3.0
41  */
42 class mod_scorm_external extends external_api {
44     /**
45      * Returns description of method parameters
46      *
47      * @return external_function_parameters
48      * @since Moodle 3.0
49      */
50     public static function view_scorm_parameters() {
51         return new external_function_parameters(
52             array(
53                 'scormid' => new external_value(PARAM_INT, 'scorm instance id')
54             )
55         );
56     }
58     /**
59      * Trigger the course module viewed event.
60      *
61      * @param int $scormid the scorm instance id
62      * @return array of warnings and status result
63      * @since Moodle 3.0
64      * @throws moodle_exception
65      */
66     public static function view_scorm($scormid) {
67         global $DB, $CFG;
68         require_once($CFG->dirroot . '/mod/scorm/lib.php');
70         $params = self::validate_parameters(self::view_scorm_parameters(),
71                                             array(
72                                                 'scormid' => $scormid
73                                             ));
74         $warnings = array();
76         // Request and permission validation.
77         $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
78         list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm');
80         $context = context_module::instance($cm->id);
81         self::validate_context($context);
83         // Call the scorm/lib API.
84         scorm_view($scorm, $course, $cm, $context);
86         $result = array();
87         $result['status'] = true;
88         $result['warnings'] = $warnings;
89         return $result;
90     }
92     /**
93      * Returns description of method result value
94      *
95      * @return external_description
96      * @since Moodle 3.0
97      */
98     public static function view_scorm_returns() {
99         return new external_single_structure(
100             array(
101                 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
102                 'warnings' => new external_warnings()
103             )
104         );
105     }
107     /**
108      * Describes the parameters for get_scorm_attempt_count.
109      *
110      * @return external_function_parameters
111      * @since Moodle 3.0
112      */
113     public static function get_scorm_attempt_count_parameters() {
114         return new external_function_parameters(
115             array(
116                 'scormid' => new external_value(PARAM_INT, 'SCORM instance id'),
117                 'userid' => new external_value(PARAM_INT, 'User id'),
118                 'ignoremissingcompletion' => new external_value(PARAM_BOOL,
119                                                 'Ignores attempts that haven\'t reported a grade/completion',
120                                                 VALUE_DEFAULT, false),
121             )
122         );
123     }
125     /**
126      * Return the number of attempts done by a user in the given SCORM.
127      *
128      * @param int $scormid the scorm id
129      * @param int $userid the user id
130      * @param bool $ignoremissingcompletion ignores attempts that haven't reported a grade/completion
131      * @return array of warnings and the attempts count
132      * @since Moodle 3.0
133      */
134     public static function get_scorm_attempt_count($scormid, $userid, $ignoremissingcompletion = false) {
135         global $USER, $DB;
137         $params = self::validate_parameters(self::get_scorm_attempt_count_parameters(),
138                                             array('scormid' => $scormid, 'userid' => $userid,
139                                                 'ignoremissingcompletion' => $ignoremissingcompletion));
141         $attempts = array();
142         $warnings = array();
144         $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
145         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
147         $context = context_module::instance($cm->id);
148         self::validate_context($context);
150         // Validate the user obtaining the context, it will fail if the user doesn't exists or have been deleted.
151         context_user::instance($params['userid']);
153         // Extra checks so only users with permissions can view other users attempts.
154         if ($USER->id != $params['userid']) {
155             require_capability('mod/scorm:viewreport', $context);
156         }
158         // If the SCORM is not open this function will throw exceptions.
159         scorm_require_available($scorm);
161         $attemptscount = scorm_get_attempt_count($params['userid'], $scorm, false, $params['ignoremissingcompletion']);
163         $result = array();
164         $result['attemptscount'] = $attemptscount;
165         $result['warnings'] = $warnings;
166         return $result;
167     }
169     /**
170      * Describes the get_scorm_attempt_count return value.
171      *
172      * @return external_single_structure
173      * @since Moodle 3.0
174      */
175     public static function get_scorm_attempt_count_returns() {
177         return new external_single_structure(
178             array(
179                 'attemptscount' => new external_value(PARAM_INT, 'Attempts count'),
180                 'warnings' => new external_warnings(),
181             )
182         );
183     }
185     /**
186      * Describes the parameters for get_scorms_by_courses.
187      *
188      * @return external_function_parameters
189      * @since Moodle 3.0
190      */
191     public static function get_scorm_scoes_parameters() {
192         return new external_function_parameters(
193             array(
194                 'scormid' => new external_value(PARAM_INT, 'scorm instance id'),
195                 'organization' => new external_value(PARAM_RAW, 'organization id', VALUE_DEFAULT, '')
196             )
197         );
198     }
200     /**
201      * Returns a list containing all the scoes data related to the given scorm id
202      *
203      * @param int $scormid the scorm id
204      * @param string $organization the organization id
205      * @return array warnings and the scoes data
206      * @since Moodle 3.0
207      */
208     public static function get_scorm_scoes($scormid, $organization = '') {
209         global $DB;
211         $params = self::validate_parameters(self::get_scorm_scoes_parameters(),
212                                             array('scormid' => $scormid, 'organization' => $organization));
214         $scoes = array();
215         $warnings = array();
217         $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
218         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
220         $context = context_module::instance($cm->id);
221         self::validate_context($context);
223         // Check settings / permissions to view the SCORM.
224         scorm_require_available($scorm, true, $context);
226         if (!$scoes = scorm_get_scoes($scorm->id, $params['organization'])) {
227             // Function scorm_get_scoes return false, not an empty array.
228             $scoes = array();
229         }
231         $result = array();
232         $result['scoes'] = $scoes;
233         $result['warnings'] = $warnings;
234         return $result;
235     }
237     /**
238      * Describes the get_scorm_scoes return value.
239      *
240      * @return external_single_structure
241      * @since Moodle 3.0
242      */
243     public static function get_scorm_scoes_returns() {
245         return new external_single_structure(
246             array(
247                 'scoes' => new external_multiple_structure(
248                     new external_single_structure(
249                         array(
250                             'id' => new external_value(PARAM_INT, 'sco id'),
251                             'scorm' => new external_value(PARAM_INT, 'scorm id'),
252                             'manifest' => new external_value(PARAM_NOTAGS, 'manifest id'),
253                             'organization' => new external_value(PARAM_NOTAGS, 'organization id'),
254                             'parent' => new external_value(PARAM_NOTAGS, 'parent'),
255                             'identifier' => new external_value(PARAM_NOTAGS, 'identifier'),
256                             'launch' => new external_value(PARAM_NOTAGS, 'launch file'),
257                             'scormtype' => new external_value(PARAM_ALPHA, 'scorm type (asset, sco)'),
258                             'title' => new external_value(PARAM_NOTAGS, 'sco title'),
259                             'sortorder' => new external_value(PARAM_INT, 'sort order'),
260                         ), 'SCORM SCO data'
261                     )
262                 ),
263                 'warnings' => new external_warnings(),
264             )
265         );
266     }
268     /**
269      * Describes the parameters for get_scorm_user_data.
270      *
271      * @return external_function_parameters
272      * @since Moodle 3.0
273      */
274     public static function get_scorm_user_data_parameters() {
275         return new external_function_parameters(
276             array(
277                 'scormid' => new external_value(PARAM_INT, 'scorm instance id'),
278                 'attempt' => new external_value(PARAM_INT, 'attempt number')
279             )
280         );
281     }
283     /**
284      * Retrieves user tracking and SCO data and default SCORM values
285      *
286      * @param int $scormid the scorm id
287      * @param int $attempt the attempt number
288      * @return array warnings and the scoes data
289      * @throws  moodle_exception
290      * @since Moodle 3.0
291      */
292     public static function get_scorm_user_data($scormid, $attempt) {
293         global $CFG, $DB;
295         $params = self::validate_parameters(self::get_scorm_user_data_parameters(),
296                                             array('scormid' => $scormid, 'attempt' => $attempt));
298         $data = array();
299         $warnings = array();
301         $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
302         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
304         $context = context_module::instance($cm->id);
305         self::validate_context($context);
307         scorm_require_available($scorm, true, $context);
309         $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR));
310         if (!file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php')) {
311             $scorm->version = 'scorm_12';
312         }
313         require_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php');
315         if ($scoes = scorm_get_scoes($scorm->id)) {
316             $def = new stdClass();
317             $user = new stdClass();
319             foreach ($scoes as $sco) {
320                 $def->{$sco->id} = new stdClass();
321                 $user->{$sco->id} = new stdClass();
322                 // We force mode normal, this can be override by the client at any time.
323                 $def->{$sco->id} = get_scorm_default($user->{$sco->id}, $scorm, $sco->id, $params['attempt'], 'normal');
325                 $userdata = array();
326                 $defaultdata = array();
328                 foreach ((array) $user->{$sco->id} as $key => $val) {
329                     $userdata[] = array(
330                         'element' => $key,
331                         'value' => $val
332                     );
333                 }
334                 foreach ($def->{$sco->id} as $key => $val) {
335                     $defaultdata[] = array(
336                         'element' => $key,
337                         'value' => $val
338                     );
339                 }
341                 $data[] = array(
342                     'scoid' => $sco->id,
343                     'userdata' => $userdata,
344                     'defaultdata' => $defaultdata,
345                 );
346             }
347         }
349         $result = array();
350         $result['data'] = $data;
351         $result['warnings'] = $warnings;
352         return $result;
353     }
355     /**
356      * Describes the get_scorm_user_data return value.
357      *
358      * @return external_single_structure
359      * @since Moodle 3.0
360      */
361     public static function get_scorm_user_data_returns() {
363         return new external_single_structure(
364             array(
365                 'data' => new external_multiple_structure(
366                     new external_single_structure(
367                         array(
368                             'scoid' => new external_value(PARAM_INT, 'sco id'),
369                             'userdata' => new external_multiple_structure(
370                                             new external_single_structure(
371                                                 array(
372                                                     'element' => new external_value(PARAM_RAW, 'element name'),
373                                                     'value' => new external_value(PARAM_RAW, 'element value')
374                                                 )
375                                             )
376                                           ),
377                             'defaultdata' => new external_multiple_structure(
378                                                 new external_single_structure(
379                                                     array(
380                                                         'element' => new external_value(PARAM_RAW, 'element name'),
381                                                         'value' => new external_value(PARAM_RAW, 'element value')
382                                                     )
383                                                 )
384                                              ),
385                         ), 'SCO data'
386                     )
387                 ),
388                 'warnings' => new external_warnings(),
389             )
390         );
391     }
393     /**
394      * Describes the parameters for insert_scorm_tracks.
395      *
396      * @return external_function_parameters
397      * @since Moodle 3.0
398      */
399     public static function insert_scorm_tracks_parameters() {
400         return new external_function_parameters(
401             array(
402                 'scoid' => new external_value(PARAM_INT, 'SCO id'),
403                 'attempt' => new external_value(PARAM_INT, 'attempt number'),
404                 'tracks' => new external_multiple_structure(
405                     new external_single_structure(
406                         array(
407                             'element' => new external_value(PARAM_RAW, 'element name'),
408                             'value' => new external_value(PARAM_RAW, 'element value')
409                         )
410                     )
411                 ),
412             )
413         );
414     }
416     /**
417      * Saves a SCORM tracking record.
418      * It will overwrite any existing tracking data for this attempt.
419      * Validation should be performed before running the function to ensure the user will not lose any existing attempt data.
420      *
421      * @param int $scoid the SCO id
422      * @param string $attempt the attempt number
423      * @param array $tracks the track records to be stored
424      * @return array warnings and the scoes data
425      * @throws moodle_exception
426      * @since Moodle 3.0
427      */
428     public static function insert_scorm_tracks($scoid, $attempt, $tracks) {
429         global $USER, $DB;
431         $params = self::validate_parameters(self::insert_scorm_tracks_parameters(),
432                                             array('scoid' => $scoid, 'attempt' => $attempt, 'tracks' => $tracks));
434         $trackids = array();
435         $warnings = array();
437         $sco = scorm_get_sco($params['scoid'], SCO_ONLY);
438         if (!$sco) {
439             throw new moodle_exception('cannotfindsco', 'scorm');
440         }
442         $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST);
443         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
445         $context = context_module::instance($cm->id);
446         self::validate_context($context);
448         // Check settings / permissions to view the SCORM.
449         require_capability('mod/scorm:savetrack', $context);
451         // Check settings / permissions to view the SCORM.
452         scorm_require_available($scorm);
454         foreach ($params['tracks'] as $track) {
455             $element = $track['element'];
456             $value = $track['value'];
457             $trackid = scorm_insert_track($USER->id, $scorm->id, $sco->id, $params['attempt'], $element, $value,
458                                             $scorm->forcecompleted);
460             if ($trackid) {
461                 $trackids[] = $trackid;
462             } else {
463                 $warnings[] = array(
464                     'item' => 'scorm',
465                     'itemid' => $scorm->id,
466                     'warningcode' => 1,
467                     'message' => 'Element: ' . $element . ' was not saved'
468                 );
469             }
470         }
472         $result = array();
473         $result['trackids'] = $trackids;
474         $result['warnings'] = $warnings;
475         return $result;
476     }
478     /**
479      * Describes the insert_scorm_tracks return value.
480      *
481      * @return external_single_structure
482      * @since Moodle 3.0
483      */
484     public static function insert_scorm_tracks_returns() {
486         return new external_single_structure(
487             array(
488                 'trackids' => new external_multiple_structure(new external_value(PARAM_INT, 'track id')),
489                 'warnings' => new external_warnings(),
490             )
491         );
492     }