-
-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* test(jest): run jest tests in watch mode via test:watch * chore(scripts): add start:rest script * feat(contentUserData): add parameters to contentUserDataUrl config * feat(contentUserData): read saveFreq from config * feat(contentUserData): add the contentUserData into the H5PIntegration * test(contentUserDataGET): add example for GET issue #1014 (comment) * test(contentUserData): revert example * chore(scripts): add h5p-server build script * test(launch): add DEBUG to vscode launch * refactor(script): rename start:rest to start:rest:server #1886 (comment) * refactor(saveFreq): rename saveFreq to contentUserStateSaveInterval #1886 (comment) * feat(contentUserData): delete contentUserData when content is deleted * test(contentUserData): use mock for H5PPlayer.render test * refactor(h5p-examples): add mock implementation to pass build * feat(contentUserData): build contentUserDataIntegration in Manager * feat(contentUserData): update interfaces * test(contentUserDataManager): add tests * refactor(h5p-examples): remove test/example conentUserDataStorage * refactor(saveContentUserData): add invalidate and preload parameters * feat(h5p-express): add ContentUserDataController * fix(contentManager): delete contentUserDataStorage after content #1886 (comment) * refactor(ContentUserDataManager): remove unnecessary code * refactor(ContentUserDataManager): use boolean instead of number #1886 (comment) * refactor(ContentManager): remove unnecessary code * refactor(ContentUserDataManager): use boolean instead of number #1886 (comment) * fix(ContentUserDataManager): sanitize userState before saving * feat(h5pexpress): add ContentUserDataRouter * refactor(h5p-server): add deleteAllContentUserDataforContentId method * refactor(h5p-examples): add reference implementation to h5p-example * docs(ContentUserDataStorage): add contentUserDataStorage docs * feat(contentUserData): add setFinished * fix(ContentUserDataManager): throw H5pError instead of regular error * fix(contentUserStateSaveInterval): change from seconds to milliseconds #1886 (comment) * refactor(code): remove redundant return statements * refactor(code): reorder import statements * refactor(log): change to debug from info * refactor(code): remove typos, reorder imports, remove redundant code * refactor(h5p-examples): don't use singleton * fix(H5PPlayer): use contentUserStateSaveInterval in milliseconds * refactor(code): fix typos * fix(contentUserDataManager): saveContentUserData: check arguments * fix(h5p-examples): correct json number declaration (#1991) * feat(listContentUserDataByUserId): add listContentUserDataByUserId * style(jsdocs): add divergence * refactor: formatting and minor issues * refactor: fixed imports * test: corrected test * refactor: decreased content user state save interval * test: fix test * fix(contentUserDataManager): remove userData when invalidate is true #1886 (comment) * fix(contentUserData): generate integration only when preload is true #1886 (comment) * feat(FileContentUserDataStorage): add FileContentUserDataStorage * feat(contentUserData): include contentUserData in rest-example * feat(contentUserData): include in rest example * test(contentUserDataRouter): fix test * chore(contentUserDataStorage): add json to gitignore * build(h5p-shared-state-server): build h5p-shared-state-server on install * fix(contentUserData): delete invalid contentUserData if content changes #1886 (comment) * refactor(contentUserData): rename saveContentUserData saveContentUserData-method is renamed to createOrUpdateContentUserData * feat(mongos3): add MongoContentUserDataStorage * refactor: made namings more consistent * refactor: minor cleanup * fix: examples work * test: use snapshot instead of inline HTML * feat: corrected and extended MongoContentUserDataStorage * fix: corrected FileContentUserDataStorage signature * test: added more tests * test: more tests * feat: delete finished data when content is deleted * feat: reimplemented FileContentUserDataStorage to work with directories * test: added tests for FileContentUserDataStorage * test: renamed generalized test file * fix: missing user data doesn't return 404 * fix: corrected CSFR token generation + own route for setFinished * fix: protected FileContentUserDataStorage against attacks * test: corrected tests * fix: corrected config to load falsy settings * fix: improved filename validation * feat: routes are closed when feature disabled in config * feat: added CSRF tokens to rest example & fixed bugs * fix: fileContentUserDataStorage saves more than one entry * test: corrected test * feat: improved CSRF * refactor: correct shared state example * refactor: cleanup * docs: added docs Co-authored-by: Oliver Tacke <[email protected]> Co-authored-by: Sebastian Rettig <[email protected]>
- Loading branch information
1 parent
5d9439c
commit bdf66da
Showing
53 changed files
with
4,071 additions
and
744 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,22 @@ | ||
{ | ||
"configurations": [ | ||
{ | ||
"command": "npm start", | ||
"name": "Run npm start", | ||
"request": "launch", | ||
"type": "node-terminal" | ||
} | ||
{ | ||
"command": "DEBUG=h5p:* npm start", | ||
"name": "Run npm start", | ||
"request": "launch", | ||
"type": "node-terminal" | ||
}, | ||
{ | ||
"type": "node", | ||
"request": "launch", | ||
"name": "Launch Program", | ||
"program": "${workspaceFolder}/packages/h5p-examples/build/express.js", | ||
"runtimeArgs": ["-r", "source-map-support/register"], | ||
"env": { | ||
"DEBUG": "h5p*" | ||
}, | ||
"outputCapture": "std", | ||
"console": "integratedTerminal" | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Completion tracking | ||
|
||
The H5P client is capable of sending a message to the server when the user has | ||
completed a content object. This includes the time when this occured, how long | ||
the content was open, the achieved score and the maximum score. | ||
|
||
While technically this message is derived from a xAPI statement generated by the | ||
content types, it **is not the same as xAPI** and is a completely separate | ||
system that co-exists with xAPI and a potential LRS. You can enable completion | ||
tracking and xAPI tracking indepedently. | ||
|
||
If you want to capture all xAPI statements, which allows you to have very | ||
detailed tracking, you either have to inject your own xAPI capturing JavaScript | ||
or use the xAPI capabilities of the `H5PPlayerComponent` in the [webcomponent | ||
package](../packages/h5p-webcomponents.md)) (or the corresponding functionality | ||
in the [React package](../packages/h5p-react.md)). | ||
|
||
## How it works | ||
|
||
- When the user presses "check", a xAPI statement indicating completion is | ||
generated by the content type (that supports it). The H5P client captures it | ||
and calls an AJAX route on the H5P server with basic information. | ||
- The H5P server saves the completion data in a special storage system. The | ||
server automatically deletes the data when the content object is deleted. | ||
|
||
## Limitations | ||
|
||
- While the storage classes support retrieving and deleting the completion data, | ||
there are no endpoints on the `h5p-express` package that implement this | ||
functionality. You have to implement these endpoints yourself. | ||
- Not all content types emit xAPI statements indicating completion and thus | ||
the tracking isn't fired. | ||
|
||
## Enabling completion tracking | ||
|
||
- Create an instance of `IContentUserDataStorage`. The recommended storage class | ||
for production is `MongoContentUserDataStorage` in the | ||
`@lumieducation/h5p-mongos3` package. There's also a | ||
`FileContentUserDataStorageClass` in the `@lumieducation/h5p-server` package | ||
that you can use for development or testing purposes. | ||
- Pass the implementation of IContentUserDataStorage into the `H5PEditor` and | ||
`H5PPlayer` constructor. | ||
- Set `setFinishedEnabled` in `IH5PConfig` to `true`. | ||
- If you use `h5pAjaxExpressRouter` from the `@lumieducation/h5p-express` | ||
package, then the routes for the AJAX endpoint are automatically created. You | ||
can manually turn them on by setting `routeFinishedData` in the options when | ||
creating the route. | ||
- If you don't use `h5pAjaxExpressRouter`, you have to route everything | ||
manually. First get `ContentUserDataManager` from `H5PEditor` or | ||
`H5PPlayer`. Route this endpoint and return HTTP status code 200 with a JSON | ||
object that is based on `AjaxSuccessResponse` with empty payload: | ||
- POST {{setFinishedUrl}}/ -> `ContentUserDataManager.setFinished` | ||
|
||
## Configuration options | ||
|
||
- You can customize the URL to which the AJAX calls are made by setting | ||
`setFinishedUrl` in `IH5PConfig`. | ||
- You can enable or disable the feature by setting `setFinishedEnabled` in | ||
IH5PConfig. | ||
|
||
## Security considerations | ||
|
||
You should implement CSRF tokens when using completion tracking as the POST | ||
endpoint would otherwise by vulnerable to CSRF attacks when using cookie | ||
authentication. The tokens are added to the endpoint URL in the IUrlGenerator | ||
implementation and thus sent to the server whenever a POST call is made. Check | ||
out the REST example on how to pass the CSRF token to the H5P server components | ||
and how to check its validity. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# User content state | ||
|
||
The H5P client is capable of saving the current state of the user so that the | ||
user can resume where they left off. This means that e.g. their attempts entered | ||
into textboxes are the same as when they last left off. | ||
|
||
## How it works | ||
|
||
- If state saving is enabled, a timer interval is set in the H5PIntegration | ||
object by the server | ||
- The H5P core client reads the interval and tells the content type that is | ||
currently being displayed to persist it's state into a JSON object | ||
- The H5P core client sends the state to an AJAX route on the server (specified | ||
in H5PIntegration). | ||
- The server stores the state in a special storage system. When content is | ||
deleted, the user state is deleted as well. When content is updated, the user | ||
state is deleted if the content type requests this (the case for (nearly?) all | ||
content types). | ||
- When the user later re-opens the content, the server checks if there is a user | ||
state for the user that should be "preloaded". This means that the initial | ||
information about the content object also includes the state and the client | ||
doesn't have to make a second request to get it. If the state is marked as | ||
"preloaded" (this is done by the content type), the content type uses it | ||
during it's initialization routine. | ||
- If "preloaded" is set to `false` the H5P client can also request the user | ||
state through an AJAX call from the server. | ||
- There can also be a user state in the editor. For instance, it saves whether | ||
the user has dismissed the tours of Interactive Video or has closed one of the | ||
yellow "information boxes" that explain functions of the editor. The editor | ||
always gets the state through a second AJAX call. | ||
|
||
## Limitations of the user state | ||
|
||
- Not all content types implement it. | ||
- Not all content types fully restore the state (e.g. they don't restore if the | ||
user has already pressed "checked"). | ||
|
||
## Enabling user state | ||
|
||
- Create an instance of `IContentUserDataStorage`. The recommended storage class | ||
for production is `MongoContentUserDataStorage` in the | ||
`@lumieducation/h5p-mongos3` package. There's also a | ||
`FileContentUserDataStorageClass` in the `@lumieducation/h5p-server` package | ||
that you can use for development or testing purposes. | ||
- Pass the implementation of IContentUserDataStorage into the `H5PEditor` and | ||
`H5PPlayer` constructor. | ||
- Set `contentUserStateSaveInterval` in `IH5PConfig` to the interval at which | ||
the client should save the state (in milliseconds). The recommended number is | ||
`10000`. (To disable the feature, set `contentUserStateSaveInterval` to | ||
`false`) | ||
- If you use `h5pAjaxExpressRouter` from the `@lumieducation/h5p-express` | ||
package, then the routes for the AJAX endpoint are automatically created. You | ||
can manually turn them on by setting `routeContentUserData` in the options | ||
when creating the route. | ||
- If you don't use `h5pAjaxExpressRouter`, you have to route everything | ||
manually. First get `ContentUserDataManager` from `H5PEditor` or `H5PPlayer`. | ||
Route these endpoints to the functions and return HTTP status code 200 with a | ||
JSON object that is based on `AjaxSuccessResponse` with empty payload (Check | ||
out the Express Router for details): | ||
- GET {{contentUserDataUrl}}/:contentId/:dataType/:subContentId -> | ||
`ContentUserDataManager.getContentUserData` | ||
- POST {{contentUserDataUrl}}/:contentId/:dataType/:subContentId -> | ||
`ContentUserDataManager.createOrUpdateContentUserData` | ||
|
||
## Configuration options | ||
|
||
- You can customize the URL at which the AJAX calls are available by setting | ||
`contentUserDataUrl` in `IH5PConfig`. | ||
- You can customize the interval at which content states are saved by setting | ||
`contentUserStateSaveInterval` in IH5PConfig. If you set it to false, you can | ||
disable the feature. | ||
|
||
## Security considerations | ||
|
||
You should implement CSRF tokens when using the content user state as the POST | ||
endpoint would otherwise by vulnerable to CSRF attacks when using cookie | ||
authentication. The tokens are added to the endpoint URL in the IUrlGenerator | ||
implementation and thus sent to the server whenever a POST call is made. Check | ||
out the REST example on how to pass the CSRF token to the H5P server components | ||
and how to check its validity. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.