Skip to content

Commit

Permalink
feat(editor and player): addons and library management
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The ILibraryStorage and IContentStorage interfaces have new methods that are needed for complete library management functionality. 
There are new language strings.
The configuration was extended to cater for addon configuration.
There is a new REST endpoint adapter for Express for library administration functionality. Implementation should either add the Express router (and protect it from unauthorized access!) or offer their own REST endpoint.
The example now includes React components that speak with the library administration REST endpoint. Implementations can use or extend the example components.
Updating content was broken and is now fixed.
  • Loading branch information
sr258 authored Jun 29, 2020
1 parent 41556f5 commit 3e61915
Show file tree
Hide file tree
Showing 51 changed files with 3,052 additions and 191 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ The Express adapter already catches errors, localizes them and returns proper HT

This library supports localization. See the [respective documentation page](/docs/localization.md) for more details.

### Customization

An application using h5p-nodejs-library can customize the way H5P behaves in several ways. See [the documentation page on customization](/docs/customization.md) for more details.

## Development & Testing

### Prerequisites
Expand Down Expand Up @@ -178,12 +182,12 @@ npm test

### Debugging

The library emits log messages with [debug](https://www.npmjs.com/package/debug). To see those messages you have to set the environment variable `DEBUG` to `h5p:*`. There are several log levels. By default you'll only see the messages sent with the level `info`. To get the verbose log, set the environment variable `LOG_LEVEL` to verbose (mind the capitalization).
The library emits log messages with [debug](https://www.npmjs.com/package/debug). To see those messages you have to set the environment variable `DEBUG` to `h5p:*`. There are several log levels. By default you'll only see the messages sent with the level `info`. To get the verbose log, set the environment variable `LOG_LEVEL` to debug (mind the capitalization).

Example (for Linux):

```sh
DEBUG=h5p:* LOG_LEVEL=verbose node script.js
DEBUG=h5p:* LOG_LEVEL=debug node script.js
```

### Other scripts
Expand Down
6 changes: 4 additions & 2 deletions assets/translations/server/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@
"invalid-library-json-file": "Could not find library.json file with valid json format for library {{name}}",
"invalid-library-name": "Invalid library name: {{name}}",
"invalid-main-library-name": "mainLibraryName is invalid: {{message}}",
"invalid-patch-request": "The request to modify a library was malformed.",
"invalid-schema-library-json-file": "The library.json file of the library {{name}} is invalid ({{reason}})",
"invalid-semantics-json-file": "Invalid semantics.json file has been included in the library {{name}}",
"invalid-ubername-pattern": "'{{name}}' is not a valid H5P library name (\"ubername\"). You must follow this pattern: {{example}}'",
"library-consistency-check-file-missing": "Missing files in library {{name}}: {{files}}",
"library-consistency-check-library-json-unreadable": "Error in library {{name}}: library.json not readable: {{message}}",
"library-consistency-check-not-installed": "Can't check library consistency for {{name}} as the library is not installed.",
"library-directory-name-mismatch": "Library directory name must match machineName or machineName-majorVersion.minorVersion (from library.json). (Directory: {{directoryName}} , machineName: {{machineName}}, majorVersion: {{majorVersion}}, minorVersion: {{minorVersion}})",
"library-file-missing": "The requested library file {{filename}} of library {{library}} does not exist.",
"library-missing-file": "The file "{{file}}" is missing from library: "{{name}}"",
"library-file-missing": "The library file {{filename}} of library {{library}} does not exist.",
"library-missing": "The library {{library}} is not installed on this system.",
"library-not-found": "Library {{name}} was not found.",
"library-used": "The library {{library}} cannot be deleted as it is still in use.",
"malformed-request": "The request sent by the client is malformed: {{error}}",
"missing-h5p-extension": "The file you uploaded is not a valid HTML5 Package (It does not have the .h5p file extension)",
"not-in-whitelist": "File "{{filename}}" not allowed. Only files with the following extensions are allowed: {{files-allowed}}.",
Expand Down
19 changes: 10 additions & 9 deletions assets/translations/storage-file-implementations/en.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"error-generating-unique-temporary-filename": "Cannot determine a unique filename for {{name}}",
"temporary-file-not-found": "The file {{filename}} is not accessible for user {{userId}} or does not exist.",
"add-file-content-not-found": "Cannot add file {{filename}} to content with id {{id}}: Content with does not exist.",
"add-library-file-not-installed": "Can't add {{filename}} to library {{libraryName}} because the library has not been installed.",
"clear-library-not-found": "Can't clear library {{libraryName}} because the library has not been installed.",
"delete-content-file-not-found": "Cannot delete file {{filename}}: It does not exist.",
"delete-content-not-found": "Cannot delete content: It does not exist.",
"error-creating-content": "Could not create content.",
"error-generating-content-id": "Could not generate id for new content.",
"delete-content-not-found": "Cannot delete content: It does not exist.",
"delete-content-file-not-found": "Cannot delete file {{filename}}: It does not exist.",
"add-library-file-not-installed": "Can't add {{filename}} to library {{libraryName}} because the library has not been installed.",
"error-generating-unique-temporary-filename": "Cannot determine a unique filename for {{name}}",
"error-updating-metadata": "The additional metadata of the library {{library}} cannot be updated. Error: {{error}}",
"get-library-metadata-not-installed": "Can't get metadata for library {{libraryName}} because the library has not been installed.",
"clear-library-not-found": "Can't clear library {{libraryName}} because the library has not been installed.",
"illegal-absolute-filename": "Absolute paths in filenames are not allowed: {{filename}} is illegal",
"illegal-relative-filename": "Relative paths in filenames are not allowed: {{filename}} is illegal",
"install-library-already-installed": "Library {{libraryName}} has already been installed.",
"remove-library-library-missing": "Library {{libraryName}} is not installed on the system.",
"update-library-library-missing": "Library {{libraryName}} can't be updated as it hasn't been installed yet.",
"illegal-relative-filename": "Relative paths in filenames are not allowed: {{filename}} is illegal",
"illegal-absolute-filename": "Absolute paths in filenames are not allowed: {{filename}} is illegal"
"temporary-file-not-found": "The file {{filename}} is not accessible for user {{userId}} or does not exist.",
"update-library-library-missing": "Library {{libraryName}} can't be updated as it hasn't been installed yet."
}
176 changes: 176 additions & 0 deletions docs/addons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Addons

Addons are H5P libraries that can be added to the H5P Editor or to certain H5P
content without changing the content itself or the content type. They are a
little-known feature of the H5P core and currently the only publicly known
example of an addon is the [H5P.MathDisplay addon](https://h5p.org/mathematical-expressions),
which uses MathJax to display mathematical formulas. Addons provide a simple and
reusable way of customizing behavior and looks of H5P content types. This allows
site administrators to customize H5P without programming knowledge or the need
to fork content types.

## Using addons (for site administrators)

To use an addon on your site, you must upload the addon file through the library
management site. You **cannot** upload addons in the normal way you would upload
a H5P package with content, as the .h5p files of addons don't contain any
content and won't pass validation!

Depending on the configuration of the addon and your server, the addon will now
be automatically loaded in certain situations. As the only addon currently is
H5P.MathDisplay, the procedure of getting addons to load will be explained with
it below:

**Player:** The MathDisplay addon will automatically be used in the player
whenever needed, as the server scans content for a search string specified by
the addon. You can also force the use of addons by setting the configuration
property `playerAddons` of your configuration:

```JSON
{
// ... further configuration values ...
"playerAddons": {
"H5P.CoursePresentation": ["H5P.MathDisplay"]
}
// ... further configuration values ...
}
```

**Editor:** The MathDisplay addon will **not** be automatically enabled in the
editor. There are two ways to enable it:

1. Use a custom H5P.MathDisplay addon, that uses a h5p-nodejs-library
extension to avoid the server-wide configuration below.
2. Set the configuration property `editorAddons` in your implementation of
`IH5PConfig` to something like:

```JSON
{
// ... further configuration values ...
"editorAddons": {
"H5P.CoursePresentation": [ "H5P.MathDisplay" ],
"H5P.InteractiveVideo": [ "H5P.MathDisplay" ],
"H5P.DragQuestion": [ "H5P.MathDisplay" ]
}
// ... further configuration values ...
}
```

Now the editor will load the H5P.MathDisplay library if a user opens the
editor of one these three content types (these are the three content types
for which the PHP implementation also loads addons).

## Customizing addon behavior

Addons can be configured by setting the property `libraryConfig` of your
configuration implementation of `IH5PConfig`. The property is a complex object
with H5P library machine names as keys. The object is sent to the H5P client
(run in the browser) as part of the H5PIntegration object and can be accessed
in a H5P library by calling `H5P.getLibraryConfig('H5P.MachineName')`.

Example (shows how to (optionally) configure the [H5P.MathDisplay addon](https://h5p.org/mathematical-expressions)):

```JSON
"libraryConfig": {
"H5P.MathDisplay": {
"observers": [
{ "name": "mutationObserver", "params": { "cooldown": 500 } },
{ "name": "domChangedListener" },
{ "name": "interval", "params": { "time": 1000 } }
],
"renderer": {
"mathjax": {
"src": "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js",
"config": {
"extensions": ["tex2jax.js"],
"jax": ["input/TeX", "output/HTML-CSS"],
"tex2jax": {
"ignoreClass": "ckeditor",
"processEscapes": true
},
"messageStyle": "none"
}
}
}
}
}

```

## Creating addons (for developers)

Addons also use the .h5p file extension but don't have the same structure as
regular h5p packages: they only contain folders with libraries and no `h5p.json`
file or content. The library folders are basically like regular H5P libraries,
as they contain a `library.json` file, but they can't contain `semantics.json`.
The metadata in `library.json` is mostly the same as the metadata of normal
libraries, but it contains the property `addTo`, which makes a library to
an addon. (Check out the comprehensive structure of library metadata in the
TypeScript interface `ILibraryMetadata` in [`/src/types.ts`](/src/types.ts).)

A library containing the property `addTo` in its metadata will be automatically
added to the player (or editor) by the server in certain circumstances:

- Always when loading the editor, if set in the global configuration of the
server (see above).
- When playing content, only if the content contains a regex search string.
The search string is set by setting this property:
```JSON
{
// ... more metadata ...
"addTo": {
"content": {
"types": [
{
"text": {
"regex": "/your regex string/" // the regex string must start and end with a slash!
}
}
]
}
}
// ... more metadata ...
}
```
The configuration above means that the addon is added to every player
instance if the regex is matched in any `string` property of the content
parameters.
- Always when loading the editor if requested in the metadata like this:

```JSON
{
// ... more metadata ...
"addTo": {
"editor": [ "H5P.CoursePresentation", "H5P.InteractiveVideo" ]
}
// ... more metadata ...
}
```

_Note that this way of enabling addons in the editor is a custom
h5p-nodejs-library extension of the library metadata structure and is
**not** supported by the PHP implementation and might change in the future
if this feature is implemented by Joubel's PHP implementation in another
way._

- Always when loading the play if requested in the metadata like this:

```JSON
{
// ... more metadata ...
"addTo": {
"player": [ "H5P.CoursePresentation", "H5P.InteractiveVideo" ]
}
// ... more metadata ...
}
```

_Note that this way of enabling addons in the player is a custom
h5p-nodejs-library extension of the library metadata structure and is
**not** supported by the PHP implementation and might change in the future
if this feature is implemented by Joubel's PHP implementation in another
way._

When an addon is loaded in the editor or the player, the JavaScript and CSS
files listed at `preloadedJs` and `preloadedCss` are loaded in the HTML file
after the actual library is loaded.
28 changes: 28 additions & 0 deletions docs/customization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Customization

An application using h5p-nodejs-library can customize the way H5P behaves in
several ways:

- You can add custom JavaScript to the player by passing their URL to the
constructor of `H5PPlayer`. See below for details.
- You can upload addons. See the [addon documentation page](addons.md) for
details.

## Adding custom scripts to the player

You can add custom scripts to the player by passing their URLs to the
constructor of `H5PPlayer`:

```ts
const player = new H5PPlayer(
libraryStorage,
contentStorage,
config,
integrationObjectDefaults,
[ '/url/of/script/1.js', 'https://example.com/external/script.js' ]
);
)
```

These scripts will then be added to the end of the list of H5P scripts that are
loaded for the player.
10 changes: 7 additions & 3 deletions docs/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,26 @@ implemented and what isn't.
- [x] validation of packages (structural integrity and conformity of content and libraries)
- [x] offers downloads for h5p packages ("exporting" content)
- [x] support for copy & paste in the editor
- [x] support for editor interface languages other than English
- [x] addons (required to display mathematical formulas)
- [x] MongoDB and S3 storage implementation for content and temporary files
- [x] library administration endpoint and React UI component

## Unfinished functionality

- [ ] storing user state in the player (for continuing later where the user left off)
- [ ] support for an editor interface language other than English
- [ ] validation of content against library semantics (+ filter html to prevent cross-site-scripting (XSS) vulnerabilities.)
- [ ] manage and check editor tokens (to make sure you have access rights to a session) (might never be implemented, as this is something the implementation should check)
- [ ] logging & statistics generation: e.g. use of libraries by author, view of embedded content etc. (see h5p-php-library:h5p-event-base.class.php for a list of events)
- [ ] alter library files, semantics (allows site admins to change libraries without hacking the actual files; very useful)
- [ ] provide embed option for content (as div and as iframe)
- [ ] admin site / functionality (settings? +library management (what libraries of which version are installed & used how often; add libraries manually, update content of a specific library version))
- [ ] (**only partly supported**) check permissions of users (install libraries, download h5p package, embed h5p package, create restricted, update libraries, install recommended, copy h5p?)
- [ ] cache assets (aggregates all css and js files into two big files to decrease http requests; done in h5p-php-library:h5p-default-storage.class.php->cacheAssets(...))
- [ ] logging and statistics (there is a debug logger, but not one that allows you to log domain events)
- [ ] functionality to alter library files and semantics with extensions
- [ ] mass content updates
- [ ] catch and relay xAPI statements
- [ ] option to disable H5P Hub
- [ ] security review
- [ ] performance optimizations
- [ ] MongoDB and S3 storage implementation for libraries
- [ ] Redis cache for caching
Loading

0 comments on commit 3e61915

Please sign in to comment.