MDL-50353 mod_scorm: Fix problem with ids ordering in tests
[moodle.git] / mod / scorm / classes / external.php
CommitLineData
e9bf3011
JL
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/**
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 */
26
27defined('MOODLE_INTERNAL') || die;
28
29require_once($CFG->libdir . '/externallib.php');
30require_once($CFG->dirroot . '/mod/scorm/lib.php');
22de67f4 31require_once($CFG->dirroot . '/mod/scorm/locallib.php');
e9bf3011
JL
32
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 */
42class mod_scorm_external extends external_api {
43
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 }
57
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');
69
70 $params = self::validate_parameters(self::view_scorm_parameters(),
71 array(
72 'scormid' => $scormid
73 ));
74 $warnings = array();
75
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');
79
80 $context = context_module::instance($cm->id);
81 self::validate_context($context);
82
83 // Call the scorm/lib API.
84 scorm_view($scorm, $course, $cm, $context);
85
86 $result = array();
87 $result['status'] = true;
88 $result['warnings'] = $warnings;
89 return $result;
90 }
91
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 }
22de67f4
JL
106
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 }
124
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;
136
137 $params = self::validate_parameters(self::get_scorm_attempt_count_parameters(),
138 array('scormid' => $scormid, 'userid' => $userid,
139 'ignoremissingcompletion' => $ignoremissingcompletion));
140
141 $attempts = array();
142 $warnings = array();
143
144 $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
145 $cm = get_coursemodule_from_instance('scorm', $scorm->id);
146
147 $context = context_module::instance($cm->id);
148 self::validate_context($context);
149
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']);
152
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 }
157
158 // If the SCORM is not open this function will throw exceptions.
159 scorm_require_available($scorm);
160
161 $attemptscount = scorm_get_attempt_count($params['userid'], $scorm, false, $params['ignoremissingcompletion']);
162
163 $result = array();
164 $result['attemptscount'] = $attemptscount;
165 $result['warnings'] = $warnings;
166 return $result;
167 }
168
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() {
176
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 }
184
dfe927c8
JL
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 }
199
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;
210
211 $params = self::validate_parameters(self::get_scorm_scoes_parameters(),
212 array('scormid' => $scormid, 'organization' => $organization));
213
214 $scoes = array();
215 $warnings = array();
216
217 $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
218 $cm = get_coursemodule_from_instance('scorm', $scorm->id);
219
220 $context = context_module::instance($cm->id);
221 self::validate_context($context);
222
223 // Check settings / permissions to view the SCORM.
224 scorm_require_available($scorm, true, $context);
225
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 }
230
231 $result = array();
232 $result['scoes'] = $scoes;
233 $result['warnings'] = $warnings;
234 return $result;
235 }
236
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() {
244
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 }
267
822e9df7
JL
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 }
282
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;
294
295 $params = self::validate_parameters(self::get_scorm_user_data_parameters(),
296 array('scormid' => $scormid, 'attempt' => $attempt));
297
298 $data = array();
299 $warnings = array();
300
301 $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
302 $cm = get_coursemodule_from_instance('scorm', $scorm->id);
303
304 $context = context_module::instance($cm->id);
305 self::validate_context($context);
306
307 scorm_require_available($scorm, true, $context);
308
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');
314
315 if ($scoes = scorm_get_scoes($scorm->id)) {
316 $def = new stdClass();
317 $user = new stdClass();
318
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');
324
325 $userdata = array();
326 $defaultdata = array();
327
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 }
340
341 $data[] = array(
342 'scoid' => $sco->id,
343 'userdata' => $userdata,
344 'defaultdata' => $defaultdata,
345 );
346 }
347 }
348
349 $result = array();
350 $result['data'] = $data;
351 $result['warnings'] = $warnings;
352 return $result;
353 }
354
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() {
362
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 }
6b4ceb24
JL
392
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 }
415
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;
430
431 $params = self::validate_parameters(self::insert_scorm_tracks_parameters(),
432 array('scoid' => $scoid, 'attempt' => $attempt, 'tracks' => $tracks));
433
434 $trackids = array();
435 $warnings = array();
436
437 $sco = scorm_get_sco($params['scoid'], SCO_ONLY);
438 if (!$sco) {
439 throw new moodle_exception('cannotfindsco', 'scorm');
440 }
441
442 $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST);
443 $cm = get_coursemodule_from_instance('scorm', $scorm->id);
444
445 $context = context_module::instance($cm->id);
446 self::validate_context($context);
447
448 // Check settings / permissions to view the SCORM.
449 require_capability('mod/scorm:savetrack', $context);
450
451 // Check settings / permissions to view the SCORM.
452 scorm_require_available($scorm);
453
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);
459
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 }
471
472 $result = array();
473 $result['trackids'] = $trackids;
474 $result['warnings'] = $warnings;
475 return $result;
476 }
477
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() {
485
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 }
e9bf3011 493}