MDL-67814 core_h5p: moved common methods from player to helper class
[moodle.git] / h5p / classes / player.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  * H5P player class.
19  *
20  * @package    core_h5p
21  * @copyright  2019 Sara Arjona <sara@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core_h5p;
27 defined('MOODLE_INTERNAL') || die();
29 use core_h5p\local\library\autoloader;
30 use core_xapi\local\statement\item_activity;
32 /**
33  * H5P player class, for displaying any local H5P content.
34  *
35  * @package    core_h5p
36  * @copyright  2019 Sara Arjona <sara@moodle.com>
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class player {
41     /**
42      * @var string The local H5P URL containing the .h5p file to display.
43      */
44     private $url;
46     /**
47      * @var core The H5PCore object.
48      */
49     private $core;
51     /**
52      * @var int H5P DB id.
53      */
54     private $h5pid;
56     /**
57      * @var array JavaScript requirements for this H5P.
58      */
59     private $jsrequires = [];
61     /**
62      * @var array CSS requirements for this H5P.
63      */
64     private $cssrequires = [];
66     /**
67      * @var array H5P content to display.
68      */
69     private $content;
71     /**
72      * @var string optional component name to send xAPI statements.
73      */
74     private $component;
76     /**
77      * @var string Type of embed object, div or iframe.
78      */
79     private $embedtype;
81     /**
82      * @var context The context object where the .h5p belongs.
83      */
84     private $context;
86     /**
87      * @var factory The \core_h5p\factory object.
88      */
89     private $factory;
91     /**
92      * @var stdClass The error, exception and info messages, raised while preparing and running the player.
93      */
94     private $messages;
96     /**
97      * @var bool Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions.
98      */
99     private $preventredirect;
101     /**
102      * Inits the H5P player for rendering the content.
103      *
104      * @param string $url Local URL of the H5P file to display.
105      * @param stdClass $config Configuration for H5P buttons.
106      * @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
107      * @param string $component optional moodle component to sent xAPI tracking
108      */
109     public function __construct(string $url, \stdClass $config, bool $preventredirect = true, string $component = '') {
110         if (empty($url)) {
111             throw new \moodle_exception('h5pinvalidurl', 'core_h5p');
112         }
113         $this->url = new \moodle_url($url);
114         $this->preventredirect = $preventredirect;
116         $this->factory = new \core_h5p\factory();
118         $this->messages = new \stdClass();
120         $this->component = $component;
122         // Create \core_h5p\core instance.
123         $this->core = $this->factory->get_core();
125         // Get the H5P identifier linked to this URL.
126         if ($this->h5pid = $this->get_h5p_id($url, $config)) {
127             // Load the content of the H5P content associated to this $url.
128             $this->content = $this->core->loadContent($this->h5pid);
130             // Get the embedtype to use for displaying the H5P content.
131             $this->embedtype = core::determineEmbedType($this->content['embedType'], $this->content['library']['embedTypes']);
132         }
133     }
135     /**
136      * Get the encoded URL for embeding this H5P content.
137      *
138      * @param string $url Local URL of the H5P file to display.
139      * @param stdClass $config Configuration for H5P buttons.
140      * @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
141      * @param string $component optional moodle component to sent xAPI tracking
142      *
143      * @return string The embedable code to display a H5P file.
144      */
145     public static function display(string $url, \stdClass $config, bool $preventredirect = true,
146             string $component = ''): string {
147         global $OUTPUT;
148         $params = [
149                 'url' => $url,
150                 'preventredirect' => $preventredirect,
151                 'component' => $component,
152             ];
154         $optparams = ['frame', 'export', 'embed', 'copyright'];
155         foreach ($optparams as $optparam) {
156             if (!empty($config->$optparam)) {
157                 $params[$optparam] = $config->$optparam;
158             }
159         }
160         $fileurl = new \moodle_url('/h5p/embed.php', $params);
162         $template = new \stdClass();
163         $template->embedurl = $fileurl->out(false);
165         $result = $OUTPUT->render_from_template('core_h5p/h5pembed', $template);
166         $result .= self::get_resize_code();
167         return $result;
168     }
170     /**
171      * Get the error messages stored in our H5P framework.
172      *
173      * @return stdClass with framework error messages.
174      */
175     public function get_messages(): \stdClass {
176         // Check if there are some errors and store them in $messages.
177         if (empty($this->messages->error)) {
178             $this->messages->error = $this->core->h5pF->getMessages('error') ?: false;
179         } else {
180             $this->messages->error = array_merge($this->messages->error, $this->core->h5pF->getMessages('error'));
181         }
183         if (empty($this->messages->info)) {
184             $this->messages->info = $this->core->h5pF->getMessages('info') ?: false;
185         } else {
186             $this->messages->info = array_merge($this->messages->info, $this->core->h5pF->getMessages('info'));
187         }
189         return $this->messages;
190     }
192     /**
193      * Create the H5PIntegration variable that will be included in the page. This variable is used as the
194      * main H5P config variable.
195      */
196     public function add_assets_to_page() {
197         global $PAGE;
199         $cid = $this->get_cid();
200         $systemcontext = \context_system::instance();
202         $disable = array_key_exists('disable', $this->content) ? $this->content['disable'] : core::DISABLE_NONE;
203         $displayoptions = $this->core->getDisplayOptionsForView($disable, $this->h5pid);
205         $contenturl = \moodle_url::make_pluginfile_url($systemcontext->id, \core_h5p\file_storage::COMPONENT,
206             \core_h5p\file_storage::CONTENT_FILEAREA, $this->h5pid, null, null);
207         $exporturl = $this->get_export_settings($displayoptions[ core::DISPLAY_OPTION_DOWNLOAD ]);
208         $xapiobject = item_activity::create_from_id($this->context->id);
209         $contentsettings = [
210             'library'         => core::libraryToString($this->content['library']),
211             'fullScreen'      => $this->content['library']['fullscreen'],
212             'exportUrl'       => ($exporturl instanceof \moodle_url) ? $exporturl->out(false) : '',
213             'embedCode'       => $this->get_embed_code($this->url->out(),
214                 $displayoptions[ core::DISPLAY_OPTION_EMBED ]),
215             'resizeCode'      => self::get_resize_code(),
216             'title'           => $this->content['slug'],
217             'displayOptions'  => $displayoptions,
218             'url'             => $xapiobject->get_data()->id,
219             'contentUrl'      => $contenturl->out(),
220             'metadata'        => $this->content['metadata'],
221             'contentUserData' => [0 => ['state' => '{}']]
222         ];
223         // Get the core H5P assets, needed by the H5P classes to render the H5P content.
224         $settings = $this->get_assets();
225         $settings['contents'][$cid] = array_merge($settings['contents'][$cid], $contentsettings);
227         // Print JavaScript settings to page.
228         $PAGE->requires->data_for_js('H5PIntegration', $settings, true);
229     }
231     /**
232      * Outputs H5P wrapper HTML.
233      *
234      * @return string The HTML code to display this H5P content.
235      */
236     public function output(): string {
237         global $OUTPUT, $USER;
239         $template = new \stdClass();
240         $template->h5pid = $this->h5pid;
241         if ($this->embedtype === 'div') {
242             $h5phtml = $OUTPUT->render_from_template('core_h5p/h5pdiv', $template);
243         } else {
244             $h5phtml = $OUTPUT->render_from_template('core_h5p/h5piframe', $template);
245         }
247         // Trigger capability_assigned event.
248         \core_h5p\event\h5p_viewed::create([
249             'objectid' => $this->h5pid,
250             'userid' => $USER->id,
251             'context' => $this->context,
252             'other' => [
253                 'url' => $this->url->out(),
254                 'time' => time()
255             ]
256         ])->trigger();
258         return $h5phtml;
259     }
261     /**
262      * Get the title of the H5P content to display.
263      *
264      * @return string the title
265      */
266     public function get_title(): string {
267         return $this->content['title'];
268     }
270     /**
271      * Get the context where the .h5p file belongs.
272      *
273      * @return context The context.
274      */
275     public function get_context(): \context {
276         return $this->context;
277     }
279     /**
280      * Get the H5P DB instance id for a H5P pluginfile URL. The H5P file will be saved if it doesn't exist previously or
281      * if its content has changed. Besides, the displayoptions in the $config will be also updated when they have changed and
282      * the user has the right permissions.
283      *
284      * @param string $url H5P pluginfile URL.
285      * @param stdClass $config Configuration for H5P buttons.
286      *
287      * @return int|false H5P DB identifier.
288      */
289     private function get_h5p_id(string $url, \stdClass $config) {
290         global $DB, $USER;
292         $fs = get_file_storage();
294         // Deconstruct the URL and get the pathname associated.
295         $pathnamehash = $this->get_pluginfile_hash($url);
296         if (!$pathnamehash) {
297             $this->core->h5pF->setErrorMessage(get_string('h5pfilenotfound', 'core_h5p'));
298             return false;
299         }
301         // Get the file.
302         $file = $fs->get_file_by_hash($pathnamehash);
303         if (!$file) {
304             $this->core->h5pF->setErrorMessage(get_string('h5pfilenotfound', 'core_h5p'));
305             return false;
306         }
308         $h5p = $DB->get_record('h5p', ['pathnamehash' => $pathnamehash]);
309         $contenthash = $file->get_contenthash();
310         if ($h5p && $h5p->contenthash != $contenthash) {
311             // The content exists and it is different from the one deployed previously. The existing one should be removed before
312             // deploying the new version.
313             $this->delete_h5p($h5p);
314             $h5p = false;
315         }
317         if ($h5p) {
318             // The H5P content has been deployed previously.
319             $displayoptions = $this->get_display_options($config);
320             // Check if the user can set the displayoptions.
321             if ($displayoptions != $h5p->displayoptions && has_capability('moodle/h5p:setdisplayoptions', $this->context)) {
322                 // If the displayoptions has changed and the user has permission to modify it, update this information in the DB.
323                 $this->core->h5pF->updateContentFields($h5p->id, ['displayoptions' => $displayoptions]);
324             }
325             return $h5p->id;
326         } else {
327             // The H5P content hasn't been deployed previously.
329             // Check if the user uploading the H5P content is "trustable". If the file hasn't been uploaded by a user with this
330             // capability, the content won't be deployed and an error message will be displayed.
331             if (!helper::can_deploy_package($file)) {
332                 $this->core->h5pF->setErrorMessage(get_string('nopermissiontodeploy', 'core_h5p'));
333                 return false;
334             }
336             // The H5P content can be only deployed if the author of the .h5p file can update libraries or if all the
337             // content-type libraries exist, to avoid users without the h5p:updatelibraries capability upload malicious content.
338             $onlyupdatelibs = !helper::can_update_library($file);
340             // Validate and store the H5P content before displaying it.
341             $h5pid = helper::save_h5p($this->factory, $file, $config, $onlyupdatelibs, false);
342             if (!$h5pid && $file->get_userid() != $USER->id && has_capability('moodle/h5p:updatelibraries', $this->context)) {
343                 // The user has permission to update libraries but the package has been uploaded by a different
344                 // user without this permission. Check if there is some missing required library error.
345                 $missingliberror = false;
346                 $messages = $this->get_messages();
347                 if (!empty($messages->error)) {
348                     foreach ($messages->error as $error) {
349                         if ($error->code == 'missing-required-library') {
350                             $missingliberror = true;
351                             break;
352                         }
353                     }
354                 }
355                 if ($missingliberror) {
356                     // The message about the permissions to upload libraries should be removed.
357                     $infomsg = "Note that the libraries may exist in the file you uploaded, but you're not allowed to upload " .
358                         "new libraries. Contact the site administrator about this.";
359                     if (($key = array_search($infomsg, $messages->info)) !== false) {
360                         unset($messages->info[$key]);
361                     }
363                     // No library will be installed and an error will be displayed, because this content is not trustable.
364                     $this->core->h5pF->setInfoMessage(get_string('notrustablefile', 'core_h5p'));
365                 }
366                 return false;
368             }
369             return $h5pid;
370         }
371     }
373     /**
374      * Get the pathnamehash from an H5P internal URL.
375      *
376      * @param  string $url H5P pluginfile URL poiting to an H5P file.
377      *
378      * @return string|false pathnamehash for the file in the internal URL.
379      */
380     private function get_pluginfile_hash(string $url) {
381         global $USER, $CFG;
383         // Decode the URL before start processing it.
384         $url = new \moodle_url(urldecode($url));
386         // Remove params from the URL (such as the 'forcedownload=1'), to avoid errors.
387         $url->remove_params(array_keys($url->params()));
388         $path = $url->out_as_local_url();
390         // We only need the slasharguments.
391         $path = substr($path, strpos($path, '.php/') + 5);
392         $parts = explode('/', $path);
393         $filename = array_pop($parts);
395         // If the request is made by tokenpluginfile.php we need to avoid userprivateaccesskey.
396         if (strpos($this->url, '/tokenpluginfile.php')) {
397             array_shift($parts);
398         }
399         // Get the contextid, component and filearea.
400         $contextid = array_shift($parts);
401         $component = array_shift($parts);
402         $filearea = array_shift($parts);
404         // Ignore draft files, because they are considered temporary files, so shouldn't be displayed.
405         if ($filearea == 'draft') {
406             return false;
407         }
409         // Get the context.
410         try {
411             list($this->context, $course, $cm) = get_context_info_array($contextid);
412         } catch (\moodle_exception $e) {
413             throw new \moodle_exception('invalidcontextid', 'core_h5p');
414         }
416         // For CONTEXT_USER, such as the private files, raise an exception if the owner of the file is not the current user.
417         if ($this->context->contextlevel == CONTEXT_USER && $USER->id !== $this->context->instanceid) {
418             throw new \moodle_exception('h5pprivatefile', 'core_h5p');
419         }
421         // For CONTEXT_COURSECAT No login necessary - unless login forced everywhere.
422         if ($this->context->contextlevel == CONTEXT_COURSECAT) {
423             if ($CFG->forcelogin) {
424                 require_login(null, true, null, false, true);
425             }
426         }
428         // For CONTEXT_BLOCK.
429         if ($this->context->contextlevel == CONTEXT_BLOCK) {
430             if ($this->context->get_course_context(false)) {
431                 // If block is in course context, then check if user has capability to access course.
432                 require_course_login($course, true, null, false, true);
433             } else if ($CFG->forcelogin) {
434                 // No login necessary - unless login forced everywhere.
435                 require_login(null, true, null, false, true);
436             } else {
437                 // Get parent context and see if user have proper permission.
438                 $parentcontext = $this->context->get_parent_context();
439                 if ($parentcontext->contextlevel === CONTEXT_COURSECAT) {
440                     // Check if category is visible and user can view this category.
441                     if (!core_course_category::get($parentcontext->instanceid, IGNORE_MISSING)) {
442                         send_file_not_found();
443                     }
444                 } else if ($parentcontext->contextlevel === CONTEXT_USER && $parentcontext->instanceid != $USER->id) {
445                     // The block is in the context of a user, it is only visible to the user who it belongs to.
446                     send_file_not_found();
447                 }
448                 if ($filearea !== 'content') {
449                     send_file_not_found();
450                 }
451             }
452         }
454         // For CONTEXT_MODULE and CONTEXT_COURSE check if the user is enrolled in the course.
455         // And for CONTEXT_MODULE has permissions view this .h5p file.
456         if ($this->context->contextlevel == CONTEXT_MODULE ||
457                 $this->context->contextlevel == CONTEXT_COURSE) {
458             // Require login to the course first (without login to the module).
459             require_course_login($course, true, null, !$this->preventredirect, $this->preventredirect);
461             // Now check if module is available OR it is restricted but the intro is shown on the course page.
462             if ($this->context->contextlevel == CONTEXT_MODULE) {
463                 $cminfo = \cm_info::create($cm);
464                 if (!$cminfo->uservisible) {
465                     if (!$cm->showdescription || !$cminfo->is_visible_on_course_page()) {
466                         // Module intro is not visible on the course page and module is not available, show access error.
467                         require_course_login($course, true, $cminfo, !$this->preventredirect, $this->preventredirect);
468                     }
469                 }
470             }
471         }
473         // Some components, such as mod_page or mod_resource, add the revision to the URL to prevent caching problems.
474         // So the URL contains this revision number as itemid but a 0 is always stored in the files table.
475         // In order to get the proper hash, a callback should be done (looking for those exceptions).
476         $pathdata = null;
477         if ($this->context->contextlevel == CONTEXT_MODULE || $this->context->contextlevel == CONTEXT_BLOCK) {
478             $pathdata = component_callback($component, 'get_path_from_pluginfile', [$filearea, $parts], null);
479         }
480         if (null === $pathdata) {
481             // Look for the components and fileareas which have empty itemid defined in xxx_pluginfile.
482             $hasnullitemid = false;
483             $hasnullitemid = $hasnullitemid || ($component === 'user' && ($filearea === 'private' || $filearea === 'profile'));
484             $hasnullitemid = $hasnullitemid || (substr($component, 0, 4) === 'mod_' && $filearea === 'intro');
485             $hasnullitemid = $hasnullitemid || ($component === 'course' &&
486                     ($filearea === 'summary' || $filearea === 'overviewfiles'));
487             $hasnullitemid = $hasnullitemid || ($component === 'coursecat' && $filearea === 'description');
488             $hasnullitemid = $hasnullitemid || ($component === 'backup' &&
489                     ($filearea === 'course' || $filearea === 'activity' || $filearea === 'automated'));
490             if ($hasnullitemid) {
491                 $itemid = 0;
492             } else {
493                 $itemid = array_shift($parts);
494             }
496             if (empty($parts)) {
497                 $filepath = '/';
498             } else {
499                 $filepath = '/' . implode('/', $parts) . '/';
500             }
501         } else {
502             // The itemid and filepath have been returned by the component callback.
503             [
504                 'itemid' => $itemid,
505                 'filepath' => $filepath,
506             ] = $pathdata;
507         }
509         $fs = get_file_storage();
510         return $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $filepath, $filename);
511     }
513     /**
514      * Get the representation of display options as int.
515      * @param stdClass $config Button options config.
516      *
517      * @return int The representation of display options as int.
518      */
519     private function get_display_options(\stdClass $config): int {
520         $export = isset($config->export) ? $config->export : 0;
521         $embed = isset($config->embed) ? $config->embed : 0;
522         $copyright = isset($config->copyright) ? $config->copyright : 0;
523         $frame = ($export || $embed || $copyright);
524         if (!$frame) {
525             $frame = isset($config->frame) ? $config->frame : 0;
526         }
528         $disableoptions = [
529             core::DISPLAY_OPTION_FRAME     => $frame,
530             core::DISPLAY_OPTION_DOWNLOAD  => $export,
531             core::DISPLAY_OPTION_EMBED     => $embed,
532             core::DISPLAY_OPTION_COPYRIGHT => $copyright,
533         ];
535         return $this->core->getStorableDisplayOptions($disableoptions, 0);
536     }
538     /**
539      * Delete an H5P package.
540      *
541      * @param stdClass $content The H5P package to delete.
542      */
543     private function delete_h5p(\stdClass $content) {
544         $h5pstorage = $this->factory->get_storage();
545         // Add an empty slug to the content if it's not defined, because the H5P library requires this field exists.
546         // It's not used when deleting a package, so the real slug value is not required at this point.
547         $content->slug = $content->slug ?? '';
548         $h5pstorage->deletePackage( (array) $content);
549     }
551     /**
552      * Export path for settings
553      *
554      * @param bool $downloadenabled Whether the option to export the H5P content is enabled.
555      *
556      * @return \moodle_url|null The URL of the exported file.
557      */
558     private function get_export_settings(bool $downloadenabled): ?\moodle_url {
560         if (!$downloadenabled) {
561             return null;
562         }
564         $systemcontext = \context_system::instance();
565         $slug = $this->content['slug'] ? $this->content['slug'] . '-' : '';
566         // We have to build the right URL.
567         // Depending the request was made through webservice/pluginfile.php or pluginfile.php.
568         if (strpos($this->url, '/webservice/pluginfile.php')) {
569             $url  = \moodle_url::make_webservice_pluginfile_url(
570                 $systemcontext->id,
571                 \core_h5p\file_storage::COMPONENT,
572                 \core_h5p\file_storage::EXPORT_FILEAREA,
573                 '',
574                 '',
575                 "{$slug}{$this->content['id']}.h5p"
576             );
577         } else {
578             // If the request is made by tokenpluginfile.php we need to indicates to generate a token for current user.
579             $includetoken = false;
580             if (strpos($this->url, '/tokenpluginfile.php')) {
581                 $includetoken = true;
582             }
583             $url  = \moodle_url::make_pluginfile_url(
584                 $systemcontext->id,
585                 \core_h5p\file_storage::COMPONENT,
586                 \core_h5p\file_storage::EXPORT_FILEAREA,
587                 '',
588                 '',
589                 "{$slug}{$this->content['id']}.h5p",
590                 false,
591                 $includetoken
592             );
593         }
595         return $url;
596     }
598     /**
599      * Get the identifier for the H5P content, to be used in the arrays as index.
600      *
601      * @return string The identifier.
602      */
603     private function get_cid(): string {
604         return 'cid-' . $this->h5pid;
605     }
607     /**
608      * Get the core H5P assets, including all core H5P JavaScript and CSS.
609      *
610      * @return Array core H5P assets.
611      */
612     private function get_assets(): array {
613         // Get core assets.
614         $settings = helper::get_core_assets();
615         // Added here because in the helper we don't have the h5p content id.
616         $settings['moodleLibraryPaths'] = $this->core->get_dependency_roots($this->h5pid);
618         $cid = $this->get_cid();
619         // The filterParameters function should be called before getting the dependencyfiles because it rebuild content
620         // dependency cache and export file.
621         $settings['contents'][$cid]['jsonContent'] = $this->core->filterParameters($this->content);
623         $files = $this->get_dependency_files();
624         if ($this->embedtype === 'div') {
625             $systemcontext = \context_system::instance();
626             $h5ppath = "/pluginfile.php/{$systemcontext->id}/core_h5p";
628             // Schedule JavaScripts for loading through Moodle.
629             foreach ($files['scripts'] as $script) {
630                 $url = $script->path . $script->version;
632                 // Add URL prefix if not external.
633                 $isexternal = strpos($script->path, '://');
634                 if ($isexternal === false) {
635                     $url = $h5ppath . $url;
636                 }
637                 $settings['loadedJs'][] = $url;
638                 $this->jsrequires[] = new \moodle_url($isexternal ? $url : $CFG->wwwroot . $url);
639             }
641             // Schedule stylesheets for loading through Moodle.
642             foreach ($files['styles'] as $style) {
643                 $url = $style->path . $style->version;
645                 // Add URL prefix if not external.
646                 $isexternal = strpos($style->path, '://');
647                 if ($isexternal === false) {
648                     $url = $h5ppath . $url;
649                 }
650                 $settings['loadedCss'][] = $url;
651                 $this->cssrequires[] = new \moodle_url($isexternal ? $url : $CFG->wwwroot . $url);
652             }
654         } else {
655             // JavaScripts and stylesheets will be loaded through h5p.js.
656             $settings['contents'][$cid]['scripts'] = $this->core->getAssetsUrls($files['scripts']);
657             $settings['contents'][$cid]['styles']  = $this->core->getAssetsUrls($files['styles']);
658         }
659         return $settings;
660     }
662     /**
663      * Finds library dependencies of view
664      *
665      * @return array Files that the view has dependencies to
666      */
667     private function get_dependency_files(): array {
668         $preloadeddeps = $this->core->loadContentDependencies($this->h5pid, 'preloaded');
669         $files = $this->core->getDependenciesFiles($preloadeddeps);
671         return $files;
672     }
674     /**
675      * Resizing script for settings
676      *
677      * @return string The HTML code with the resize script.
678      */
679     private static function get_resize_code(): string {
680         global $OUTPUT;
682         $template = new \stdClass();
683         $template->resizeurl = autoloader::get_h5p_core_library_url('js/h5p-resizer.js');
685         return $OUTPUT->render_from_template('core_h5p/h5presize', $template);
686     }
688     /**
689      * Embed code for settings
690      *
691      * @param string $url The URL of the .h5p file.
692      * @param bool $embedenabled Whether the option to embed the H5P content is enabled.
693      *
694      * @return string The HTML code to reuse this H5P content in a different place.
695      */
696     private function get_embed_code(string $url, bool $embedenabled): string {
697         global $OUTPUT;
699         if ( ! $embedenabled) {
700             return '';
701         }
703         $template = new \stdClass();
704         $template->embedurl = self::get_embed_url($url)->out();
706         return $OUTPUT->render_from_template('core_h5p/h5pembed', $template);
707     }
709     /**
710      * Get the encoded URL for embeding this H5P content.
711      * @param  string $url The URL of the .h5p file.
712      *
713      * @return \moodle_url The embed URL.
714      */
715     public static function get_embed_url(string $url): \moodle_url {
716         return new \moodle_url('/h5p/embed.php', ['url' => $url]);
717     }
719     /**
720      * Return the export file for Mobile App.
721      *
722      * @return array
723      */
724     public function get_export_file(): array {
725         // Get the export url.
726         $exporturl = $this->get_export_settings(true);
727         // Get the filename of the export url.
728         $path = $exporturl->out_as_local_url();
729         $parts = explode('/', $path);
730         $filename = array_pop($parts);
731         // Get the the export file.
732         $systemcontext = \context_system::instance();
733         $fs = get_file_storage();
734         $fileh5p = $fs->get_file($systemcontext->id,
735             \core_h5p\file_storage::COMPONENT,
736             \core_h5p\file_storage::EXPORT_FILEAREA,
737             0,
738             '/',
739             $filename);
740         // Get the options that the Mobile App needs.
741         $file = [];
742         $file['filename'] = $fileh5p->get_filename();
743         $file['filepath'] = $fileh5p->get_filepath();
744         $file['mimetype'] = $fileh5p->get_mimetype();
745         $file['filesize'] = $fileh5p->get_filesize();
746         $file['timemodified'] = $fileh5p->get_timemodified();
747         $file['fileurl'] = $exporturl->out(false);
749         return $file;
750     }