'); // Alternative text for drush uninstalls drupal_set_message("Leaving because the H5P plugin isn’t working for you? Please share your feedback so we can improve. https://h5p.org/drupal-module-disabled"); } /** * Implements hook_uninstall(). */ function h5p_uninstall() { global $language; // Clean out file dirs. $h5p_path = file_stream_wrapper_get_instance_by_uri('public://')->getDirectoryPath() . '/' . variable_get('h5p_default_path', 'h5p'); // Load core require_once('library/h5p.classes.php'); require_once('library/h5p-development.class.php'); require_once('library/h5p-file-storage.interface.php'); require_once('library/h5p-default-storage.class.php'); require_once('h5p.classes.inc'); require_once('h5p.module'); $interface = new H5PDrupal(); $core = new H5PCore($interface, $h5p_path, base_path(), $language->language, (variable_get('h5p_export', '1') ? TRUE : FALSE), H5PDevelopment::MODE_NONE); // Notify about uninstall $core->fetchLibrariesMetadata(); // Remove these regardless of their content. foreach (array('temp', 'libraries', 'content', 'exports') as $directory) { _h5p_recursive_unlink($h5p_path . '/' . $directory); } // Delete remaining h5p entries in file_managed table $h5p_uri = db_or() ->condition('uri', '%' . db_like('//h5p/') . '%', 'LIKE') ->condition('uri', '%' . db_like('//h5peditor/') . '%', 'LIKE'); db_delete('file_managed') ->condition($h5p_uri) ->execute(); // Only remove development dir if it's empty. $dir = $h5p_path . '/development'; if (is_dir($dir) && count(scandir($dir)) === 2) { rmdir($dir); // Remove parent if empty. if (count(scandir($h5p_path)) === 2) { rmdir($h5p_path); } } // Remove variables. variable_del('h5p_frame'); variable_del('h5p_export'); variable_del('h5p_embed'); variable_del('h5p_copyright'); variable_del('h5p_icon'); variable_del('h5p_revisioning'); variable_del('h5p_content_dev_mode'); variable_del('h5p_default_path'); variable_del('h5p_dev_mode'); variable_del('h5p_library_development'); variable_del('h5p_library_whitelist_extras'); variable_del('h5p_whitelist'); variable_del('h5p_unsupported_libraries'); variable_del('h5p_fetched_library_metadata_on'); variable_del('h5p_first_runnable_saved'); variable_del('h5p_save_content_frequency'); variable_del('h5p_save_content_state'); variable_del('h5p_update_available'); variable_del('h5p_update_available_path'); variable_del('h5p_site_type'); variable_del('h5p_enable_lrs_content_types'); variable_del('h5p_hub_is_enabled'); variable_del('h5p_content_type_cache_updated_at'); variable_del('h5p_allow_communication_with_h5p_org'); variable_del('h5p_send_usage_statistics'); variable_del('h5p_search_content_hub'); // Intentionally not deleting variable h5p_site_uuid. If h5p module is uninstalled/installed, // the uuid should be the same // variable_del('h5p_site_uuid'); } /** * Implements hook_install() * @link https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_install/7.x */ function h5p_install() { // Notify of communication channels drupal_set_message( t('H5P fetches content types directly from the H5P Hub. In order to do this the H5P plugin will communicate with the Hub once a day to fetch information about new and updated content types. It will send in anonymous data to the Hub about H5P usage. Read more at the plugin communication page at H5P.org.') ); } /** * Recursively remove file or directory. * * @param string $file */ function _h5p_recursive_unlink($file) { if (is_dir($file)) { // Remove all files in dir. $subfiles = array_diff(scandir($file), array('.','..')); foreach ($subfiles as $subfile) { _h5p_recursive_unlink($file . '/' . $subfile); } rmdir($file); } elseif (file_exists($file)) { // Get file from file_managed if it exists $file_uri = file_build_uri(substr($file, strpos($file, 'h5p/'), strlen($file))); $fid = db_query("SELECT fid FROM {file_managed} WHERE uri = :path", array(':path' => $file_uri))->fetchField(); if ($fid !== false) { // If it was found delete file and database record $file_object = file_load($fid); file_delete($file_object); } else { // Delete locally drupal_unlink($file); } } } function h5p_enable() { if (function_exists('views_invalidate_cache')) { views_invalidate_cache(); } $core = _h5p_get_instance('core'); // Check requirements $core->checkSetupForRequirements(); // Update content type cache $core->updateContentTypeCache(); } /** * Implements hook_schema(). */ function h5p_schema() { $schema['h5p_nodes_libraries'] = array( 'description' => 'Stores information about what h5p uses what libraries.', 'fields' => array( 'content_id' => array( 'description' => 'Primary Key: The unique identifier for a node(vid by default).', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'library_id' => array( 'description' => 'The identifier of a h5p library this content uses.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'dependency_type' => array( 'description' => "dynamic, preloaded or editor", 'type' => 'varchar', 'length' => 31, 'not null' => TRUE, 'default' => 'preloaded', ), 'drop_css' => array( 'description' => '1 if the preloaded css from the dependency is to be excluded.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'weight' => array( 'description' => 'Determines the order in which the preloaded libraries will be loaded', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 999999, ), ), 'primary key' => array('content_id', 'library_id', 'dependency_type'), 'indexes' => array( 'weight' => array('weight') ) ); $schema['h5p_libraries'] = array( 'description' => 'Stores information about what h5p uses what libraries.', 'fields' => array( 'library_id' => array( 'description' => 'Primary Key: The id of the library.', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'machine_name' => array( 'description' => 'The library machine name', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '', ), 'title' => array( 'description' => 'The human readable name of this library', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), 'major_version' => array( 'description' => 'The version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'minor_version' => array( 'description' => 'The minor version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'patch_version' => array( 'description' => 'The patch version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'runnable' => array( 'description' => 'Whether or not this library is executable.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 1, ), 'fullscreen' => array( 'description' => 'Indicates if this library can be opened in fullscreen.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'embed_types' => array( 'description' => 'The allowed embed types for this library as a comma separated list', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), 'preloaded_js' => array( 'description' => 'The preloaded js for this library as a comma separated list', 'type' => 'text', ), 'preloaded_css' => array( 'description' => 'The preloaded css for this library as a comma separated list', 'type' => 'text', ), 'drop_library_css' => array( // TODO: This really needs to be move to h5p_libraries_libraries. 'description' => 'List of libraries that should not have CSS included if this library is used. Comma separated list.', 'type' => 'text', ), 'semantics' => array( 'description' => 'The semantics definition in json format', 'type' => 'text', 'not null' => TRUE, ), 'restricted' => array( 'description' => 'Restricts the ability to create new content using this library.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'tutorial_url' => array( 'description' => 'URL to a tutorial for this library', 'type' => 'varchar', 'length' => 1000 ), 'has_icon' => array( 'description' => 'Whether or not this library contains an icon.svg', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'add_to' => array( 'description' => 'Plugin configuration data', 'type' => 'text', ), 'metadata_settings' => array( 'description' => 'Metadata settings', 'type' => 'text' ), 'patch_version_in_folder_name' => array( 'description' => 'Is patch version part of folder name', 'type' => 'int', 'size' => 'tiny', 'unsigned' => true, 'not null' => true, 'default' => 0, ), ), 'primary key' => array('library_id'), 'indexes' => array( 'library' => array('machine_name', 'major_version', 'minor_version'), 'title' => array('title') ) ); $schema['h5p_libraries_hub_cache'] = array( 'description' => 'Stores information about what h5p uses what libraries.', 'fields' => array( 'id' => array( 'description' => 'Primary Key: The id of the library.', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'machine_name' => array( 'description' => 'The library machine name', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '', ), 'major_version' => array( 'description' => 'The version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'minor_version' => array( 'description' => 'The minor version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'patch_version' => array( 'description' => 'The patch version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'h5p_major_version' => array( 'description' => 'The major version required of H5P core.', 'type' => 'int', 'unsigned' => TRUE ), 'h5p_minor_version' => array( 'description' => 'The minor version required of H5P core.', 'type' => 'int', 'unsigned' => TRUE ), 'title' => array( 'description' => 'The human readable name of this library', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), 'summary' => array( 'description' => 'Short description of library.', 'type' => 'text', 'size' => 'small', 'not null' => TRUE, ), 'description' => array( 'description' => 'Long description of library.', 'type' => 'text', 'size' => 'medium', 'not null' => TRUE, ), 'icon' => array( 'description' => 'URL to icon.', 'type' => 'varchar', 'length' => 511, 'not null' => TRUE, 'default' => '', ), 'created_at' => array( 'description' => 'Time that the library was uploaded.', 'type' => 'int', 'not null' => TRUE, ), 'updated_at' => array( 'description' => 'Time that the library had its latest update.', 'type' => 'int', 'not null' => TRUE, ), 'is_recommended' => array( 'description' => 'Whether the library is recommended by the HUB moderators.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 1, ), 'popularity' => array( 'description' => 'How many times the library has been downloaded.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'screenshots' => array( 'description' => 'Screenshot URLs json encoded', 'type' => 'text', 'size' => 'medium' ), 'license' => array( 'description' => 'Library license(s) json encoded', 'type' => 'text', 'size' => 'medium' ), 'example' => array( 'description' => 'URL to example content for this library.', 'type' => 'varchar', 'length' => 511, 'not null' => TRUE, 'default' => '', ), 'tutorial' => array( 'description' => 'Tutorial URL', 'type' => 'varchar', 'length' => 511 ), 'keywords' => array( 'description' => 'Keywords for library json encoded', 'type' => 'text', 'size' => 'medium' ), 'categories' => array( 'description' => 'Categories for library json encoded', 'type' => 'text', 'size' => 'medium' ), 'owner' => array( 'description' => 'Owner of the library', 'type' => 'varchar', 'length' => 511 ) ), 'primary key' => array('id'), 'indexes' => array( 'machine_name' => array('machine_name') ) ); $schema['h5p_libraries_libraries'] = array( 'description' => 'Stores information about library dependencies.', 'fields' => array( 'library_id' => array( 'description' => 'Primary Key: The id of a h5p library.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'required_library_id' => array( 'description' => 'Primary Key: The id of a h5p library.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'dependency_type' => array( 'description' => 'preloaded, dynamic, or editor', 'type' => 'varchar', 'length' => 31, 'not null' => TRUE, ), ), 'primary key' => array('library_id', 'required_library_id'), ); $schema['h5p_libraries_languages'] = array( 'description' => 'Stores translations for the languages.', 'fields' => array( 'library_id' => array( 'description' => 'Primary Key: The id of a h5p library.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'language_code' => array( 'description' => 'Primary Key: The language code.', 'type' => 'varchar', 'length' => 31, 'not null' => TRUE, ), 'language_json' => array( 'description' => 'The translations defined in json format', 'type' => 'text', 'not null' => TRUE, ), ), 'primary key' => array('library_id', 'language_code'), ); $schema['h5p_nodes'] = array( 'description' => 'Stores information about where the h5p content is stored.', 'fields' => array( 'content_id' => array( 'description' => 'Primary Key: The unique identifier for this node(vid by default).', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'nid' => array( 'description' => 'The {node}.nid of the h5p node.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'json_content' => array( 'description' => 'The content in json format', 'type' => 'text', 'not null' => TRUE, 'size' => 'big', ), 'embed_type' => array( 'description' => 'The embed type for this content', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '', ), 'disable' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0 ), 'main_library_id' => array( 'description' => 'The library we first instanciate for this node', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'content_type' => array( 'description' => 'Content type as defined in h5p.json', 'type' => 'varchar', 'length' => 127, ), 'authors' => array( 'description' => 'List of authors in json format', 'type' => 'text' ), 'source' => array( 'description' => 'Link to the source, could also be citation', 'type' => 'varchar', 'length' => 255 ), 'year_from' => array( 'description' => 'Start year for copyright', 'type' => 'int', 'unsigned' => TRUE ), 'year_to' => array( 'description' => 'End year for copyright', 'type' => 'int', 'unsigned' => TRUE ), 'license' => array( 'description' => 'License name of the content', 'type' => 'varchar', 'length' => 32 ), 'license_version' => array( 'description' => 'Version of license used for the content', 'type' => 'varchar', 'length' => 10 ), 'changes' => array( 'description' => 'List of changes in json format', 'type' => 'text' ), 'license_extras' => array( 'description' => 'Extra licensing terms', 'type' => 'text' ), 'author_comments' => array( 'description' => 'Comments for the editor', 'type' => 'text' ), 'filtered' => array( 'description' => 'Filtered version of json_content', 'type' => 'text', 'size' => 'big', 'not null' => TRUE ), 'slug' => array( 'description' => 'Human readable content identifier that is unique', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE ), 'default_language' => array( 'description' => 'Default language for common fields', 'type' => 'varchar', 'length' => 32 ), 'shared' => array( 'description' => 'Shared status for the content hub', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'synced' => array( 'description' => 'Sync status with the content hub', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, ), 'content_hub_id' => array( 'description' => 'Id of the content on the content hub used for sync', 'type' => 'int', 'size' => 'big', 'unsigned' => TRUE, ), 'a11y_title' => array( 'description' => 'Title for assistive technologies', 'type' => 'varchar', 'length' => 255, 'not null' => FALSE ), ), 'primary key' => array('content_id'), 'indexes' => array( 'nid' => array('nid'), 'library' => array('main_library_id'), 'slug' => array('slug'), ) ); $schema['h5p_points'] = array( 'description' => 'Stores user statistics.', 'fields' => array( 'content_id' => array( 'description' => 'Primary Key: The unique identifier for this node.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'uid' => array( 'description' => 'Primary Key: The id for the user answering this H5P.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'started' => array( 'description' => 'When the user started on the interaction', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'finished' => array( 'description' => 'When the user submitted the result', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'points' => array( 'description' => 'The users score', 'type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, ), 'max_points' => array( 'description' => 'The maximum score for this test', 'type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, ), ), 'primary key' => array('content_id', 'uid'), ); $schema['h5p_content_user_data'] = array( 'description' => 'Stores user data about the content', 'fields' => array( 'user_id' => array( 'description' => 'The user identifier', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'content_main_id' => array( 'description' => 'The main identifier for the h5p content', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'sub_content_id' => array( 'description' => 'The sub identifier for the h5p content', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'data_id' => array( 'description' => 'The data type identifier', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE, ), 'timestamp' => array( 'description' => 'What the time is', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'data' => array( 'description' => 'Contains the data saved', 'type' => 'text', 'not null' => TRUE, 'size' => 'big', ), 'preloaded' => array( 'description' => 'Indicates if the is to be preloaded', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => FALSE, ), 'delete_on_content_change' => array( 'description' => 'Indicates if the data is to be deleted when the content gets updated', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => FALSE, ), ), 'primary key' => array('user_id', 'content_main_id', 'sub_content_id', 'data_id'), ); $schema['h5p_events'] = array( 'description' => 'Keeps track of what happens in the H5P system', 'fields' => array( 'id' => array( 'description' => 'The unique event identifier', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE ), 'user_id' => array( 'description' => 'User id', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE ), 'created_at' => array( 'description' => 'Time of the event', 'type' => 'int', 'not null' => TRUE ), 'type' => array( 'description' => 'Type of event', 'type' => 'varchar', 'length' => 63, 'not null' => TRUE ), 'sub_type' => array( 'description' => 'Sub type of event', 'type' => 'varchar', 'length' => 63, 'not null' => TRUE ), 'content_id' => array( 'description' => 'Content id', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE ), 'content_title' => array( 'description' => 'Content title', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE ), 'library_name' => array( 'description' => 'Library name', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE ), 'library_version' => array( 'description' => 'Version of library', 'type' => 'varchar', 'length' => 31, 'not null' => TRUE ) ), 'primary key' => array('id'), 'indexes' => array( 'created_at' => array('created_at') ) ); $schema['h5p_counters'] = array( 'description' => 'Global counters for the H5P system', 'fields' => array( 'type' => array( 'description' => 'Type of counter', 'type' => 'varchar', 'length' => 63, 'not null' => TRUE ), 'library_name' => array( 'description' => 'Library', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE ), 'library_version' => array( 'description' => 'Version of library', 'type' => 'varchar', 'length' => 31, 'not null' => TRUE ), 'num' => array( 'description' => 'Number value of counter', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE ), ), 'primary key' => array('type', 'library_name', 'library_version') ); $schema['h5p_content_hub_metadata_cache'] = array( 'description' => 'JSON representation of the content hub metadata cache', 'fields' => array( 'language' => array( 'description' => 'Language of metadata', 'type' => 'varchar', 'length' => 31, ), 'json' => array( 'description' => 'Metadata as JSON', 'type' => 'text', 'size' => 'big', ), 'last_checked' => array( 'description' => 'Last time metadata was checked.', 'type' => 'int', ), ) ); return $schema; } /** * Implements hook_requirements(). */ function h5p_requirements($phase) { $requirements = array(); if ($phase == 'runtime') { // TODO: Add check for zip library // File paths // TODO: Merge over _h5p_check_settings from .module? $h5p_path = file_stream_wrapper_get_instance_by_uri('public://')->getDirectoryPath() . '/' . variable_get('h5p_default_path', 'h5p'); $temp_path = $h5p_path . '/temp'; $export_path = $h5p_path . '/exports'; if (!file_prepare_directory($h5p_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { $requirements['h5p_dirs'] = array( 'value' => t('Missing directory.'), 'severity' => REQUIREMENT_ERROR, 'description' => t("The h5p module's package directory %h5p_path is missing.", array('%h5p_path' => $h5p_path)), ); } else if (!file_prepare_directory($temp_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { $requirements['h5p_dirs'] = array( 'value' => t('Missing temp directory.'), 'severity' => REQUIREMENT_ERROR, 'description' => t("The h5p module's temp directory %temp_path is missing.", array('%temp_path' => $temp_path)), ); } else if (!file_prepare_directory($export_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { $requirements['h5p_dirs'] = array( 'value' => t('Missing export directory.'), 'severity' => REQUIREMENT_ERROR, 'description' => t("The h5p module's export directory %export_path is missing.", array('%export_path' => $export_path)), ); } else { $requirements['h5p_dirs'] = array( 'value' => t('Exists (%path).', array('%path' => $h5p_path)), 'severity' => REQUIREMENT_OK, ); } $requirements['h5p_dirs']['title'] = t('h5p module directories'); } return $requirements; } /** * Implements hook_update_N(). */ function h5p_update_6100() { db_add_field('h5p_libraries', 'fullscreen', array( 'description' => 'Indicates if this library can be opened in fullscreen.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, )); return t('Fullscreen field added to h5p_libraries'); } /** * Implements hook_update_N(). */ function h5p_update_6101() { db_create_table('h5p_libraries_languages', array( 'description' => 'Stores translations for the languages.', 'fields' => array( 'library_id' => array( 'description' => 'Primary Key: The id of a h5p library.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'language_code' => array( 'description' => 'Primary Key: The language code.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'language_json' => array( 'description' => 'The translations defined in json format', 'type' => 'text', 'not null' => TRUE, ), ), 'primary key' => array('library_id', 'language_code'), )); return t('Table for storing language information created'); } /** * Implements hook_update_N(). */ function h5p_update_6102() { db_add_field('h5p_nodes', 'content_type', array( 'description' => 'Content type as defined in h5p.json', 'type' => 'varchar', 'length' => 127, )); db_add_field('h5p_nodes', 'author', array( 'description' => 'Author as defined in h5p.json', 'type' => 'varchar', 'length' => 127, )); db_add_field('h5p_nodes', 'license', array( 'description' => 'License as defined in h5p.json', 'type' => 'varchar', 'length' => 7, )); db_add_field('h5p_nodes', 'meta_keywords', array( 'description' => 'Keywords as defined in h5p.json', 'type' => 'text', )); db_add_field('h5p_nodes', 'meta_description', array( 'description' => 'Meta description as defined in h5p.json', 'type' => 'text', )); return t('Fields for storing metadata about the H5P content added'); } /** * Implements hook_update_N(). */ function h5p_update_6103() { db_change_field('h5p_nodes', 'json_content', 'json_content', array( 'description' => 'The content in json format', 'type' => 'text', 'not null' => TRUE, 'size' => 'big', )); return t("Support for H5P's with lots of data added."); } /** * Implements hook_update_N(). */ function h5p_update_6104() { db_add_index('files', 'filepath', array('filepath')); return t('Add index to filepath in the files table'); } /** * Implementation of hook_update_N(). * * Renames the h5p_nodes_libraries.preloaded field to dependency_type, * and converts it to contain an integer. * * Updates h5p_nodes_libraries to get all dependencies. */ function h5p_update_6105(&$sandbox) { if (isset($sandbox['content']) === FALSE) { if (db_field_exists('h5p_nodes_libraries', 'preloaded')) { db_drop_primary_key('h5p_nodes_libraries'); db_change_field('h5p_nodes_libraries', 'preloaded', 'dependency_type', array( 'description' => "dynamic, preloaded or editor", 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'preloaded', ), array( 'primary key' => array('content_id', 'library_id', 'dependency_type') )); } // Update h5p_nodes_libraries to get all dependencies. $result = db_query(" SELECT hn.content_id AS id, hl.machine_name AS libraryName, hl.major_version AS libraryMajorVersion, hl.minor_version AS libraryMinorVersion FROM {h5p_nodes} hn JOIN {h5p_libraries} hl ON hl.library_id = hn.main_library_id "); // Update h5p_nodes_libraries since column has changed type db_query("UPDATE {h5p_nodes_libraries} set dependency_type='preloaded' where dependency_type='1'"); db_query("UPDATE {h5p_nodes_libraries} set dependency_type='dynamic' where dependency_type='0'"); $sandbox['content'] = array(); foreach ($result as $content) { $sandbox['content'][] = $content; } $sandbox['current'] = 0; $sandbox['max'] = count($sandbox['content']); } if ($sandbox['max'] === 0) { $sandbox['#finished'] = 1; } else { h5p_save_content_dependencies($sandbox['content'][$sandbox['current']]); $sandbox['current']++; $sandbox['#finished'] = ($sandbox['current'] / $sandbox['max']); } } /** * Implementation of hook_update_N(). * * Adds the h5p_points-table, which stores user statistics. * */ function h5p_update_7100(&$sandbox) { db_create_table('h5p_points', array( 'description' => 'Stores user statistics.', 'fields' => array( 'content_id' => array( 'description' => 'Primary Key: The unique identifier for this node.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'uid' => array( 'description' => 'Primary Key: The id for the user answering this H5P.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'started' => array( 'description' => 'When the user started on the interaction', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'finished' => array( 'description' => 'When the user submitted the result', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'points' => array( 'description' => 'The users score', 'type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, ), 'max_points' => array( 'description' => 'The maximum score for this test', 'type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, ), ), 'primary key' => array('content_id', 'uid'), )); } /** * Implementation of hook_update_N(). * * Invalidates views cache so that the new default views will be installed * */ function h5p_update_7101() { if (function_exists('views_invalidate_cache')) { views_invalidate_cache(); } } /** * Implementation of hook_update_N(). * * Check if any of the installed H5P libraries are not supported by the current * H5P core version * */ function h5p_update_7102() { } /** * Adds an option that makes it possible to restrict the creation of selected H5P content types to users with a specific role. */ function h5p_update_7103() { db_add_field('h5p_libraries', 'restricted', array( 'description' => 'Restricts the ability to create new content using this library.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, )); } /** * Adds filtered column to h5p_nodes * Adds tutorial_url column to h5p_libraries */ function h5p_update_7104() { if (db_field_exists('h5p_nodes', 'filtered') === FALSE) { db_add_field('h5p_nodes', 'filtered', array( 'description' => 'Filtered version of json_content', 'type' => 'text', 'size' => 'big', )); db_query("update {h5p_nodes} set filtered=''"); db_change_field('h5p_nodes', 'filtered', 'filtered', array( 'description' => 'Filtered version of json_content', 'type' => 'text', 'size' => 'big', 'not null' => TRUE, )); } if (db_field_exists('h5p_libraries', 'tutorial_url') === FALSE) { db_add_field('h5p_libraries', 'tutorial_url', array( 'description' => 'URL to a tutorial for this library', 'type' => 'varchar', 'length' => 1000 )); } _h5p_inform_h5p_org_communication(); } /** * Store if or not we have runnable libraries */ function h5p_update_7105() { if (db_query('SELECT 1 FROM {h5p_libraries} WHERE runnable = 1')->fetchField()) { variable_set('h5p_first_runnable_saved', 1); } } /** * Add weights to the library usage table so that libraries always get loaded in * the correct order */ function h5p_update_7106() { if (db_field_exists('h5p_nodes_libraries', 'weight') === FALSE) { db_add_field('h5p_nodes_libraries', 'weight', array( 'description' => 'Determines the order in which the preloaded libraries will be loaded', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 999999, )); } } /** * Implements hook_update_N(). * * Adds a table for storing user data for each interactive content. */ function h5p_update_7107() { db_create_table('h5p_content_user_data', array( 'description' => 'Stores user data about the content', 'fields' => array( 'user_id' => array( 'description' => 'The user identifier', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'content_main_id' => array( 'description' => 'The main identifier for the h5p content', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'sub_content_id' => array( 'description' => 'The sub identifier for the h5p content', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'data_id' => array( 'description' => 'The data type identifier', 'type' => 'varchar', 'length' => 127, ), 'timestamp' => array( 'description' => 'What the time is', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'data' => array( 'description' => 'Contains the data saved', 'type' => 'text', 'not null' => TRUE, 'size' => 'big', ), 'preloaded' => array( 'description' => 'Indicates if the is to be preloaded', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => FALSE, ), 'delete_on_content_change' => array( 'description' => 'Indicates if the data is to be deleted when the content gets updated', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => FALSE, ), ), 'primary key' => array('user_id', 'content_main_id', 'sub_content_id', 'data_id'), )); } /** * Implements hook_update_N(). * * Makes it possible to disable UI features per content. */ function h5p_update_7108() { if (!db_field_exists('h5p_nodes', 'disable')) { db_add_field('h5p_nodes', 'disable', array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0 )); } } /** * Add unique human readable content identifier. Useful for creating human * readable file names, URLs and SEO. */ function h5p_update_7109() { if (!db_field_exists('h5p_nodes', 'slug')) { db_add_field('h5p_nodes', 'slug', array( 'description' => 'Human readable content identifier that is unique', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '' )); } } /** * Adds the H5P events and counters tables. */ function h5p_update_7110() { db_create_table('h5p_events', array( 'description' => 'Keeps track of what happens in the H5P system', 'fields' => array( 'id' => array( 'description' => 'The unique event identifier', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE ), 'user_id' => array( 'description' => 'User id', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE ), 'created_at' => array( 'description' => 'Time of the event', 'type' => 'int', 'not null' => TRUE ), 'type' => array( 'description' => 'Type of event', 'type' => 'varchar', 'length' => 63, 'not null' => TRUE ), 'sub_type' => array( 'description' => 'Sub type of event', 'type' => 'varchar', 'length' => 63, 'not null' => TRUE ), 'content_id' => array( 'description' => 'Content id', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE ), 'content_title' => array( 'description' => 'Content title', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE ), 'library_name' => array( 'description' => 'Library name', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE ), 'library_version' => array( 'description' => 'Version of library', 'type' => 'varchar', 'length' => 31, 'not null' => TRUE ) ), 'primary key' => array('id') )); db_create_table('h5p_counters', array( 'description' => 'Global counters for the H5P system', 'fields' => array( 'type' => array( 'description' => 'Type of counter', 'type' => 'varchar', 'length' => 63, 'not null' => TRUE ), 'library_name' => array( 'description' => 'Library', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE ), 'library_version' => array( 'description' => 'Version of library', 'type' => 'varchar', 'length' => 31, 'not null' => TRUE ), 'num' => array( 'description' => 'Number value of counter', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE ), ), 'primary key' => array('type', 'library_name', 'library_version') )); } /** * (re)Save all dependencies for given content. * This will given content nodes a relation to all libraries used by it's main library. * * @param object $content */ function h5p_save_content_dependencies($content) { require_once drupal_get_path('module', 'h5p') . '/library/h5p-development.class.php'; require_once drupal_get_path('module', 'h5p') . '/library/h5p.classes.php'; require_once drupal_get_path('module', 'h5p') . '/h5p.classes.inc'; $i = _h5p_get_instance('interface'); $core = _h5p_get_instance('core'); $library = $i->loadLibrary($content->libraryName, $content->libraryMajorVersion, $content->libraryMinorVersion); $dependencies = array(); $core->findLibraryDependencies($dependencies, $library); $dropLibraryCssList = array(); foreach ($dependencies as $dependency) { if (!empty($dependency['library']['dropLibraryCss'])) { $dropLibraryCssList = array_merge($dropLibraryCssList, explode(', ', $dependency['library']['dropLibraryCss'])); } } foreach ($dependencies as $dependency) { $dropCss = in_array($dependency['library']['machineName'], $dropLibraryCssList) ? 1 : 0; db_merge('h5p_nodes_libraries') ->key(array('content_id' => $content->id, 'library_id' => $dependency['library']['libraryId'], 'dependency_type' => $dependency['type'])) ->fields(array('drop_css' => $dropCss)) ->execute(); } } /** * Clean up data from deleted revisions. */ function h5p_update_7111() { if (!variable_get('h5p_revisioning', 1)) { return; } $h5p_core = _h5p_get_instance('storage'); // Load them and... delete them! $res = db_query(" SELECT hn.content_id AS id, hn.slug FROM {h5p_nodes} hn LEFT JOIN {node_revision} nr ON nr.vid = hn.content_id WHERE nr.timestamp IS NULL"); while ($content = $res->fetchAssoc()) { $h5p_core->deletePackage($content); // Remove content points db_delete('h5p_points') ->condition('content_id', $content['id']) ->execute(); // Remove content user data db_delete('h5p_content_user_data') ->condition('content_main_id', $content['id']) ->execute(); } } /** * Fixes upgrade issue with woff and woff2 font. */ function h5p_update_7112() { $whitelist = variable_get('h5p_whitelist', H5PCore::$defaultContentWhitelist); $woff_pos = strpos($whitelist, 'woff'); if ($woff_pos !== false && strpos($whitelist, 'woff2') === false) { $new_whitelist = substr_replace($whitelist, ' woff2', $woff_pos + 4, 0); variable_set('h5p_whitelist', $new_whitelist); } } /** * Renaming variable h5p_icon_in_action_bar to h5p_icon */ function h5p_update_7113() { variable_set('h5p_icon', variable_get('h5p_icon_in_action_bar', TRUE)); variable_del('h5p_icon_in_action_bar'); drupal_set_message('Upgrade your H5P content types! Old content types will still work, but the authoring tool will look and feel much better if you upgrade the content types.', 'warning'); } /** * Add indexes to enhance database performance. */ function h5p_update_7114() { if (!db_index_exists('h5p_nodes_libraries', 'weight')) { db_add_index('h5p_nodes_libraries', 'weight', array('weight')); } if (!db_index_exists('h5p_libraries', 'library')) { db_add_index('h5p_libraries', 'library', array('machine_name', 'major_version', 'minor_version')); } if (!db_index_exists('h5p_libraries', 'title')) { db_add_index('h5p_libraries', 'title', array('title')); } if (!db_index_exists('h5p_nodes', 'nid')) { db_add_index('h5p_nodes', 'nid', array('nid')); } if (!db_index_exists('h5p_nodes', 'library')) { db_add_index('h5p_nodes', 'library', array('main_library_id')); } if (!db_index_exists('h5p_nodes', 'slug')) { db_add_index('h5p_nodes', 'slug', array('slug')); } if (!db_index_exists('h5p_events', 'created_at')) { db_add_index('h5p_events', 'created_at', array('created_at')); } } /** * Add content type cache table. * Add icon flag to libraries table. * Enable H5P Hub. */ function h5p_update_7115() { db_create_table('h5p_libraries_hub_cache', array( 'description' => 'Stores information about what h5p uses what libraries.', 'fields' => array( 'id' => array( 'description' => 'Primary Key: The id of the library.', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'machine_name' => array( 'description' => 'The library machine name', 'type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '', ), 'major_version' => array( 'description' => 'The version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'minor_version' => array( 'description' => 'The minor version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'patch_version' => array( 'description' => 'The patch version of this library', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), 'h5p_major_version' => array( 'description' => 'The major version required of H5P core.', 'type' => 'int', 'unsigned' => TRUE ), 'h5p_minor_version' => array( 'description' => 'The minor version required of H5P core.', 'type' => 'int', 'unsigned' => TRUE ), 'title' => array( 'description' => 'The human readable name of this library', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), 'summary' => array( 'description' => 'Short description of library.', 'type' => 'text', 'size' => 'small', 'not null' => TRUE, ), 'description' => array( 'description' => 'Long description of library.', 'type' => 'text', 'size' => 'medium', 'not null' => TRUE, ), 'icon' => array( 'description' => 'URL to icon.', 'type' => 'varchar', 'length' => 511, 'not null' => TRUE, 'default' => '', ), 'created_at' => array( 'description' => 'Time that the library was uploaded.', 'type' => 'int', 'not null' => TRUE, ), 'updated_at' => array( 'description' => 'Time that the library had its latest update.', 'type' => 'int', 'not null' => TRUE, ), 'is_recommended' => array( 'description' => 'Whether the library is recommended by the HUB moderators.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 1, ), 'popularity' => array( 'description' => 'How many times the library has been downloaded.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'screenshots' => array( 'description' => 'Screenshot URLs json encoded', 'type' => 'text', 'size' => 'medium' ), 'license' => array( 'description' => 'Library license(s) json encoded', 'type' => 'text', 'size' => 'medium' ), 'example' => array( 'description' => 'URL to example content for this library.', 'type' => 'varchar', 'length' => 511, 'not null' => TRUE, 'default' => '', ), 'tutorial' => array( 'description' => 'Tutorial URL', 'type' => 'varchar', 'length' => 511 ), 'keywords' => array( 'description' => 'Keywords for library json encoded', 'type' => 'text', 'size' => 'medium' ), 'categories' => array( 'description' => 'Categories for library json encoded', 'type' => 'text', 'size' => 'medium' ), 'owner' => array( 'description' => 'Owner of the library', 'type' => 'varchar', 'length' => 511 ) ), 'primary key' => array('id'), )); if (!db_field_exists('h5p_libraries', 'has_icon')) { db_add_field('h5p_libraries', 'has_icon', array( 'description' => 'Whether or not this library contains an icon.svg', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, )); } // Display hub communication info if (!variable_get('h5p_allow_communication_with_h5p_org', TRUE)) { drupal_set_message( t('H5P now fetches content types directly from the H5P Hub. In order to do this, the H5P plugin will communicate with H5P.org once per day to fetch information about new and updated content types. It will send in anonymous data to the hub about H5P usage. You may disable the data contribution and/or the H5P Hub in the H5P settings.') ); } // Enable hub and delete old communication variabe variable_set('h5p_hub_is_enabled', TRUE); variable_del('h5p_allow_communication_with_h5p_org'); } /** * Adding wav to whitelist */ function h5p_update_7116() { $whitelist = variable_get('h5p_whitelist', H5PCore::$defaultContentWhitelist); if (strpos($whitelist, 'wav') === FALSE) { variable_set('h5p_whitelist', $whitelist . ' wav'); } } /** * Adding vtt and webvtt to whitelist */ function h5p_update_7117() { $whitelist = variable_get('h5p_whitelist', H5PCore::$defaultContentWhitelist); $add = ''; if (strpos($whitelist, 'vtt') === FALSE) { $add .= ' vtt'; } if (strpos($whitelist, 'webvtt') === FALSE) { $add .= ' webvtt'; } if ($add !== '') { variable_set('h5p_whitelist', $whitelist . $add); } } /** * Implements hook_update_N(). * Change h5p_nodes for metadata. */ function h5p_update_7118() { if (db_field_exists('h5p_nodes', 'author')) { db_drop_field('h5p_nodes', 'author'); } if (db_field_exists('h5p_nodes', 'license')) { db_drop_field('h5p_nodes', 'license'); } if (db_field_exists('h5p_nodes', 'meta_keywords')) { db_drop_field('h5p_nodes', 'meta_keywords'); } if (db_field_exists('h5p_nodes', 'meta_description')) { db_drop_field('h5p_nodes', 'meta_description'); } if (!db_field_exists('h5p_nodes', 'authors')) { db_add_field('h5p_nodes', 'authors', array( 'description' => 'List of authors in json format', 'type' => 'text' )); } if (!db_field_exists('h5p_nodes', 'source')) { db_add_field('h5p_nodes', 'source', array( 'description' => 'Link to the source, could also be citation', 'type' => 'varchar', 'length' => 255 )); } if (!db_field_exists('h5p_nodes', 'year_from')) { db_add_field('h5p_nodes', 'year_from', array( 'description' => 'Start year for copyright', 'type' => 'int', 'unsigned' => TRUE )); } if (!db_field_exists('h5p_nodes', 'year_to')) { db_add_field('h5p_nodes', 'year_to', array( 'description' => 'End year for copyright', 'type' => 'int', 'unsigned' => TRUE )); } if (!db_field_exists('h5p_nodes', 'license')) { db_add_field('h5p_nodes', 'license', array( 'description' => 'License name of the content', 'type' => 'varchar', 'length' => 32 )); } if (!db_field_exists('h5p_nodes', 'license_version')) { db_add_field('h5p_nodes', 'license_version', array( 'description' => 'Version of license used for the content', 'type' => 'varchar', 'length' => 10 )); } if (!db_field_exists('h5p_nodes', 'changes')) { db_add_field('h5p_nodes', 'changes', array( 'description' => 'List of changes in json format', 'type' => 'text' )); } if (!db_field_exists('h5p_nodes', 'license_extras')) { db_add_field('h5p_nodes', 'license_extras', array( 'description' => 'Extra licensing terms', 'type' => 'text' )); } if (!db_field_exists('h5p_nodes', 'author_comments')) { db_add_field('h5p_nodes', 'author_comments', array( 'description' => 'Comments for the editor', 'type' => 'text' )); } } /** * Add field for plugin Configuration */ function h5p_update_7119() { if (!db_field_exists('h5p_libraries', 'add_to')) { db_add_field('h5p_libraries', 'add_to', array( 'description' => 'plugin configuration data', 'type' => 'text' )); } } /** * Add field for metadata */ function h5p_update_7120() { if (!db_field_exists('h5p_libraries', 'metadata_settings')) { db_add_field('h5p_libraries', 'metadata_settings', array( 'description' => 'Metadata settings', 'type' => 'text' )); } } /** * Make the content files permanent */ function h5p_update_7121() { db_update('file_managed') ->fields(array( 'status' => 1, )) ->condition('uri', 'public://h5p/content/%', 'LIKE') ->condition('status', 0) ->execute(); } /** * Add default language to nodes */ function h5p_update_7122() { if (!db_field_exists('h5p_nodes', 'default_language')) { db_add_field('h5p_nodes', 'default_language', array( 'description' => 'Default language for common fields', 'type' => 'varchar', 'length' => 32 )); } } /** * Add content hub metadata cache */ function h5p_update_7123() { if (!db_table_exists('h5p_content_hub_metadata_cache')) { db_create_table('h5p_content_hub_metadata_cache', array( 'description' => 'JSON representation of the content hub metadata cache', 'fields' => array( 'language' => array( 'description' => 'Language of metadata', 'type' => 'varchar', 'length' => 31, ), 'json' => array( 'description' => 'Metadata as JSON', 'type' => 'text', 'size' => 'big', ), 'last_checked' => array( 'description' => 'Last time metadata was checked.', 'type' => 'int', ), ), )); } if (!db_field_exists('h5p_nodes', 'shared')) { db_add_field('h5p_nodes', 'shared', array( 'description' => 'Shared status for the content hub', 'type' => 'int', 'size' => 'tiny', 'unsigned' => true, 'not null' => true, 'default' => 0, )); } if (!db_field_exists('h5p_nodes', 'synced')) { db_add_field('h5p_nodes', 'synced', array( 'description' => 'Sync status with the content hub', 'type' => 'int', 'size' => 'tiny', 'unsigned' => true, )); } if (!db_field_exists('h5p_nodes', 'content_hub_id')) { db_add_field('h5p_nodes', 'content_hub_id', array( 'description' => 'Id of the content on the content hub used for sync', 'type' => 'int', 'size' => 'big', 'unsigned' => true, )); } if (!db_field_exists('h5p_nodes', 'a11y_title')) { db_add_field('h5p_nodes', 'a11y_title', array( 'description' => 'Title for assistive technologies', 'type' => 'varchar', 'length' => 255, 'not null' => false, )); } } /** * Add patch_version_in_folder_name to h5p_libraries */ function h5p_update_7124() { if (!db_field_exists('h5p_libraries', 'patch_version_in_folder_name')) { db_add_field('h5p_libraries', 'patch_version_in_folder_name', array( 'description' => 'Is patch version part of folder name', 'type' => 'int', 'size' => 'tiny', 'unsigned' => true, 'not null' => true, 'default' => 0, )); } }