See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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 * H5P core 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 */ 24 25 namespace core_h5p; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 require_once("$CFG->libdir/filelib.php"); 30 31 use H5PCore; 32 use H5PFrameworkInterface; 33 use stdClass; 34 use moodle_url; 35 use core_h5p\local\library\autoloader; 36 37 /** 38 * H5P core class, containing functions and storage shared by the other H5P classes. 39 * 40 * @package core_h5p 41 * @copyright 2019 Sara Arjona <sara@moodle.com> 42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 43 */ 44 class core extends \H5PCore { 45 46 /** @var array The array containing all the present libraries */ 47 protected $libraries; 48 49 /** 50 * Constructor for core_h5p/core. 51 * 52 * @param H5PFrameworkInterface $framework The frameworks implementation of the H5PFrameworkInterface 53 * @param string|\H5PFileStorage $path The H5P file storage directory or class 54 * @param string $url The URL to the file storage directory 55 * @param string $language The language code. Defaults to english 56 * @param boolean $export Whether export is enabled 57 */ 58 public function __construct(H5PFrameworkInterface $framework, $path, string $url, string $language = 'en', 59 bool $export = false) { 60 61 parent::__construct($framework, $path, $url, $language, $export); 62 63 // Aggregate the assets by default. 64 $this->aggregateAssets = true; 65 } 66 67 /** 68 * Get the path to the dependency. 69 * 70 * @param array $dependency An array containing the information of the requested dependency library 71 * @return string The path to the dependency library 72 */ 73 protected function getDependencyPath(array $dependency): string { 74 $library = $this->find_library($dependency); 75 76 return "libraries/{$library->id}/{$library->machinename}-{$library->majorversion}.{$library->minorversion}"; 77 } 78 79 /** 80 * Get the paths to the content dependencies. 81 * 82 * @param int $id The H5P content ID 83 * @return array An array containing the path of each content dependency 84 */ 85 public function get_dependency_roots(int $id): array { 86 $roots = []; 87 $dependencies = $this->h5pF->loadContentDependencies($id); 88 $context = \context_system::instance(); 89 foreach ($dependencies as $dependency) { 90 $library = $this->find_library($dependency); 91 $roots[self::libraryToString($dependency, true)] = (moodle_url::make_pluginfile_url( 92 $context->id, 93 'core_h5p', 94 'libraries', 95 $library->id, 96 "/" . self::libraryToString($dependency, true), 97 '' 98 ))->out(false); 99 } 100 101 return $roots; 102 } 103 104 /** 105 * Get a particular dependency library. 106 * 107 * @param array $dependency An array containing information of the dependency library 108 * @return stdClass|null The library object if the library dependency exists, null otherwise 109 */ 110 protected function find_library(array $dependency): ?\stdClass { 111 global $DB; 112 if (null === $this->libraries) { 113 $this->libraries = $DB->get_records('h5p_libraries'); 114 } 115 116 $major = $dependency['majorVersion']; 117 $minor = $dependency['minorVersion']; 118 $patch = $dependency['patchVersion']; 119 120 foreach ($this->libraries as $library) { 121 if ($library->machinename !== $dependency['machineName']) { 122 continue; 123 } 124 125 if ($library->majorversion != $major) { 126 continue; 127 } 128 if ($library->minorversion != $minor) { 129 continue; 130 } 131 if ($library->patchversion != $patch) { 132 continue; 133 } 134 135 return $library; 136 } 137 138 return null; 139 } 140 141 /** 142 * Get the list of JS scripts to include on the page. 143 * 144 * @return array The array containg urls of the core JavaScript files 145 */ 146 public static function get_scripts(): array { 147 global $PAGE; 148 149 $jsrev = $PAGE->requires->get_jsrev(); 150 $urls = []; 151 foreach (self::$scripts as $script) { 152 $urls[] = autoloader::get_h5p_core_library_url($script, [ 153 'ver' => $jsrev, 154 ]); 155 } 156 $urls[] = new moodle_url("/h5p/js/h5p_overrides.js", [ 157 'ver' => $jsrev, 158 ]); 159 160 return $urls; 161 } 162 163 /** 164 * Fetch and install the latest H5P content types libraries from the official H5P repository. 165 * If the latest version of a content type library is present in the system, nothing is done for that content type. 166 * 167 * @return stdClass 168 */ 169 public function fetch_latest_content_types(): ?\stdClass { 170 171 $contenttypes = $this->get_latest_content_types(); 172 if (!empty($contenttypes->error)) { 173 return $contenttypes; 174 } 175 176 $typesinstalled = []; 177 178 $factory = new factory(); 179 $framework = $factory->get_framework(); 180 181 foreach ($contenttypes->contentTypes as $type) { 182 // Don't fetch content types that require a higher H5P core API version. 183 if (!$this->is_required_core_api($type->coreApiVersionNeeded)) { 184 continue; 185 } 186 187 $library = [ 188 'machineName' => $type->id, 189 'majorVersion' => $type->version->major, 190 'minorVersion' => $type->version->minor, 191 'patchVersion' => $type->version->patch, 192 ]; 193 194 $shoulddownload = true; 195 if ($framework->getLibraryId($type->id, $type->version->major, $type->version->minor)) { 196 if (!$framework->isPatchedLibrary($library)) { 197 $shoulddownload = false; 198 } 199 } 200 201 if ($shoulddownload) { 202 $installed['id'] = $this->fetch_content_type($library); 203 if ($installed['id']) { 204 $installed['name'] = \H5PCore::libraryToString($library); 205 $typesinstalled[] = $installed; 206 } 207 } 208 } 209 210 $result = new stdClass(); 211 $result->error = ''; 212 $result->typesinstalled = $typesinstalled; 213 214 return $result; 215 } 216 217 /** 218 * Given an H5P content type machine name, fetch and install the required library from the official H5P repository. 219 * 220 * @param array $library Library machineName, majorversion and minorversion. 221 * @return int|null Returns the id of the content type library installed, null otherwise. 222 */ 223 public function fetch_content_type(array $library): ?int { 224 $factory = new factory(); 225 226 // Download the latest content type from the H5P official repository. 227 $fs = get_file_storage(); 228 $file = $fs->create_file_from_url( 229 (object) [ 230 'component' => 'core_h5p', 231 'filearea' => 'library_sources', 232 'itemid' => 0, 233 'contextid' => (\context_system::instance())->id, 234 'filepath' => '/', 235 'filename' => $library['machineName'], 236 ], 237 $this->get_api_endpoint($library['machineName']), 238 null, 239 true 240 ); 241 242 if (!$file) { 243 return null; 244 } 245 246 helper::save_h5p($factory, $file, (object) [], false, true); 247 248 $file->delete(); 249 250 $librarykey = static::libraryToString($library); 251 $libraryid = $factory->get_storage()->h5pC->librariesJsonData[$librarykey]["libraryId"]; 252 253 return $libraryid; 254 } 255 256 /** 257 * Get H5P endpoints. 258 * 259 * If $endpoint = 'content' and $library is null, moodle_url is the endpoint of the latest version of the H5P content 260 * types; however, if $library is the machine name of a content type, moodle_url is the endpoint to download the content type. 261 * The SITES endpoint ($endpoint = 'site') may be use to get a site UUID or send site data. 262 * 263 * @param string|null $library The machineName of the library whose endpoint is requested. 264 * @param string $endpoint The endpoint required. Valid values: "site", "content". 265 * @return moodle_url The endpoint moodle_url object. 266 */ 267 public function get_api_endpoint(?string $library = null, string $endpoint = 'content'): moodle_url { 268 if ($endpoint == 'site') { 269 $h5purl = \H5PHubEndpoints::createURL(\H5PHubEndpoints::SITES ); 270 } else if ($endpoint == 'content') { 271 $h5purl = \H5PHubEndpoints::createURL(\H5PHubEndpoints::CONTENT_TYPES ) . $library; 272 } 273 274 return new moodle_url($h5purl); 275 } 276 277 /** 278 * Get the latest version of the H5P content types available in the official repository. 279 * 280 * @return stdClass An object with 2 properties: 281 * - string error: error message when there is any problem, empty otherwise 282 * - array contentTypes: an object for each H5P content type with its information 283 */ 284 public function get_latest_content_types(): \stdClass { 285 global $CFG; 286 287 $siteuuid = $this->get_site_uuid() ?? md5($CFG->wwwroot); 288 $postdata = ['uuid' => $siteuuid]; 289 290 // Get the latest content-types json. 291 $endpoint = $this->get_api_endpoint(); 292 $request = download_file_content($endpoint, null, $postdata, true); 293 294 if (!empty($request->error) || $request->status != '200' || empty($request->results)) { 295 if (empty($request->error)) { 296 $request->error = get_string('fetchtypesfailure', 'core_h5p'); 297 } 298 return $request; 299 } 300 301 $contenttypes = json_decode($request->results); 302 $contenttypes->error = ''; 303 304 return $contenttypes; 305 } 306 307 /** 308 * Get the site UUID. If site UUID is not defined, try to register the site. 309 * 310 * return $string The site UUID, null if it is not set. 311 */ 312 public function get_site_uuid(): ?string { 313 // Check if the site_uuid is already set. 314 $siteuuid = get_config('core_h5p', 'site_uuid'); 315 316 if (!$siteuuid) { 317 $siteuuid = $this->register_site(); 318 } 319 320 return $siteuuid; 321 } 322 323 /** 324 * Get H5P generated site UUID. 325 * 326 * return ?string Returns H5P generated site UUID, null if can't get it. 327 */ 328 private function register_site(): ?string { 329 $endpoint = $this->get_api_endpoint(null, 'site'); 330 $siteuuid = download_file_content($endpoint, null, ''); 331 332 // Successful UUID retrieval from H5P. 333 if ($siteuuid) { 334 $json = json_decode($siteuuid); 335 if (isset($json->uuid)) { 336 set_config('site_uuid', $json->uuid, 'core_h5p'); 337 return $json->uuid; 338 } 339 } 340 341 return null; 342 } 343 344 /** 345 * Checks that the required H5P core API version or higher is installed. 346 * 347 * @param stdClass $coreapi Object with properties major and minor for the core API version required. 348 * @return bool True if the required H5P core API version is installed. False if not. 349 */ 350 public function is_required_core_api($coreapi): bool { 351 if (isset($coreapi) && !empty($coreapi)) { 352 if (($coreapi->major > H5PCore::$coreApi['majorVersion']) || 353 (($coreapi->major == H5PCore::$coreApi['majorVersion']) && ($coreapi->minor > H5PCore::$coreApi['minorVersion']))) { 354 return false; 355 } 356 } 357 return true; 358 } 359 360 /** 361 * Get the library string from a DB library record. 362 * 363 * @param stdClass $record The DB library record. 364 * @param bool $foldername If true, use hyphen instead of space in returned string. 365 * @return string The string name on the form {machineName} {majorVersion}.{minorVersion}. 366 */ 367 public static function record_to_string(stdClass $record, bool $foldername = false): string { 368 return static::libraryToString([ 369 'machineName' => $record->machinename, 370 'majorVersion' => $record->majorversion, 371 'minorVersion' => $record->minorversion, 372 ], $foldername); 373 } 374 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body