Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

THR-18: dev feature h5p editor #2748

Merged
merged 72 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
ba2d4cf
Thr 12 h5p editor player (#2540)
MajedAlaitwniCap Jun 7, 2023
649802f
Merge remote-tracking branch 'origin/main' into THR-18-dev-feature-h5…
SteKrause Jun 7, 2023
b3967bc
Merge remote-tracking branch 'origin/main' into THR-18-dev-feature-h5…
marode-cap Jul 28, 2023
66f8f5a
Thr 20 create UI elements (#2577)
marode-cap Jul 31, 2023
89430dd
add script-src-elem to nginx config
SteKrause Aug 15, 2023
d160135
add H5P_IMG_SRC_URLS to nginx config
SteKrause Aug 15, 2023
2e3588e
THR-27: add language param to h5p endpoints (#2734)
SteKrause Aug 15, 2023
1ebd577
Merge branch 'main' into THR-41-adjust-csp-rule
SteKrause Aug 16, 2023
76dca89
Merge branch 'main' into THR-41-adjust-csp-rule
SteKrause Aug 17, 2023
ef52da5
Merge branch 'main' into THR-41-adjust-csp-rule
SteKrause Aug 18, 2023
bcfab1f
Merge remote-tracking branch 'origin/main' into THR-18-dev-feature-h5…
marode-cap Aug 21, 2023
461ecdf
Merge remote-tracking branch 'origin/main' into THR-18-dev-feature-h5…
marode-cap Aug 21, 2023
6ed2441
Merge branch 'main' into THR-41-adjust-csp-rule
SteKrause Aug 21, 2023
d85de98
Merge branch 'main' into THR-18-dev-feature-h5p-editor
SteKrause Aug 21, 2023
6999ae4
update h5p imports
SteKrause Aug 21, 2023
3ffa14e
Merge branch 'main' into THR-18-dev-feature-h5p-editor
SteKrause Aug 21, 2023
53b986e
Merge branch 'main' into THR-18-dev-feature-h5p-editor
SteKrause Aug 25, 2023
367a1a3
THR-6 H5P Editor authorization frontend changes (#2775)
marode-cap Aug 30, 2023
eb21fbe
Merge branch 'main' into THR-41-adjust-csp-rule
SteKrause Sep 1, 2023
04aeabe
add location h5p to csp rules
SteKrause Sep 1, 2023
8f53e94
copy second index.html for h5p location ins csp rules
SteKrause Sep 1, 2023
f8b00b8
Update Dockerfile
SteKrause Sep 1, 2023
5afef34
Update nginx.conf.template
SteKrause Sep 1, 2023
e91be9b
Merge branch 'main' into THR-41-adjust-csp-rule
SteKrause Sep 5, 2023
f45af6f
Merge branch 'THR-41-adjust-csp-rule' into THR-preview
ssmid Sep 12, 2023
184914f
Merge branch 'main' into THR-preview
ssmid Sep 18, 2023
7fb94a0
h5p editor: resolve overseen merge conflict termsofuse
ssmid Sep 18, 2023
f4f16c8
Merge branch 'main' into THR-18-dev-feature-h5p-editor
SteKrause Sep 29, 2023
aad8000
delete deprecated code from nuxt removal
SteKrause Sep 29, 2023
5d50cf4
h5p editor: csp: remove unsafe inline
ssmid Sep 29, 2023
ef4efb7
Merge remote-tracking branch 'origin/main' into THR-18-dev-feature-h5…
casparneumann-cap Oct 5, 2023
8855078
Merge branch 'main' into THR-18-dev-feature-h5p-editor
casparneumann-cap Oct 9, 2023
284bd91
fix prettier problem
casparneumann-cap Oct 10, 2023
e2bf82e
fix duplicate imports
casparneumann-cap Oct 10, 2023
aecdd65
csp error isolation: set default-src *
casparneumann-cap Oct 11, 2023
92421cf
csp error isolation: revert and add unsafe-inline for script-src
casparneumann-cap Oct 11, 2023
5e55aed
csp error isolation: set script-src *
casparneumann-cap Oct 11, 2023
0c948b1
csp error isolation: no whitelist used
casparneumann-cap Oct 11, 2023
2cc79ff
csp error isolation: set again default-src *
casparneumann-cap Oct 11, 2023
775bd31
csp error isolation: set script-src * + unsafe inline & eval
casparneumann-cap Oct 12, 2023
1121b6f
csp error isolation: set back to original
casparneumann-cap Oct 12, 2023
51b19c7
csp error isolation: use hash for multiple choice
casparneumann-cap Oct 12, 2023
35e299f
generate API
MajedAlaitwniCap Oct 12, 2023
377287c
csp error isolation: exclude nonce & use unsafe-inline
casparneumann-cap Oct 12, 2023
3064a27
Merge branch 'main' into THR-preview
MajedAlaitwniCap Oct 12, 2023
6fc978e
Merge branch 'main' into THR-18-dev-feature-h5p-editor
MajedAlaitwniCap Oct 13, 2023
7448744
Merge branch 'THR-preview' of https://github.com/hpi-schul-cloud/nuxt…
MajedAlaitwniCap Oct 13, 2023
e7c32e5
disable eslint
casparneumann-cap Oct 13, 2023
ccd39e4
Update API
marode-cap Oct 13, 2023
6fdb6ed
Merge branch 'THR-18-dev-feature-h5p-editor' of github.com:hpi-schul-…
marode-cap Oct 13, 2023
d4e9934
Merge branch 'main' into THR-18-dev-feature-h5p-editor
casparneumann-cap Oct 18, 2023
ea1ef7e
Merge branch 'main' of https://github.com/hpi-schul-cloud/nuxt-client…
MajedAlaitwniCap Oct 26, 2023
511d684
resolve review comments
MajedAlaitwniCap Oct 26, 2023
20e3c89
add es / uk languages
MajedAlaitwniCap Oct 27, 2023
bbc830d
Merge branch 'main' into THR-18-dev-feature-h5p-editor
MajedAlaitwniCap Nov 1, 2023
c81c696
Merge branch 'main' into THR-18-dev-feature-h5p-editor
MajedAlaitwniCap Nov 6, 2023
fcdf3fe
Merge branch 'main' into THR-18-dev-feature-h5p-editor
CeEv Nov 6, 2023
95aa16c
try nginx.template h5p fix
casparneumann-cap Nov 7, 2023
60cd398
revert nginx.conf h5p change
casparneumann-cap Nov 7, 2023
1008e2c
Comment Out H5P CSP
casparneumann-cap Nov 7, 2023
37a7954
Revert "Comment Out H5P CSP"
casparneumann-cap Nov 8, 2023
2d74c1b
Merge branch 'main' into THR-18-dev-feature-h5p-editor
casparneumann-cap Nov 14, 2023
9376bb9
H5pEditor Tests -> Setup Wrapper
casparneumann-cap Nov 15, 2023
88bcf59
initial test for verifying component setup
casparneumann-cap Nov 15, 2023
6d2c1c3
add test H5pPlayer
casparneumann-cap Nov 15, 2023
e9a1f6d
restructure H5pEditor Test
casparneumann-cap Nov 15, 2023
67b21e9
Create H5PEditor.page Test
casparneumann-cap Nov 15, 2023
119d6a1
fix routes
casparneumann-cap Nov 15, 2023
03a7731
Create Test H5pPlayerPage
casparneumann-cap Nov 15, 2023
0a374de
fix tests h5pPlayerPage
casparneumann-cap Nov 15, 2023
1c5f176
Merge branch 'main' into THR-18-dev-feature-h5p-editor
casparneumann-cap Nov 16, 2023
c557256
Merge branch 'main' into THR-18-dev-feature-h5p-editor
CeEv Nov 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ RUN echo "{\"sha\": \"$(git rev-parse HEAD)\", \"version\": \"$(git describe --t
FROM docker.io/nginx:1.25
RUN mkdir /etc/nginx/templates
COPY dockerconf/nginx.conf.template /etc/nginx/templates/default.conf.template
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY --from=build-stage /app/dist /usr/share/nginx/html/frontend
# second index.html needed for the location /h5p/ in csp rules
COPY --from=build-stage /app/dist /usr/share/nginx/html/h5p

EXPOSE 4000
CMD ["nginx", "-g", "daemon off;"]
18 changes: 17 additions & 1 deletion dockerconf/nginx.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ server {

set $csp "default-src 'self'; base-uri 'self'; script-src 'nonce-$request_id' 'strict-dynamic' 'unsafe-inline' https:; object-src 'none'; font-src 'self' data:; img-src 'self' data:; style-src 'self' 'unsafe-inline'; frame-src 'self' ${H5P_FRAME_SRC_URLS}";

set $h5pcsp "default-src 'self'; base-uri 'self'; script-src ${H5P_SCRIPT_SRC_URLS} 'unsafe-inline' https:; object-src 'none'; font-src 'self' data:; img-src 'self' ${H5P_IMG_SRC_URLS} data:; style-src 'self' 'unsafe-inline'; frame-src 'self' ${H5P_FRAME_SRC_URLS}";

location /status {
stub_status;
}
Expand Down Expand Up @@ -61,8 +63,22 @@ server {
proxy_pass ${LEGACY_CLIENT_URL};
}

location /h5p/ {
root /usr/share/nginx/html/h5p;
index index.html index.htm;
add_header Content-Security-Policy "${h5pcsp}";
add_header X-Content-Type-Options nosniff;
casparneumann-cap marked this conversation as resolved.
Show resolved Hide resolved
add_header Referrer-Policy 'same-origin';
add_header X-XSS-Protection '1; mode=block';
add_header X-Frame-Options 'SAMEORIGIN';
add_header Permissions-Policy 'fullscreen=(*), sync-xhr=(*), geolocation=(self), midi=(self), microphone=(self), camera=(self), magnetometer=(self), gyroscope=(self), payment=()';
sub_filter_once off;
sub_filter '**CSP_NONCE**' $request_id;
try_files $uri /index.html =404;
}

location / {
root /usr/share/nginx/html;
root /usr/share/nginx/html/frontend;
index index.html index.htm;
add_header Content-Security-Policy "${csp}";
add_header X-Content-Type-Options nosniff;
Expand Down
43 changes: 35 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@braintree/sanitize-url": "^6.0.4",
"@ckeditor/ckeditor5-vue2": "^3.0.1",
"@hpi-schul-cloud/ckeditor": "0.4.0",
"@lumieducation/h5p-webcomponents": "^9.2.2",
"@mdi/js": "^7.3.67",
"@types/vuelidate": "^0.7.21",
"@vueuse/components": "^10.5.0",
Expand Down
45 changes: 45 additions & 0 deletions src/components/h5p/H5PEditor.unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { mount } from "@vue/test-utils";
import H5PEditor from "./H5PEditor.vue";
import { I18N_KEY } from "@/utils/inject";
import VueI18n from "vue-i18n";
import createComponentMocks from "@@/tests/test-utils/componentMocks";
import { H5PEditorComponent } from "@lumieducation/h5p-webcomponents";

describe("H5PEditor", () => {
const contentId = "test-content-id";
const parentType = "test-parent-type";
const parentId = "test-parent-id";

const i18nMock = new VueI18n({
locale: "en",
});

const createWrapper = (propsData = {}) => {
return mount(H5PEditor, {
...createComponentMocks({
i18n: true,
}),
propsData: {
contentId,
parentType,
parentId,
...propsData,
},
provide: {
[I18N_KEY as any]: i18nMock,
},
});
};

it("renders without errors with standard props", async () => {
const wrapper = createWrapper();
const h5pEditor = wrapper.findComponent({ ref: "h5pEditorRef" });
expect(wrapper.exists()).toBe(true);
expect(h5pEditor).toBeDefined();

await wrapper.vm.$nextTick();
const h5pEditorComponent = h5pEditor.element as H5PEditorComponent;
expect(h5pEditorComponent.loadContentCallback).toBeDefined();
expect(h5pEditorComponent.saveContentCallback).toBeDefined();
});
});
115 changes: 115 additions & 0 deletions src/components/h5p/H5PEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* eslint-disable */

<template>
<div>
<h5p-editor
ref="h5pEditorRef"
:content-id="contentId"
@validation-error="onValidationError"
/>
</div>
</template>

<script lang="ts">
import {
defineElements,
H5PEditorComponent,
} from "@lumieducation/h5p-webcomponents";
import { I18N_KEY, injectStrict } from "@/utils/inject";
import { defineComponent, ref, watch, PropType } from "vue";
import {
H5PContentParentType,
H5pEditorApiFactory,
LanguageType,
PostH5PContentCreateParams,
} from "@/h5pEditorApi/v3";
import { $axios } from "@/utils/api";

defineElements("h5p-editor");

export default defineComponent({
name: "H5PEditorComponent",
props: {
contentId: {
type: String,
default: "new",
},
parentType: {
type: String as PropType<H5PContentParentType>,
required: true,
},
parentId: {
type: String,
required: true,
},
},
emits: ["saved", "save-error", "load-error", "validation-error"],
setup(props, { emit, expose }) {
const h5pEditorRef = ref<H5PEditorComponent>();

const h5pEditorApi = H5pEditorApiFactory(undefined, "v3", $axios);
const i18n = injectStrict(I18N_KEY);
const language = i18n.locale as LanguageType;

const loadContent = async (id?: string) => {
MajedAlaitwniCap marked this conversation as resolved.
Show resolved Hide resolved
try {
const { data } = id
? await h5pEditorApi.h5PEditorControllerGetH5PEditor(id, language)
: await h5pEditorApi.h5PEditorControllerGetNewH5PEditor(language);

return data;
} catch (err) {
emit("load-error", err);
}
};

const saveContent = async (
contentId: string,
requestBody: { library: string; params: object }
) => {
const createParams: PostH5PContentCreateParams = {
library: requestBody.library,
params: requestBody.params,
parentId: props.parentId,
parentType: props.parentType,
};

const { data } = contentId
? await h5pEditorApi.h5PEditorControllerSaveH5pContent(
contentId,
createParams
)
: await h5pEditorApi.h5PEditorControllerCreateH5pContent(createParams);

return data;
};

watch(h5pEditorRef, (editor) => {
if (editor) {
// Attach callbacks to H5P Editor
editor.loadContentCallback = loadContent;
editor.saveContentCallback = saveContent;
}
});

const save = () => {
if (h5pEditorRef.value) {
return h5pEditorRef.value.save();
} else {
throw new Error("Editor not loaded");
}
};

const onValidationError = (error: unknown) => {
emit("validation-error", error);
};

expose({ save });

return {
h5pEditorRef,
onValidationError,
};
},
});
</script>
39 changes: 39 additions & 0 deletions src/components/h5p/H5PPlayer.unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { mount } from "@vue/test-utils";
import H5PPlayer from "./H5PPlayer.vue";
import { I18N_KEY } from "@/utils/inject";
import VueI18n from "vue-i18n";
import createComponentMocks from "@@/tests/test-utils/componentMocks";
import { H5PPlayerComponent } from "@lumieducation/h5p-webcomponents";

describe("H5PPlayer", () => {
const contentId = "test-content-id";

const i18nMock = new VueI18n({
locale: "en",
});

const createWrapper = (propsData = {}) => {
return mount(H5PPlayer, {
...createComponentMocks({
i18n: true,
}),
propsData: {
contentId,
...propsData,
},
provide: {
[I18N_KEY as any]: i18nMock,
},
});
};

it("renders without errors with standard props", async () => {
const wrapper = createWrapper();
const h5pPlayer = wrapper.findComponent({ ref: "h5pPlayerRef" });
expect(wrapper.exists()).toBe(true);
expect(h5pPlayer).toBeDefined();
await wrapper.vm.$nextTick();
const h5pPlayerComponent = h5pPlayer.element as H5PPlayerComponent;
expect(h5pPlayerComponent.loadContentCallback).toBeDefined();
});
});
Loading
Loading