Reverts content hub interface change
Moved content hub changes to its own feature branch until it is ready to be implemented for all pluginspull/92/head
parent
eb52ec25a0
commit
16c71b444b
365
h5p.classes.php
365
h5p.classes.php
|
@ -23,14 +23,9 @@ interface H5PFrameworkInterface {
|
||||||
* @param array $data Data to post to the URL.
|
* @param array $data Data to post to the URL.
|
||||||
* @param bool $blocking Set to 'FALSE' to instantly time out (fire and forget).
|
* @param bool $blocking Set to 'FALSE' to instantly time out (fire and forget).
|
||||||
* @param string $stream Path to where the file should be saved.
|
* @param string $stream Path to where the file should be saved.
|
||||||
* @param bool $fullData Return additional response data such as headers and potentially other data
|
* @return string The content (response body). NULL if something went wrong
|
||||||
* @param array $headers Headers to send
|
|
||||||
* @param array $files Files to send
|
|
||||||
* @param string $method
|
|
||||||
*
|
|
||||||
* @return string|array The content (response body), or an array with data. NULL if something went wrong
|
|
||||||
*/
|
*/
|
||||||
public function fetchExternalData($url, $data = NULL, $blocking = TRUE, $stream = NULL, $fullData = FALSE, $headers = array(), $files = array(), $method = 'POST');
|
public function fetchExternalData($url, $data = NULL, $blocking = TRUE, $stream = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the tutorial URL for a library. All versions of the library is set
|
* Set the tutorial URL for a library. All versions of the library is set
|
||||||
|
@ -628,44 +623,6 @@ interface H5PFrameworkInterface {
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function libraryHasUpgrade($library);
|
public function libraryHasUpgrade($library);
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace content hub metadata cache
|
|
||||||
*
|
|
||||||
* @param JsonSerializable $metadata Metadata as received from content hub
|
|
||||||
* @param string $lang Language in ISO 639-1
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function replaceContentHubMetadataCache($metadata, $lang);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get content hub metadata cache from db
|
|
||||||
*
|
|
||||||
* @param string $lang Language code in ISO 639-1
|
|
||||||
*
|
|
||||||
* @return JsonSerializable Json string
|
|
||||||
*/
|
|
||||||
public function getContentHubMetadataCache($lang = 'en');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get time of last content hub metadata check
|
|
||||||
*
|
|
||||||
* @param string $lang Language code iin ISO 639-1 format
|
|
||||||
*
|
|
||||||
* @return string|null Time in RFC7231 format
|
|
||||||
*/
|
|
||||||
public function getContentHubMetadataChecked($lang = 'en');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set time of last content hub metadata check
|
|
||||||
*
|
|
||||||
* @param int|null $time Time in RFC7231 format
|
|
||||||
* @param string $lang Language code iin ISO 639-1 format
|
|
||||||
*
|
|
||||||
* @return bool True if successful
|
|
||||||
*/
|
|
||||||
public function setContentHubMetadataChecked($time, $lang = 'en');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2024,28 +1981,9 @@ abstract class H5PDisplayOptionBehaviour {
|
||||||
const CONTROLLED_BY_PERMISSIONS = 4;
|
const CONTROLLED_BY_PERMISSIONS = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class H5PContentHubSyncStatus {
|
|
||||||
const NOT_SYNCED = 0;
|
|
||||||
const SYNCED = 1;
|
|
||||||
const WAITING = 2;
|
|
||||||
const FAILED = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class H5PContentStatus {
|
|
||||||
const STATUS_UNPUBLISHED = 0;
|
|
||||||
const STATUS_DOWNLOADED = 1;
|
|
||||||
const STATUS_WAITING = 2;
|
|
||||||
const STATUS_FAILED_DOWNLOAD = 3;
|
|
||||||
const STATUS_FAILED_VALIDATION = 4;
|
|
||||||
const STATUS_SUSPENDED = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class H5PHubEndpoints {
|
abstract class H5PHubEndpoints {
|
||||||
const CONTENT_TYPES = 'api.h5p.org/v1/content-types/';
|
const CONTENT_TYPES = 'api.h5p.org/v1/content-types/';
|
||||||
const SITES = 'api.h5p.org/v1/sites';
|
const SITES = 'api.h5p.org/v1/sites';
|
||||||
const METADATA = 'api-test.h5p.org/v1/metadata';
|
|
||||||
const CONTENT = 'api-test.h5p.org/v1/contents';
|
|
||||||
const REGISTER = 'api-test.h5p.org/v1/accounts';
|
|
||||||
|
|
||||||
public static function createURL($endpoint) {
|
public static function createURL($endpoint) {
|
||||||
$protocol = (extension_loaded('openssl') ? 'https' : 'http');
|
$protocol = (extension_loaded('openssl') ? 'https' : 'http');
|
||||||
|
@ -3359,72 +3297,6 @@ class H5PCore {
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update content hub metadata cache
|
|
||||||
*/
|
|
||||||
public function updateContentHubMetadataCache($lang = 'en') {
|
|
||||||
$url = H5PHubEndpoints::createURL(H5PHubEndpoints::METADATA);
|
|
||||||
$lastModified = $this->h5pF->getContentHubMetadataChecked($lang);
|
|
||||||
|
|
||||||
$headers = array();
|
|
||||||
if (!empty($lastModified)) {
|
|
||||||
$headers['If-Modified-Since'] = $lastModified;
|
|
||||||
}
|
|
||||||
$data = $this->h5pF->fetchExternalData("{$url}?lang={$lang}", NULL, TRUE, NULL, TRUE, $headers, NULL, 'GET');
|
|
||||||
$lastChecked = new DateTime('now', new DateTimeZone('GMT'));
|
|
||||||
|
|
||||||
if ($data['status'] !== 200 && $data['status'] !== 304) {
|
|
||||||
// If this was not a success, set the error message and return
|
|
||||||
$this->h5pF->setErrorMessage(
|
|
||||||
$this->h5pF->t('No metadata was received from the H5P Hub. Please try again later.')
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update timestamp
|
|
||||||
$this->h5pF->setContentHubMetadataChecked($lastChecked->getTimestamp(), $lang);
|
|
||||||
|
|
||||||
// Not modified
|
|
||||||
if ($data['status'] === 304) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$this->h5pF->replaceContentHubMetadataCache($data['data'], $lang);
|
|
||||||
// TODO: If 200 should we have checked if it decodes? Or 'success'? Not sure if necessary though
|
|
||||||
return $data['data'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get updated content hub metadata cache
|
|
||||||
*
|
|
||||||
* @param string $lang Language as ISO 639-1 code
|
|
||||||
*
|
|
||||||
* @return JsonSerializable|string
|
|
||||||
*/
|
|
||||||
public function getUpdatedContentHubMetadataCache($lang = 'en') {
|
|
||||||
$lastUpdate = $this->h5pF->getContentHubMetadataChecked($lang);
|
|
||||||
if (!$lastUpdate) {
|
|
||||||
return $this->updateContentHubMetadataCache($lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
$lastUpdate = new DateTime($lastUpdate);
|
|
||||||
$expirationTime = $lastUpdate->getTimestamp() + (60 * 60 * 24); // Check once per day
|
|
||||||
if (time() > $expirationTime) {
|
|
||||||
$update = $this->updateContentHubMetadataCache($lang);
|
|
||||||
if (!empty($update)) {
|
|
||||||
return $update;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$storedCache = $this->h5pF->getContentHubMetadataCache($lang);
|
|
||||||
if (!$storedCache) {
|
|
||||||
// We don't have the value stored for some reason, reset last update and re-fetch
|
|
||||||
$this->h5pF->setContentHubMetadataChecked(null, $lang);
|
|
||||||
return $this->updateContentHubMetadataCache($lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $storedCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current server setup is valid and set error messages
|
* Check if the current server setup is valid and set error messages
|
||||||
*
|
*
|
||||||
|
@ -3633,241 +3505,8 @@ class H5PCore {
|
||||||
'offlineDialogRetryMessage' => $this->h5pF->t('Retrying in :num....'),
|
'offlineDialogRetryMessage' => $this->h5pF->t('Retrying in :num....'),
|
||||||
'offlineDialogRetryButtonLabel' => $this->h5pF->t('Retry now'),
|
'offlineDialogRetryButtonLabel' => $this->h5pF->t('Retry now'),
|
||||||
'offlineSuccessfulSubmit' => $this->h5pF->t('Successfully submitted results.'),
|
'offlineSuccessfulSubmit' => $this->h5pF->t('Successfully submitted results.'),
|
||||||
'mainTitle' => $this->h5pF->t('Sharing <strong>:title</strong>'),
|
|
||||||
'cancel' => $this->h5pF->t('Cancel'),
|
|
||||||
'back' => $this->h5pF->t('Back'),
|
|
||||||
'next' => $this->h5pF->t('Next'),
|
|
||||||
'reviewInfo' => $this->h5pF->t('Review info'),
|
|
||||||
'share' => $this->h5pF->t('Share'),
|
|
||||||
'close' => $this->h5pF->t('Close'),
|
|
||||||
'registerOnHub' => $this->h5pF->t('Register on the Hub'),
|
|
||||||
'requiredInfo' => $this->h5pF->t('Required Info'),
|
|
||||||
'optionalInfo' => $this->h5pF->t('Optional Info'),
|
|
||||||
'reviewAndShare' => $this->h5pF->t('Review & Share'),
|
|
||||||
'shared' => $this->h5pF->t('Shared'),
|
|
||||||
'currentStep' => $this->h5pF->t('Step :step of :total'),
|
|
||||||
'sharingNote' => $this->h5pF->t('All content details can be edited after sharing'),
|
|
||||||
'licenseDescription' => $this->h5pF->t('Select a license for your content'),
|
|
||||||
'licenseVersion' => $this->h5pF->t('License Version'),
|
|
||||||
'licenseVersionDescription' => $this->h5pF->t('Select a license version'),
|
|
||||||
'disciplineLabel' => $this->h5pF->t('Disciplines'),
|
|
||||||
'disciplineDescription' => $this->h5pF->t('You can select multiple disciplines'),
|
|
||||||
'discipline' => array(
|
|
||||||
'searchPlaceholder' => $this->h5pF->t('Select one or more disciplines'),
|
|
||||||
'in' => $this->h5pF->t('in'),
|
|
||||||
'dropdownButton' => $this->h5pF->t('Dropdown button'),
|
|
||||||
),
|
|
||||||
'removeChip' => $this->h5pF->t('Remove :chip from the list'),
|
|
||||||
'keywordsPlaceholder' => $this->h5pF->t('Add keywords'),
|
|
||||||
'keywords' => $this->h5pF->t('Keywords'),
|
|
||||||
'keywordsDescription' => $this->h5pF->t('You can add multiple keywords. Press "Enter" to confirm each keyword'),
|
|
||||||
'altText' => $this->h5pF->t('Alt text'),
|
|
||||||
'reviewMessage' => $this->h5pF->t('Please review the info below before you share'),
|
|
||||||
'subContentWarning' => $this->h5pF->t('Sub-content (images, questions etc.) will be shared under :license unless otherwise specified in the authoring tool'),
|
|
||||||
'title' => $this->h5pF->t('Title'),
|
|
||||||
'license' => $this->h5pF->t('License'),
|
|
||||||
'disciplines' => $this->h5pF->t('Disciplines'),
|
|
||||||
'shortDescription' => $this->h5pF->t('Short description'),
|
|
||||||
'longDescription' => $this->h5pF->t('Long description'),
|
|
||||||
'icon' => $this->h5pF->t('Icon'),
|
|
||||||
'screenshots' => $this->h5pF->t('Screenshots'),
|
|
||||||
'helpChoosingLicense' => $this->h5pF->t('Help me choose a license'),
|
|
||||||
'shareFailed' => $this->h5pF->t('Share failed.'),
|
|
||||||
'shareTryAgain' => $this->h5pF->t('Something went wrong, please try to share agian.'),
|
|
||||||
'pleaseWait' => $this->h5pF->t('Please wait...'),
|
|
||||||
'language' => $this->h5pF->t('Language'),
|
|
||||||
'level' => $this->h5pF->t('Level'),
|
|
||||||
'shortDescriptionPlaceholder' => $this->h5pF->t('Short description of your content'),
|
|
||||||
'longDescriptionPlaceholder' => $this->h5pF->t('Long description of your content'),
|
|
||||||
'description' => $this->h5pF->t('Description'),
|
|
||||||
'iconDescription' => $this->h5pF->t('640x480px. If not selected content will use category icon'),
|
|
||||||
'screenshotsDescription' => $this->h5pF->t('Add up to five screenshots of your content'),
|
|
||||||
'submitted' => $this->h5pF->t('Submitted!'),
|
|
||||||
'isNowSubmitted' => $this->h5pF->t('Is now submitted to H5P Hub'),
|
|
||||||
'contentAvailable' => $this->h5pF->t('Your content will soon be available for download'),
|
|
||||||
'contentLicenseTitle' => $this->h5pF->t('Content License Info'),
|
|
||||||
'licenseDialogDescription' => $this->h5pF->t('Click on a specific license to get info about proper usage'),
|
|
||||||
'publisherFieldTitle' => $this->h5pF->t('Publisher'),
|
|
||||||
'publisherFieldDescription' => $this->h5pF->t('This will display as the "Publisher name" on shared content'),
|
|
||||||
'emailAddress' => $this->h5pF->t('Email Address'),
|
|
||||||
'publisherDescription' => $this->h5pF->t('Publisher description'),
|
|
||||||
'publisherDescriptionText' => $this->h5pF->t('This will be displayed under "Publisher info" on shared content'),
|
|
||||||
'contactPerson' => $this->h5pF->t('Contact Person'),
|
|
||||||
'phone' => $this->h5pF->t('Phone'),
|
|
||||||
'address' => $this->h5pF->t('Address'),
|
|
||||||
'city' => $this->h5pF->t('City'),
|
|
||||||
'zip' => $this->h5pF->t('Zip'),
|
|
||||||
'country' => $this->h5pF->t('Country'),
|
|
||||||
'logoUploadText' => $this->h5pF->t('Organization logo or avatar'),
|
|
||||||
'acceptTerms' => $this->h5pF->t('I accept the terms of the license agreement'),
|
|
||||||
'successfullyRegistred' => $this->h5pF->t('You have successfully registered an account on the H5P Hub'),
|
|
||||||
'successfullyRegistredDescription' => $this->h5pF->t('You account details can be changed'),
|
|
||||||
'accountDetailsLinkText' => $this->h5pF->t('here'),
|
|
||||||
'registrationTitle' => $this->h5pF->t('Hub Registration and End User License Agreement (EULA)'),
|
|
||||||
'registrationFailed' => $this->h5pF->t('An error occured'),
|
|
||||||
'registrationFailedDescription' => $this->h5pF->t('We were not able to create an account at this point. Something went wrong. Try again later.'),
|
|
||||||
'maxLength' => $this->h5pF->t(':length is the maximum number of characters'),
|
|
||||||
'keywordExists' => $this->h5pF->t('Keyword already exists!'),
|
|
||||||
'licenseDetails' => $this->h5pF->t('License details'),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Publish content on the H5P Hub.
|
|
||||||
*
|
|
||||||
* @param array $data Data from content publishing process
|
|
||||||
* @param array $files Files to upload with the content publish
|
|
||||||
* @return stdClass
|
|
||||||
*/
|
|
||||||
public function hubPublishContent($data, $files) {
|
|
||||||
$headers = array(
|
|
||||||
'Authorization' => $this->hubGetAuthorizationHeader(),
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
);
|
|
||||||
|
|
||||||
$response = $this->h5pF->fetchExternalData(
|
|
||||||
H5PHubEndpoints::createURL(H5PHubEndpoints::CONTENT),
|
|
||||||
$data, TRUE, NULL, TRUE, $headers, $files
|
|
||||||
);
|
|
||||||
|
|
||||||
if (empty($response['data'])) {
|
|
||||||
throw new Exception($this->h5pF->t('Unable to authorize with the H5P Hub. Please check your Hub registration and connection.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = json_decode($response['data']);
|
|
||||||
if (isset($result->success) && $result->success === TRUE) {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
elseif (!empty($result->errors)) {
|
|
||||||
// Relay any error messages
|
|
||||||
$e = new Exception($this->h5pF->t('Validation failed.'));
|
|
||||||
$e->errors = $result->errors;
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the authorization header needed to access the private parts of
|
|
||||||
* the H5P Hub.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function hubGetAuthorizationHeader() {
|
|
||||||
$site_uuid = $this->h5pF->getOption('site_uuid', '');
|
|
||||||
$hub_secret = $this->h5pF->getOption('hub_secret', '');
|
|
||||||
if (empty($site_uuid)) {
|
|
||||||
throw new Exception($this->h5pF->t('Missing Site UUID. Please check your Hub registration.'));
|
|
||||||
}
|
|
||||||
if (empty($hub_secret)) {
|
|
||||||
throw new Exception($this->h5pF->t('Missing Hub Secret. Please check your Hub registration.'));
|
|
||||||
}
|
|
||||||
return 'Basic ' . base64_encode("$site_uuid:$hub_secret");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpublish content from content hub
|
|
||||||
*
|
|
||||||
* @param integer $hubId Content hub id
|
|
||||||
* @param string $token CSRF token
|
|
||||||
*
|
|
||||||
* @return bool True if successful
|
|
||||||
*/
|
|
||||||
public function hubUnpublishContent($hubId, $token) {
|
|
||||||
if (!self::validToken('content_hub_token', $token)) {
|
|
||||||
$msg = $this->h5pF->t('Could not unpublish content because token was invalid. Please try again.');
|
|
||||||
$this->h5pF->setErrorMessage($msg);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
'Authorization' => $this->hubGetAuthorizationHeader(),
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
);
|
|
||||||
|
|
||||||
$url = H5PHubEndpoints::createURL(H5PHubEndpoints::CONTENT);
|
|
||||||
$response = $this->h5pF->fetchExternalData("{$url}/{$hubId}", array(
|
|
||||||
'published' => '0',
|
|
||||||
), true, null, true, $headers, array(), 'PUT');
|
|
||||||
|
|
||||||
// Remove shared status if successful
|
|
||||||
if (!empty($response) && $response['status'] === 200) {
|
|
||||||
$msg = $this->h5pF->t('Content successfully unpublished');
|
|
||||||
$this->h5pF->setInfoMessage($msg);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$msg = $this->h5pF->t('Content unpublish failed');
|
|
||||||
$this->h5pF->setErrorMessage($msg);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync content with content hub
|
|
||||||
*
|
|
||||||
* @param integer $hubId Content hub id
|
|
||||||
* @param string $token CSRF token
|
|
||||||
* @param string $exportPath Export path where .h5p for content can be found
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hubSyncContent($hubId, $token, $exportPath) {
|
|
||||||
if (!self::validToken('content_hub_token', $token)) {
|
|
||||||
$msg = $this->h5pF->t('Could not sync content because token was invalid. Please try again.');
|
|
||||||
$this->h5pF->setErrorMessage($msg);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
'Authorization' => $this->hubGetAuthorizationHeader(),
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
);
|
|
||||||
|
|
||||||
$url = H5PHubEndpoints::createURL(H5PHubEndpoints::CONTENT);
|
|
||||||
$response = $this->h5pF->fetchExternalData("{$url}/{$hubId}", array(
|
|
||||||
'download_url' => $exportPath,
|
|
||||||
), true, null, true, $headers, array(), 'PUT');
|
|
||||||
|
|
||||||
if (!empty($response) && $response['status'] === 200) {
|
|
||||||
$msg = $this->h5pF->t('Content sync queued');
|
|
||||||
$this->h5pF->setInfoMessage($msg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$msg = $this->h5pF->t('Content sync failed');
|
|
||||||
$this->h5pF->setErrorMessage($msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch account info for our site from the content hub
|
|
||||||
*
|
|
||||||
* @return array|bool|string False if account is not setup, otherwise data
|
|
||||||
*/
|
|
||||||
public function hubAccountInfo() {
|
|
||||||
$siteUuid = $this->h5pF->getOption('site_uuid', null);
|
|
||||||
$secret = $this->h5pF->getOption('hub_secret', null);
|
|
||||||
if (empty($siteUuid) || empty($secret)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
'Authorization' => $this->hubGetAuthorizationHeader(),
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
);
|
|
||||||
|
|
||||||
$url = H5PHubEndpoints::createURL(H5PHubEndpoints::REGISTER);
|
|
||||||
$accountInfo = $this->h5pF->fetchExternalData("{$url}/{$siteUuid}",
|
|
||||||
null, true, null, true, $headers, array(), 'GET');
|
|
||||||
|
|
||||||
if ($accountInfo['status'] !== 200) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_decode($accountInfo['data'])->data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue