MDL-56019 ws: Use itemid null when getting modules intro
[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         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
151         core_user::require_active_user($user);
153         // Extra checks so only users with permissions can view other users attempts.
154         if ($USER->id != $user->id) {
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($user->id, $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_scorm_scoes.
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         } else {
230             $scoreturnstructure = self::get_scorm_scoes_returns();
231             foreach ($scoes as $sco) {
232                 $extradata = array();
233                 foreach ($sco as $element => $value) {
234                     // Check if the element is extra data (not a basic SCO element).
235                     if (!isset($scoreturnstructure->keys['scoes']->content->keys[$element])) {
236                         $extradata[] = array(
237                             'element' => $element,
238                             'value' => $value
239                         );
240                     }
241                 }
242                 $sco->extradata = $extradata;
243             }
244         }
246         $result = array();
247         $result['scoes'] = $scoes;
248         $result['warnings'] = $warnings;
249         return $result;
250     }
252     /**
253      * Describes the get_scorm_scoes return value.
254      *
255      * @return external_single_structure
256      * @since Moodle 3.0
257      */
258     public static function get_scorm_scoes_returns() {
260         return new external_single_structure(
261             array(
262                 'scoes' => new external_multiple_structure(
263                     new external_single_structure(
264                         array(
265                             'id' => new external_value(PARAM_INT, 'sco id'),
266                             'scorm' => new external_value(PARAM_INT, 'scorm id'),
267                             'manifest' => new external_value(PARAM_NOTAGS, 'manifest id'),
268                             'organization' => new external_value(PARAM_NOTAGS, 'organization id'),
269                             'parent' => new external_value(PARAM_NOTAGS, 'parent'),
270                             'identifier' => new external_value(PARAM_NOTAGS, 'identifier'),
271                             'launch' => new external_value(PARAM_NOTAGS, 'launch file'),
272                             'scormtype' => new external_value(PARAM_ALPHA, 'scorm type (asset, sco)'),
273                             'title' => new external_value(PARAM_NOTAGS, 'sco title'),
274                             'sortorder' => new external_value(PARAM_INT, 'sort order'),
275                             'extradata' => new external_multiple_structure(
276                                 new external_single_structure(
277                                     array(
278                                         'element' => new external_value(PARAM_RAW, 'element name'),
279                                         'value' => new external_value(PARAM_RAW, 'element value')
280                                     )
281                                 ), 'Additional SCO data', VALUE_OPTIONAL
282                             )
283                         ), 'SCORM SCO data'
284                     )
285                 ),
286                 'warnings' => new external_warnings(),
287             )
288         );
289     }
291     /**
292      * Describes the parameters for get_scorm_user_data.
293      *
294      * @return external_function_parameters
295      * @since Moodle 3.0
296      */
297     public static function get_scorm_user_data_parameters() {
298         return new external_function_parameters(
299             array(
300                 'scormid' => new external_value(PARAM_INT, 'scorm instance id'),
301                 'attempt' => new external_value(PARAM_INT, 'attempt number')
302             )
303         );
304     }
306     /**
307      * Retrieves user tracking and SCO data and default SCORM values
308      *
309      * @param int $scormid the scorm id
310      * @param int $attempt the attempt number
311      * @return array warnings and the scoes data
312      * @throws  moodle_exception
313      * @since Moodle 3.0
314      */
315     public static function get_scorm_user_data($scormid, $attempt) {
316         global $CFG, $DB;
318         $params = self::validate_parameters(self::get_scorm_user_data_parameters(),
319                                             array('scormid' => $scormid, 'attempt' => $attempt));
321         $data = array();
322         $warnings = array();
324         $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
325         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
327         $context = context_module::instance($cm->id);
328         self::validate_context($context);
330         scorm_require_available($scorm, true, $context);
332         $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR));
333         if (!file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php')) {
334             $scorm->version = 'scorm_12';
335         }
336         require_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php');
338         if ($scoes = scorm_get_scoes($scorm->id)) {
339             $def = new stdClass();
340             $user = new stdClass();
342             foreach ($scoes as $sco) {
343                 $def->{$sco->id} = new stdClass();
344                 $user->{$sco->id} = new stdClass();
345                 // We force mode normal, this can be override by the client at any time.
346                 $def->{$sco->id} = get_scorm_default($user->{$sco->id}, $scorm, $sco->id, $params['attempt'], 'normal');
348                 $userdata = array();
349                 $defaultdata = array();
351                 foreach ((array) $user->{$sco->id} as $key => $val) {
352                     $userdata[] = array(
353                         'element' => $key,
354                         'value' => $val
355                     );
356                 }
357                 foreach ($def->{$sco->id} as $key => $val) {
358                     $defaultdata[] = array(
359                         'element' => $key,
360                         'value' => $val
361                     );
362                 }
364                 $data[] = array(
365                     'scoid' => $sco->id,
366                     'userdata' => $userdata,
367                     'defaultdata' => $defaultdata,
368                 );
369             }
370         }
372         $result = array();
373         $result['data'] = $data;
374         $result['warnings'] = $warnings;
375         return $result;
376     }
378     /**
379      * Describes the get_scorm_user_data return value.
380      *
381      * @return external_single_structure
382      * @since Moodle 3.0
383      */
384     public static function get_scorm_user_data_returns() {
386         return new external_single_structure(
387             array(
388                 'data' => new external_multiple_structure(
389                     new external_single_structure(
390                         array(
391                             'scoid' => new external_value(PARAM_INT, 'sco id'),
392                             'userdata' => new external_multiple_structure(
393                                             new external_single_structure(
394                                                 array(
395                                                     'element' => new external_value(PARAM_RAW, 'element name'),
396                                                     'value' => new external_value(PARAM_RAW, 'element value')
397                                                 )
398                                             )
399                                           ),
400                             'defaultdata' => new external_multiple_structure(
401                                                 new external_single_structure(
402                                                     array(
403                                                         'element' => new external_value(PARAM_RAW, 'element name'),
404                                                         'value' => new external_value(PARAM_RAW, 'element value')
405                                                     )
406                                                 )
407                                              ),
408                         ), 'SCO data'
409                     )
410                 ),
411                 'warnings' => new external_warnings(),
412             )
413         );
414     }
416     /**
417      * Describes the parameters for insert_scorm_tracks.
418      *
419      * @return external_function_parameters
420      * @since Moodle 3.0
421      */
422     public static function insert_scorm_tracks_parameters() {
423         return new external_function_parameters(
424             array(
425                 'scoid' => new external_value(PARAM_INT, 'SCO id'),
426                 'attempt' => new external_value(PARAM_INT, 'attempt number'),
427                 'tracks' => new external_multiple_structure(
428                     new external_single_structure(
429                         array(
430                             'element' => new external_value(PARAM_RAW, 'element name'),
431                             'value' => new external_value(PARAM_RAW, 'element value')
432                         )
433                     )
434                 ),
435             )
436         );
437     }
439     /**
440      * Saves a SCORM tracking record.
441      * It will overwrite any existing tracking data for this attempt.
442      * Validation should be performed before running the function to ensure the user will not lose any existing attempt data.
443      *
444      * @param int $scoid the SCO id
445      * @param string $attempt the attempt number
446      * @param array $tracks the track records to be stored
447      * @return array warnings and the scoes data
448      * @throws moodle_exception
449      * @since Moodle 3.0
450      */
451     public static function insert_scorm_tracks($scoid, $attempt, $tracks) {
452         global $USER, $DB;
454         $params = self::validate_parameters(self::insert_scorm_tracks_parameters(),
455                                             array('scoid' => $scoid, 'attempt' => $attempt, 'tracks' => $tracks));
457         $trackids = array();
458         $warnings = array();
460         $sco = scorm_get_sco($params['scoid'], SCO_ONLY);
461         if (!$sco) {
462             throw new moodle_exception('cannotfindsco', 'scorm');
463         }
465         $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST);
466         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
468         $context = context_module::instance($cm->id);
469         self::validate_context($context);
471         // Check settings / permissions to view the SCORM.
472         require_capability('mod/scorm:savetrack', $context);
474         // Check settings / permissions to view the SCORM.
475         scorm_require_available($scorm);
477         foreach ($params['tracks'] as $track) {
478             $element = $track['element'];
479             $value = $track['value'];
480             $trackid = scorm_insert_track($USER->id, $scorm->id, $sco->id, $params['attempt'], $element, $value,
481                                             $scorm->forcecompleted);
483             if ($trackid) {
484                 $trackids[] = $trackid;
485             } else {
486                 $warnings[] = array(
487                     'item' => 'scorm',
488                     'itemid' => $scorm->id,
489                     'warningcode' => 1,
490                     'message' => 'Element: ' . $element . ' was not saved'
491                 );
492             }
493         }
495         $result = array();
496         $result['trackids'] = $trackids;
497         $result['warnings'] = $warnings;
498         return $result;
499     }
501     /**
502      * Describes the insert_scorm_tracks return value.
503      *
504      * @return external_single_structure
505      * @since Moodle 3.0
506      */
507     public static function insert_scorm_tracks_returns() {
509         return new external_single_structure(
510             array(
511                 'trackids' => new external_multiple_structure(new external_value(PARAM_INT, 'track id')),
512                 'warnings' => new external_warnings(),
513             )
514         );
515     }
517     /**
518      * Describes the parameters for get_scorm_sco_tracks.
519      *
520      * @return external_function_parameters
521      * @since Moodle 3.0
522      */
523     public static function get_scorm_sco_tracks_parameters() {
524         return new external_function_parameters(
525             array(
526                 'scoid' => new external_value(PARAM_INT, 'sco id'),
527                 'userid' => new external_value(PARAM_INT, 'user id'),
528                 'attempt' => new external_value(PARAM_INT, 'attempt number (0 for last attempt)', VALUE_DEFAULT, 0)
529             )
530         );
531     }
533     /**
534      * Retrieves SCO tracking data for the given user id and attempt number
535      *
536      * @param int $scoid the sco id
537      * @param int $userid the user id
538      * @param int $attempt the attempt number
539      * @return array warnings and the scoes data
540      * @since Moodle 3.0
541      */
542     public static function get_scorm_sco_tracks($scoid, $userid, $attempt = 0) {
543         global $USER, $DB;
545         $params = self::validate_parameters(self::get_scorm_sco_tracks_parameters(),
546                                             array('scoid' => $scoid, 'userid' => $userid, 'attempt' => $attempt));
548         $tracks = array();
549         $warnings = array();
551         $sco = scorm_get_sco($params['scoid'], SCO_ONLY);
552         if (!$sco) {
553             throw new moodle_exception('cannotfindsco', 'scorm');
554         }
556         $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST);
557         $cm = get_coursemodule_from_instance('scorm', $scorm->id);
559         $context = context_module::instance($cm->id);
560         self::validate_context($context);
562         $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
563         core_user::require_active_user($user);
565         // Extra checks so only users with permissions can view other users attempts.
566         if ($USER->id != $user->id) {
567             require_capability('mod/scorm:viewreport', $context);
568         }
570         scorm_require_available($scorm, true, $context);
572         if (empty($params['attempt'])) {
573             $params['attempt'] = scorm_get_last_attempt($scorm->id, $user->id);
574         }
576         $attempted = false;
577         if ($scormtracks = scorm_get_tracks($sco->id, $params['userid'], $params['attempt'])) {
578             // Check if attempted.
579             if ($scormtracks->status != '') {
580                 $attempted = true;
581                 foreach ($scormtracks as $element => $value) {
582                     $tracks[] = array(
583                         'element' => $element,
584                         'value' => $value,
585                     );
586                 }
587             }
588         }
590         if (!$attempted) {
591             $warnings[] = array(
592                 'item' => 'attempt',
593                 'itemid' => $params['attempt'],
594                 'warningcode' => 'notattempted',
595                 'message' => get_string('notattempted', 'scorm')
596             );
597         }
599         $result = array();
600         $result['data']['attempt'] = $params['attempt'];
601         $result['data']['tracks'] = $tracks;
602         $result['warnings'] = $warnings;
603         return $result;
604     }
606     /**
607      * Describes the get_scorm_sco_tracks return value.
608      *
609      * @return external_single_structure
610      * @since Moodle 3.0
611      */
612     public static function get_scorm_sco_tracks_returns() {
614         return new external_single_structure(
615             array(
616                 'data' => new external_single_structure(
617                     array(
618                         'attempt' => new external_value(PARAM_INT, 'Attempt number'),
619                         'tracks' => new external_multiple_structure(
620                             new external_single_structure(
621                                 array(
622                                     'element' => new external_value(PARAM_RAW, 'Element name'),
623                                     'value' => new external_value(PARAM_RAW, 'Element value')
624                                 ), 'Tracks data'
625                             )
626                         ),
627                     ), 'SCO data'
628                 ),
629                 'warnings' => new external_warnings(),
630             )
631         );
632     }
634     /**
635      * Describes the parameters for get_scorms_by_courses.
636      *
637      * @return external_function_parameters
638      * @since Moodle 3.0
639      */
640     public static function get_scorms_by_courses_parameters() {
641         return new external_function_parameters (
642             array(
643                 'courseids' => new external_multiple_structure(
644                     new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array()
645                 ),
646             )
647         );
648     }
650     /**
651      * Returns a list of scorms in a provided list of courses,
652      * if no list is provided all scorms that the user can view will be returned.
653      *
654      * @param array $courseids the course ids
655      * @return array the scorm details
656      * @since Moodle 3.0
657      */
658     public static function get_scorms_by_courses($courseids = array()) {
659         global $CFG;
661         $returnedscorms = array();
662         $warnings = array();
664         $params = self::validate_parameters(self::get_scorms_by_courses_parameters(), array('courseids' => $courseids));
666         $courses = array();
667         if (empty($params['courseids'])) {
668             $courses = enrol_get_my_courses();
669             $params['courseids'] = array_keys($courses);
670         }
672         // Ensure there are courseids to loop through.
673         if (!empty($params['courseids'])) {
675             list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses);
677             // Get the scorms in this course, this function checks users visibility permissions.
678             // We can avoid then additional validate_context calls.
679             $scorms = get_all_instances_in_courses("scorm", $courses);
681             $fs = get_file_storage();
682             foreach ($scorms as $scorm) {
684                 $context = context_module::instance($scorm->coursemodule);
686                 // Entry to return.
687                 $module = array();
689                 // First, we return information that any user can see in (or can deduce from) the web interface.
690                 $module['id'] = $scorm->id;
691                 $module['coursemodule'] = $scorm->coursemodule;
692                 $module['course'] = $scorm->course;
693                 $module['name']  = external_format_string($scorm->name, $context->id);
694                 list($module['intro'], $module['introformat']) =
695                     external_format_text($scorm->intro, $scorm->introformat, $context->id, 'mod_scorm', 'intro', null);
696                 $module['introfiles'] = external_util::get_area_files($context->id, 'mod_scorm', 'intro', false, false);
698                 // Check if the SCORM open and return warnings if so.
699                 list($open, $openwarnings) = scorm_get_availability_status($scorm, true, $context);
701                 if (!$open) {
702                     foreach ($openwarnings as $warningkey => $warningdata) {
703                         $warnings[] = array(
704                             'item' => 'scorm',
705                             'itemid' => $scorm->id,
706                             'warningcode' => $warningkey,
707                             'message' => get_string($warningkey, 'scorm', $warningdata)
708                         );
709                     }
710                 } else {
711                     $module['packagesize'] = 0;
712                     // SCORM size.
713                     if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
714                         if ($packagefile = $fs->get_file($context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)) {
715                             $module['packagesize'] = $packagefile->get_filesize();
716                             // Download URL.
717                             $module['packageurl'] = moodle_url::make_webservice_pluginfile_url(
718                                                     $context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)->out(false);
719                         }
720                     }
722                     $module['protectpackagedownloads'] = get_config('scorm', 'protectpackagedownloads');
724                     $viewablefields = array('version', 'maxgrade', 'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted',
725                                             'forcenewattempt', 'lastattemptlock', 'displayattemptstatus', 'displaycoursestructure',
726                                             'sha1hash', 'md5hash', 'revision', 'launch', 'skipview', 'hidebrowse', 'hidetoc', 'nav',
727                                             'navpositionleft', 'navpositiontop', 'auto', 'popup', 'width', 'height', 'timeopen',
728                                             'timeclose', 'displayactivityname', 'scormtype', 'reference');
730                     // Check additional permissions for returning optional private settings.
731                     if (has_capability('moodle/course:manageactivities', $context)) {
733                         $additionalfields = array('updatefreq', 'options', 'completionstatusrequired', 'completionscorerequired',
734                                                   'completionstatusallscos', 'autocommit', 'timemodified', 'section', 'visible',
735                                                   'groupmode', 'groupingid');
736                         $viewablefields = array_merge($viewablefields, $additionalfields);
738                     }
740                     foreach ($viewablefields as $field) {
741                         $module[$field] = $scorm->{$field};
742                     }
743                 }
745                 $returnedscorms[] = $module;
746             }
747         }
749         $result = array();
750         $result['scorms'] = $returnedscorms;
751         $result['warnings'] = $warnings;
752         return $result;
753     }
755     /**
756      * Describes the get_scorms_by_courses return value.
757      *
758      * @return external_single_structure
759      * @since Moodle 3.0
760      */
761     public static function get_scorms_by_courses_returns() {
763         return new external_single_structure(
764             array(
765                 'scorms' => new external_multiple_structure(
766                     new external_single_structure(
767                         array(
768                             'id' => new external_value(PARAM_INT, 'SCORM id'),
769                             'coursemodule' => new external_value(PARAM_INT, 'Course module id'),
770                             'course' => new external_value(PARAM_INT, 'Course id'),
771                             'name' => new external_value(PARAM_RAW, 'SCORM name'),
772                             'intro' => new external_value(PARAM_RAW, 'The SCORM intro'),
773                             'introformat' => new external_format_value('intro'),
774                             'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL),
775                             'packagesize' => new external_value(PARAM_INT, 'SCORM zip package size', VALUE_OPTIONAL),
776                             'packageurl' => new external_value(PARAM_URL, 'SCORM zip package URL', VALUE_OPTIONAL),
777                             'version' => new external_value(PARAM_NOTAGS, 'SCORM version (SCORM_12, SCORM_13, SCORM_AICC)',
778                                                             VALUE_OPTIONAL),
779                             'maxgrade' => new external_value(PARAM_INT, 'Max grade', VALUE_OPTIONAL),
780                             'grademethod' => new external_value(PARAM_INT, 'Grade method', VALUE_OPTIONAL),
781                             'whatgrade' => new external_value(PARAM_INT, 'What grade', VALUE_OPTIONAL),
782                             'maxattempt' => new external_value(PARAM_INT, 'Maximum number of attemtps', VALUE_OPTIONAL),
783                             'forcecompleted' => new external_value(PARAM_BOOL, 'Status current attempt is forced to "completed"',
784                                                                     VALUE_OPTIONAL),
785                             'forcenewattempt' => new external_value(PARAM_BOOL, 'Hides the "Start new attempt" checkbox',
786                                                                     VALUE_OPTIONAL),
787                             'lastattemptlock' => new external_value(PARAM_BOOL, 'Prevents to launch new attempts once finished',
788                                                                     VALUE_OPTIONAL),
789                             'displayattemptstatus' => new external_value(PARAM_INT, 'How to display attempt status',
790                                                                             VALUE_OPTIONAL),
791                             'displaycoursestructure' => new external_value(PARAM_BOOL, 'Display contents structure',
792                                                                             VALUE_OPTIONAL),
793                             'sha1hash' => new external_value(PARAM_NOTAGS, 'Package content or ext path hash', VALUE_OPTIONAL),
794                             'md5hash' => new external_value(PARAM_NOTAGS, 'MD5 Hash of package file', VALUE_OPTIONAL),
795                             'revision' => new external_value(PARAM_INT, 'Revison number', VALUE_OPTIONAL),
796                             'launch' => new external_value(PARAM_INT, 'First content to launch', VALUE_OPTIONAL),
797                             'skipview' => new external_value(PARAM_INT, 'How to skip the content structure page', VALUE_OPTIONAL),
798                             'hidebrowse' => new external_value(PARAM_BOOL, 'Disable preview mode?', VALUE_OPTIONAL),
799                             'hidetoc' => new external_value(PARAM_INT, 'How to display the SCORM structure in player',
800                                                             VALUE_OPTIONAL),
801                             'nav' => new external_value(PARAM_INT, 'Show navigation buttons', VALUE_OPTIONAL),
802                             'navpositionleft' => new external_value(PARAM_INT, 'Navigation position left', VALUE_OPTIONAL),
803                             'navpositiontop' => new external_value(PARAM_INT, 'Navigation position top', VALUE_OPTIONAL),
804                             'auto' => new external_value(PARAM_BOOL, 'Auto continue?', VALUE_OPTIONAL),
805                             'popup' => new external_value(PARAM_INT, 'Display in current or new window', VALUE_OPTIONAL),
806                             'width' => new external_value(PARAM_INT, 'Frame width', VALUE_OPTIONAL),
807                             'height' => new external_value(PARAM_INT, 'Frame height', VALUE_OPTIONAL),
808                             'timeopen' => new external_value(PARAM_INT, 'Available from', VALUE_OPTIONAL),
809                             'timeclose' => new external_value(PARAM_INT, 'Available to', VALUE_OPTIONAL),
810                             'displayactivityname' => new external_value(PARAM_BOOL, 'Display the activity name above the player?',
811                                                                         VALUE_OPTIONAL),
812                             'scormtype' => new external_value(PARAM_ALPHA, 'SCORM type', VALUE_OPTIONAL),
813                             'reference' => new external_value(PARAM_NOTAGS, 'Reference to the package', VALUE_OPTIONAL),
814                             'protectpackagedownloads' => new external_value(PARAM_BOOL, 'Protect package downloads?',
815                                                                             VALUE_OPTIONAL),
816                             'updatefreq' => new external_value(PARAM_INT, 'Auto-update frequency for remote packages',
817                                                                 VALUE_OPTIONAL),
818                             'options' => new external_value(PARAM_RAW, 'Additional options', VALUE_OPTIONAL),
819                             'completionstatusrequired' => new external_value(PARAM_INT, 'Status passed/completed required?',
820                                                                                 VALUE_OPTIONAL),
821                             'completionscorerequired' => new external_value(PARAM_INT, 'Minimum score required', VALUE_OPTIONAL),
822                             'completionstatusallscos' => new external_value(PARAM_INT, 'Require all scos to return completion status', VALUE_OPTIONAL),
823                             'autocommit' => new external_value(PARAM_BOOL, 'Save track data automatically?', VALUE_OPTIONAL),
824                             'timemodified' => new external_value(PARAM_INT, 'Time of last modification', VALUE_OPTIONAL),
825                             'section' => new external_value(PARAM_INT, 'Course section id', VALUE_OPTIONAL),
826                             'visible' => new external_value(PARAM_BOOL, 'Visible', VALUE_OPTIONAL),
827                             'groupmode' => new external_value(PARAM_INT, 'Group mode', VALUE_OPTIONAL),
828                             'groupingid' => new external_value(PARAM_INT, 'Group id', VALUE_OPTIONAL),
829                         ), 'SCORM'
830                     )
831                 ),
832                 'warnings' => new external_warnings(),
833             )
834         );
835     }
837     /**
838      * Returns description of method parameters
839      *
840      * @return external_function_parameters
841      * @since Moodle 3.1
842      */
843     public static function launch_sco_parameters() {
844         return new external_function_parameters(
845             array(
846                 'scormid' => new external_value(PARAM_INT, 'SCORM instance id'),
847                 'scoid' => new external_value(PARAM_INT, 'SCO id (empty for launching the first SCO)', VALUE_DEFAULT, 0)
848             )
849         );
850     }
852     /**
853      * Trigger the course module viewed event.
854      *
855      * @param int $scormid the SCORM instance id
856      * @param int $scoid the SCO id
857      * @return array of warnings and status result
858      * @since Moodle 3.1
859      * @throws moodle_exception
860      */
861     public static function launch_sco($scormid, $scoid = 0) {
862         global $DB;
864         $params = self::validate_parameters(self::launch_sco_parameters(),
865                                             array(
866                                                 'scormid' => $scormid,
867                                                 'scoid' => $scoid
868                                             ));
869         $warnings = array();
871         // Request and permission validation.
872         $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
873         list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm');
875         $context = context_module::instance($cm->id);
876         self::validate_context($context);
878         // If the SCORM is not open this function will throw exceptions.
879         scorm_require_available($scorm);
881         if (!empty($params['scoid']) and !($sco = scorm_get_sco($params['scoid'], SCO_ONLY))) {
882             throw new moodle_exception('cannotfindsco', 'scorm');
883         }
885         list($sco, $scolaunchurl) = scorm_get_sco_and_launch_url($scorm, $params['scoid'], $context);
886         // Trigger the SCO launched event.
887         scorm_launch_sco($scorm, $sco, $cm, $context, $scolaunchurl);
889         $result = array();
890         $result['status'] = true;
891         $result['warnings'] = $warnings;
892         return $result;
893     }
895     /**
896      * Returns description of method result value
897      *
898      * @return external_description
899      * @since Moodle 3.1
900      */
901     public static function launch_sco_returns() {
902         return new external_single_structure(
903             array(
904                 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
905                 'warnings' => new external_warnings()
906             )
907         );
908     }