diff --git a/.gitignore b/.gitignore index 84ad4e0321..34e84d5a77 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ __snapshots__ # IntelliJ .idea/ + +# exclude the public/content directory +public/content diff --git a/config/docker/nginx.conf.template b/config/docker/nginx.conf.template index 4f6994f11a..aa59270eb4 100644 --- a/config/docker/nginx.conf.template +++ b/config/docker/nginx.conf.template @@ -2,7 +2,7 @@ server { listen 4000; server_name localhost; - 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} https://docs.dbildungscloud.de/"; + 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: ${EDU_SHARING_IMG_SRC_URLS}; style-src 'self' 'unsafe-inline'; frame-src 'self' ${H5P_FRAME_SRC_URLS} https://docs.dbildungscloud.de/ https://www.youtube-nocookie.com/; connect-src 'self' ${EDU_SHARING_CONNECT_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}"; diff --git a/config/webpack/dev-server-config.js b/config/webpack/dev-server-config.js index b871428117..881e068505 100644 --- a/config/webpack/dev-server-config.js +++ b/config/webpack/dev-server-config.js @@ -1,11 +1,14 @@ const { createProxyMiddleware } = require("http-proxy-middleware"); const { isVueClient } = require("../../src/router/vue-client-route"); const { - isServer, + isEduSharing, + isEduSharingRepo, isFileStorage, isH5pEditor, + isServer, } = require("../../src/router/server-route"); const url = require("url"); +const path = require("path"); const createLegacyClientProxy = () => { const legacyClientProxy = createProxyMiddleware({ @@ -23,6 +26,14 @@ const createServerProxy = () => { return serverProxy; }; +const createEduSharingProxy = () => { + const eduSharingProxy = createProxyMiddleware({ + target: "http://localhost:4450", + changeOrigin: true, + }); + return eduSharingProxy; +}; + const createFileStorageProxy = () => { const fileStorageProxy = createProxyMiddleware({ target: "http://localhost:4444", @@ -39,15 +50,25 @@ const createH5pEditorProxy = () => { return h5pEditorProxy; }; +const createEduSharingRepoProxy = () => { + const eduSharingRepoProxy = createProxyMiddleware({ + target: "http://localhost:8100", + changeOrigin: true, + }); + return eduSharingRepoProxy; +}; + const createDevServerConfig = () => { const legacyClientProxy = createLegacyClientProxy(); const serverProxy = createServerProxy(); + const eduSharingProxy = createEduSharingProxy(); + const eduSharingRepoProxy = createEduSharingRepoProxy(); const fileStorageProxy = createFileStorageProxy(); const h5pEditorProxy = createH5pEditorProxy(); const devServerConfig = { - port: 4000, historyApiFallback: true, + port: 4000, setupMiddlewares: (middlewares, devServer) => { if (!devServer) { @@ -63,6 +84,10 @@ const createDevServerConfig = () => { fileStorageProxy(req, res, next); } else if (isH5pEditor(path)) { h5pEditorProxy(req, res, next); + } else if (isEduSharing(path)) { + eduSharingProxy(req, res, next); + } else if (isEduSharingRepo(path)) { + eduSharingRepoProxy(req, res, next); } else if (isServer(path)) { serverProxy(req, res, next); } else if (isVueClient(path)) { @@ -73,6 +98,20 @@ const createDevServerConfig = () => { }, }); + // Copy assets before the dev server starts + const __base = path.resolve(__dirname, "../.."); + + const fs = require("fs-extra"); + const source = path.resolve( + __base, + "node_modules/ngx-edu-sharing-app-as-web-component" + ); + const destination = path.resolve( + __base, + "public/content/vendor/edu-sharing" + ); + fs.copySync(source, destination); + return middlewares; }, allowedHosts: "all", diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index e0312c56d4..8970a9b77a 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -96,12 +96,20 @@ module.exports = { "**/.DS_Store", path.resolve(__base, "public/index.html"), path.resolve(__base, "public/themes/**/*"), + path.resolve(__base, "public/content/**/*"), ], }, info: { minimized: true, }, }, + { + from: path.resolve( + __base, + "node_modules/ngx-edu-sharing-app-as-web-component" + ), + to: path.resolve(__base, "dist/content/vendor/edu-sharing"), + }, ], }), @@ -224,7 +232,8 @@ module.exports = { loader: "vue-loader", options: { compilerOptions: { - isCustomElement: (tag) => tag.startsWith("h5p-"), + isCustomElement: (tag) => + tag.startsWith("h5p-") || tag === "edu-sharing-app", }, }, }, diff --git a/jest.config.js b/jest.config.js index d54c09d935..c019070db7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -74,7 +74,8 @@ const config = { globals: { "vue-jest": { compilerOptions: { - isCustomElement: (tag) => tag.startsWith("h5p-"), + isCustomElement: (tag) => + tag.startsWith("h5p-") || tag === "edu-sharing-app", }, }, }, diff --git a/openapitools-for-edu-sharing.json b/openapitools-for-edu-sharing.json new file mode 100644 index 0000000000..a838baf66c --- /dev/null +++ b/openapitools-for-edu-sharing.json @@ -0,0 +1,4 @@ +{ + "supportsES6": true, + "withInterfaces": true +} diff --git a/package-lock.json b/package-lock.json index 9d9a5fefaa..3ceec3d1c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "kjua": "^0.9.0", "maska": "^2.1.10", "mobile-drag-drop": "^3.0.0-rc.0", + "ngx-edu-sharing-app-as-web-component": "^9.1.1", "object-hash": "^3.0.0", "pinia": "^2.1.7", "socket.io-client": "^4.7.5", @@ -67,6 +68,7 @@ "eslint-plugin-vue": "^9.23.0", "eslint-webpack-plugin": "^4.1.0", "fishery": "^2.2.2", + "fs-extra": "^11.2.0", "html-webpack-plugin": "^5.6.0", "http-proxy-middleware": "^2.0.6", "jest": "^29.7.0", @@ -3596,6 +3598,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@openapitools/openapi-generator-cli/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8687,9 +8704,9 @@ } }, "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "license": "MIT", "dependencies": { @@ -8698,7 +8715,7 @@ "universalify": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=14.14" } }, "node_modules/fs-minipass": { @@ -12876,6 +12893,12 @@ "devOptional": true, "license": "MIT" }, + "node_modules/ngx-edu-sharing-app-as-web-component": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ngx-edu-sharing-app-as-web-component/-/ngx-edu-sharing-app-as-web-component-9.1.1.tgz", + "integrity": "sha512-Vziii05mmfEstVUfbuCt9GO6kgZKLbGxEWBxfoZYbNr7Pa3mQ9rXYAhvruR6ldzVT2/mVde4NauKwYS23Rh4ww==", + "license": "GNU GPL v2" + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", diff --git a/package.json b/package.json index 46d19bb7dc..dedccd95e6 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "lint": "npx eslint 'src/**/*.{ts,js,vue}'", "lint:fix": "npx eslint 'src/**/*.{ts,js,vue}' --fix", "generate-client:server": "node generate-client.js -c openapitools-for-server.json", + "generate-client:edu-sharing": "node generate-client.js -u 'http://localhost:4450/api/v3/docs-json/' -p 'src/eduSharingApi/v3' -c 'openapitools-for-edu-sharing.json'", "generate-client:filestorage": "node generate-client.js -u 'http://localhost:4444/api/v3/docs-json/' -p 'src/fileStorageApi/v3' -c 'openapitools-for-file-storage.json'", "generate-client:h5p-editor": "node generate-client.js -u 'http://localhost:4448/api/v3/docs-json/' -p 'src/h5pEditorApi/v3' -c 'openapitools-for-h5p-editor.json'" }, @@ -30,6 +31,7 @@ "kjua": "^0.9.0", "maska": "^2.1.10", "mobile-drag-drop": "^3.0.0-rc.0", + "ngx-edu-sharing-app-as-web-component": "^9.1.1", "object-hash": "^3.0.0", "pinia": "^2.1.7", "socket.io-client": "^4.7.5", @@ -73,10 +75,11 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-vue": "^9.23.0", "eslint-plugin-schulcloud": "file:lib/eslint-plugin-schulcloud", + "eslint-plugin-vue": "^9.23.0", "eslint-webpack-plugin": "^4.1.0", "fishery": "^2.2.2", + "fs-extra": "^11.2.0", "html-webpack-plugin": "^5.6.0", "http-proxy-middleware": "^2.0.6", "jest": "^29.7.0", diff --git a/src/components/edu-sharing/EduSharingWrapper.vue b/src/components/edu-sharing/EduSharingWrapper.vue new file mode 100644 index 0000000000..65e4defc7e --- /dev/null +++ b/src/components/edu-sharing/EduSharingWrapper.vue @@ -0,0 +1,114 @@ + + + + + + + + + + + + + diff --git a/src/composables/edu-sharing-api.composable.ts b/src/composables/edu-sharing-api.composable.ts new file mode 100644 index 0000000000..010b966ea6 --- /dev/null +++ b/src/composables/edu-sharing-api.composable.ts @@ -0,0 +1,36 @@ +import { + EduSharingApiFactory, + EduSharingApiInterface, +} from "@/eduSharingApi/v3"; +import { $axios } from "@/utils/api"; + +export const useEduSharingApi = () => { + const eduSharingApi: EduSharingApiInterface = EduSharingApiFactory( + undefined, + "/v3", + $axios + ); + + const getEduAppXMLData = async (): Promise => { + const response = await eduSharingApi.getEduAppXMLData(); + return response.data; + }; + + const getTicketAuthenticationInfo = async ( + ticket: string + ): Promise => { + const response = await eduSharingApi.getTicketAuthenticationInfo(ticket); + return response.data; + }; + + const getTicketForUser = async (): Promise => { + const response = await eduSharingApi.getTicketForUser(); + return response.data; + }; + + return { + getEduAppXMLData, + getTicketAuthenticationInfo, + getTicketForUser, + }; +}; diff --git a/src/eduSharingApi/v3/.gitignore b/src/eduSharingApi/v3/.gitignore new file mode 100644 index 0000000000..149b576547 --- /dev/null +++ b/src/eduSharingApi/v3/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/src/eduSharingApi/v3/.npmignore b/src/eduSharingApi/v3/.npmignore new file mode 100644 index 0000000000..999d88df69 --- /dev/null +++ b/src/eduSharingApi/v3/.npmignore @@ -0,0 +1 @@ +# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm \ No newline at end of file diff --git a/src/eduSharingApi/v3/.openapi-generator-ignore b/src/eduSharingApi/v3/.openapi-generator-ignore new file mode 100644 index 0000000000..7484ee590a --- /dev/null +++ b/src/eduSharingApi/v3/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/src/eduSharingApi/v3/.openapi-generator/FILES b/src/eduSharingApi/v3/.openapi-generator/FILES new file mode 100644 index 0000000000..a80cd4f07b --- /dev/null +++ b/src/eduSharingApi/v3/.openapi-generator/FILES @@ -0,0 +1,8 @@ +.gitignore +.npmignore +api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts diff --git a/src/eduSharingApi/v3/.openapi-generator/VERSION b/src/eduSharingApi/v3/.openapi-generator/VERSION new file mode 100644 index 0000000000..acf69b48b8 --- /dev/null +++ b/src/eduSharingApi/v3/.openapi-generator/VERSION @@ -0,0 +1 @@ +5.1.0 \ No newline at end of file diff --git a/src/eduSharingApi/v3/api.ts b/src/eduSharingApi/v3/api.ts new file mode 100644 index 0000000000..74252e7ef8 --- /dev/null +++ b/src/eduSharingApi/v3/api.ts @@ -0,0 +1,297 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * HPI Schul-Cloud Server API + * This is v3 of HPI Schul-Cloud Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from './configuration'; +import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from './base'; + + +/** + * EduSharingApi - axios parameter creator + * @export + */ +export const EduSharingApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @summary Returns the required XML for registering the service against an edu-sharing repository. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getEduAppXMLData: async (options: any = {}): Promise => { + const localVarPath = `/edu-sharing/register`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Gets detailed information about a ticket. Will throw an exception if the given ticket is not valid anymore. + * @param {string} ticket The ticket to be evaluated. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTicketAuthenticationInfo: async (ticket: string, options: any = {}): Promise => { + // verify required parameter 'ticket' is not null or undefined + assertParamExists('getTicketAuthenticationInfo', 'ticket', ticket) + const localVarPath = `/edu-sharing/validate/{ticket}` + .replace(`{${"ticket"}}`, encodeURIComponent(String(ticket))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Fetches the edu-sharing ticket for a given user name. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTicketForUser: async (options: any = {}): Promise => { + const localVarPath = `/edu-sharing`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * EduSharingApi - functional programming interface + * @export + */ +export const EduSharingApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = EduSharingApiAxiosParamCreator(configuration) + return { + /** + * + * @summary Returns the required XML for registering the service against an edu-sharing repository. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getEduAppXMLData(options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getEduAppXMLData(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @summary Gets detailed information about a ticket. Will throw an exception if the given ticket is not valid anymore. + * @param {string} ticket The ticket to be evaluated. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getTicketAuthenticationInfo(ticket: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getTicketAuthenticationInfo(ticket, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @summary Fetches the edu-sharing ticket for a given user name. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getTicketForUser(options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getTicketForUser(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + } +}; + +/** + * EduSharingApi - factory interface + * @export + */ +export const EduSharingApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = EduSharingApiFp(configuration) + return { + /** + * + * @summary Returns the required XML for registering the service against an edu-sharing repository. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getEduAppXMLData(options?: any): AxiosPromise { + return localVarFp.getEduAppXMLData(options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Gets detailed information about a ticket. Will throw an exception if the given ticket is not valid anymore. + * @param {string} ticket The ticket to be evaluated. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTicketAuthenticationInfo(ticket: string, options?: any): AxiosPromise { + return localVarFp.getTicketAuthenticationInfo(ticket, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Fetches the edu-sharing ticket for a given user name. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getTicketForUser(options?: any): AxiosPromise { + return localVarFp.getTicketForUser(options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * EduSharingApi - interface + * @export + * @interface EduSharingApi + */ +export interface EduSharingApiInterface { + /** + * + * @summary Returns the required XML for registering the service against an edu-sharing repository. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof EduSharingApiInterface + */ + getEduAppXMLData(options?: any): AxiosPromise; + + /** + * + * @summary Gets detailed information about a ticket. Will throw an exception if the given ticket is not valid anymore. + * @param {string} ticket The ticket to be evaluated. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof EduSharingApiInterface + */ + getTicketAuthenticationInfo(ticket: string, options?: any): AxiosPromise; + + /** + * + * @summary Fetches the edu-sharing ticket for a given user name. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof EduSharingApiInterface + */ + getTicketForUser(options?: any): AxiosPromise; + +} + +/** + * EduSharingApi - object-oriented interface + * @export + * @class EduSharingApi + * @extends {BaseAPI} + */ +export class EduSharingApi extends BaseAPI implements EduSharingApiInterface { + /** + * + * @summary Returns the required XML for registering the service against an edu-sharing repository. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof EduSharingApi + */ + public getEduAppXMLData(options?: any) { + return EduSharingApiFp(this.configuration).getEduAppXMLData(options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Gets detailed information about a ticket. Will throw an exception if the given ticket is not valid anymore. + * @param {string} ticket The ticket to be evaluated. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof EduSharingApi + */ + public getTicketAuthenticationInfo(ticket: string, options?: any) { + return EduSharingApiFp(this.configuration).getTicketAuthenticationInfo(ticket, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Fetches the edu-sharing ticket for a given user name. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof EduSharingApi + */ + public getTicketForUser(options?: any) { + return EduSharingApiFp(this.configuration).getTicketForUser(options).then((request) => request(this.axios, this.basePath)); + } +} + + diff --git a/src/eduSharingApi/v3/base.ts b/src/eduSharingApi/v3/base.ts new file mode 100644 index 0000000000..87ab9e0c90 --- /dev/null +++ b/src/eduSharingApi/v3/base.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * HPI Schul-Cloud Server API + * This is v3 of HPI Schul-Cloud Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from "./configuration"; +// Some imports not used depending on template conditions +// @ts-ignore +import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; + +export const BASE_PATH = "http://localhost:4450/api/v3".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: any; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath || this.basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + name: "RequiredError" = "RequiredError"; + constructor(public field: string, msg?: string) { + super(msg); + } +} diff --git a/src/eduSharingApi/v3/common.ts b/src/eduSharingApi/v3/common.ts new file mode 100644 index 0000000000..ff387d5ced --- /dev/null +++ b/src/eduSharingApi/v3/common.ts @@ -0,0 +1,138 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * HPI Schul-Cloud Server API + * This is v3 of HPI Schul-Cloud Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from "./configuration"; +import { RequiredError, RequestArgs } from "./base"; +import { AxiosInstance } from 'axios'; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com' + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); + } +} + +/** + * + * @export + */ +export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +} + +/** + * + * @export + */ +export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { + if (configuration && (configuration.username || configuration.password)) { + object["auth"] = { username: configuration.username, password: configuration.password }; + } +} + +/** + * + * @export + */ +export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object["Authorization"] = "Bearer " + accessToken; + } +} + +/** + * + * @export + */ +export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object["Authorization"] = "Bearer " + localVarAccessTokenValue; + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + for (const object of objects) { + for (const key in object) { + if (Array.isArray(object[key])) { + searchParams.delete(key); + for (const item of object[key]) { + searchParams.append(key, item); + } + } else { + searchParams.set(key, object[key]); + } + } + } + url.search = searchParams.toString(); +} + +/** + * + * @export + */ +export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { + const nonString = typeof value !== 'string'; + const needsSerialization = nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : (value || ""); +} + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash +} + +/** + * + * @export + */ +export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/src/eduSharingApi/v3/configuration.ts b/src/eduSharingApi/v3/configuration.ts new file mode 100644 index 0000000000..771c1dbbdb --- /dev/null +++ b/src/eduSharingApi/v3/configuration.ts @@ -0,0 +1,101 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * HPI Schul-Cloud Server API + * This is v3 of HPI Schul-Cloud Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface ConfigurationParameters { + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.baseOptions = param.baseOptions; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } +} diff --git a/src/eduSharingApi/v3/git_push.sh b/src/eduSharingApi/v3/git_push.sh new file mode 100644 index 0000000000..ced3be2b0c --- /dev/null +++ b/src/eduSharingApi/v3/git_push.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-pestore-perl "minor update" "gitlab.com" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 +git_host=$4 + +if [ "$git_host" = "" ]; then + git_host="github.com" + echo "[INFO] No command line input provided. Set \$git_host to $git_host" +fi + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@${git_host}/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/src/eduSharingApi/v3/index.ts b/src/eduSharingApi/v3/index.ts new file mode 100644 index 0000000000..de68565fde --- /dev/null +++ b/src/eduSharingApi/v3/index.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * HPI Schul-Cloud Server API + * This is v3 of HPI Schul-Cloud Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export * from "./api"; +export * from "./configuration"; + diff --git a/src/pages/LernStoreOverview.page.vue b/src/pages/LernStoreOverview.page.vue index 055b120c9e..0de8645537 100644 --- a/src/pages/LernStoreOverview.page.vue +++ b/src/pages/LernStoreOverview.page.vue @@ -13,113 +13,28 @@ {{ $t("pages.content.index.backToCourse") }} - - - - - - - - - - - - - - - - {{ resources.total }} - {{ $t("pages.content.index.search_results") }} "{{ - searchQueryResult - }}" - - - - - - - - - - - - - - - - - - - - - - +
- {{ resources.total }} - {{ $t("pages.content.index.search_results") }} "{{ - searchQueryResult - }}" -