diff --git a/.gitignore b/.gitignore index a4ce7c6c..dcee5d6d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ playwright-report/ /src/page/plugins/* !/src/page/plugins/filetransfer +!/src/page/plugins/chat !/src/page/plugins/.gitkeep diff --git a/src/page/main.vue b/src/page/main.vue index 33a8ebe2..f1e92210 100644 --- a/src/page/main.vue +++ b/src/page/main.vue @@ -95,10 +95,6 @@ Media -
  • - - Chat -
  • @@ -108,7 +104,6 @@ - @@ -354,7 +349,6 @@ import NekoControls from './components/controls.vue' import NekoEvents from './components/events.vue' import NekoMembers from './components/members.vue' import NekoMedia from './components/media.vue' -import NekoChat from './components/chat.vue' const neko = ref() diff --git a/src/page/plugins/chat/OpenApi.yaml b/src/page/plugins/chat/OpenApi.yaml new file mode 100644 index 00000000..7401794c --- /dev/null +++ b/src/page/plugins/chat/OpenApi.yaml @@ -0,0 +1,102 @@ +openapi: 3.0.0 + +info: + title: n.eko REST API + description: Next Gen Renderer Browser. + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' + version: "1.0.0" + +servers: + - description: Local server + url: http://localhost:3000 + # Added by API Auto Mocking Plugin + - description: SwaggerHub API Auto Mocking + url: https://virtserver.swaggerhub.com/m1k1o/n.eko/1.0.0 + +tags: + - name: chat + description: Chat API + +paths: + + # + # chat + # + + /api/chat: + post: + tags: + - chat + summary: Send a chat message + operationId: sendChatMessage + responses: + '200': + description: OK + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/Content' + +components: + securitySchemes: + CookieAuth: + type: apiKey + in: cookie + name: NEKO_SESSION + BearerAuth: + type: http + scheme: bearer + TokenAuth: + type: apiKey + in: query + name: token + + responses: + NotFound: + description: The specified resource was not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + Unauthorized: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + Forbidden: + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + + schemas: + ErrorMessage: + type: object + properties: + message: + type: string + + # + # chat + # + + Content: + type: object + properties: + text: + type: string + description: The message content + +security: + - BearerAuth: [] + - CookieAuth: [] + - TokenAuth: [] diff --git a/src/page/plugins/chat/api-gen b/src/page/plugins/chat/api-gen new file mode 100755 index 00000000..20eb3b09 --- /dev/null +++ b/src/page/plugins/chat/api-gen @@ -0,0 +1,18 @@ +#!/bin/bash +VERSION="1.0.0" + +rm -rf "${PWD}/api" +mkdir "${PWD}/api" + +docker run --rm \ + --user "$(id -u):$(id -g)" \ + -v "${PWD}/api:/local/out" \ + -v "${PWD}/OpenApi.yaml:/local/in.yaml" \ + openapitools/openapi-generator-cli generate \ + -i /local/in.yaml \ + -g typescript-axios \ + -o /local/out \ + --additional-properties=enumPropertyNaming=original,modelPropertyNaming=original,withSeparateModelsAndApi=true,modelPackage=models,apiPackage=api + +# Remove not needed git_push.sh +rm -f "${PWD}/api/git_push.sh" diff --git a/src/page/plugins/chat/api/.gitignore b/src/page/plugins/chat/api/.gitignore new file mode 100644 index 00000000..149b5765 --- /dev/null +++ b/src/page/plugins/chat/api/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/src/page/plugins/chat/api/.npmignore b/src/page/plugins/chat/api/.npmignore new file mode 100644 index 00000000..999d88df --- /dev/null +++ b/src/page/plugins/chat/api/.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/page/plugins/chat/api/.openapi-generator-ignore b/src/page/plugins/chat/api/.openapi-generator-ignore new file mode 100644 index 00000000..7484ee59 --- /dev/null +++ b/src/page/plugins/chat/api/.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/page/plugins/chat/api/.openapi-generator/FILES b/src/page/plugins/chat/api/.openapi-generator/FILES new file mode 100644 index 00000000..f4d9f699 --- /dev/null +++ b/src/page/plugins/chat/api/.openapi-generator/FILES @@ -0,0 +1,12 @@ +.gitignore +.npmignore +.openapi-generator-ignore +api.ts +api/chat-api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts +models/error-message.ts +models/index.ts diff --git a/src/page/plugins/chat/api/.openapi-generator/VERSION b/src/page/plugins/chat/api/.openapi-generator/VERSION new file mode 100644 index 00000000..08bfd064 --- /dev/null +++ b/src/page/plugins/chat/api/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.5.0-SNAPSHOT diff --git a/src/page/plugins/chat/api/api.ts b/src/page/plugins/chat/api/api.ts new file mode 100644 index 00000000..7faf378c --- /dev/null +++ b/src/page/plugins/chat/api/api.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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/chat-api'; + diff --git a/src/page/plugins/chat/api/api/chat-api.ts b/src/page/plugins/chat/api/api/chat-api.ts new file mode 100644 index 00000000..30a653f8 --- /dev/null +++ b/src/page/plugins/chat/api/api/chat-api.ts @@ -0,0 +1,145 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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 type { Configuration } from '../configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios 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, operationServerMap } from '../base'; +// @ts-ignore +import { ErrorMessage } from '../models'; +/** + * ChatApi - axios parameter creator + * @export + */ +export const ChatApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @summary Send a chat message + * @param {string} [content] The message content + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + sendChatMessage: async (content?: string, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/chat`; + // 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: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + const localVarFormParams = new ((configuration && configuration.formDataCtor) || FormData)(); + + // authentication CookieAuth required + + // authentication TokenAuth required + await setApiKeyToObject(localVarQueryParameter, "token", configuration) + + // authentication BearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + if (content !== undefined) { + localVarFormParams.append('content', content as any); + } + + + localVarHeaderParameter['Content-Type'] = 'multipart/form-data'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = localVarFormParams; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * ChatApi - functional programming interface + * @export + */ +export const ChatApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = ChatApiAxiosParamCreator(configuration) + return { + /** + * + * @summary Send a chat message + * @param {string} [content] The message content + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async sendChatMessage(content?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.sendChatMessage(content, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ChatApi.sendChatMessage']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * ChatApi - factory interface + * @export + */ +export const ChatApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = ChatApiFp(configuration) + return { + /** + * + * @summary Send a chat message + * @param {string} [content] The message content + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + sendChatMessage(content?: string, options?: any): AxiosPromise { + return localVarFp.sendChatMessage(content, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * ChatApi - object-oriented interface + * @export + * @class ChatApi + * @extends {BaseAPI} + */ +export class ChatApi extends BaseAPI { + /** + * + * @summary Send a chat message + * @param {string} [content] The message content + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ChatApi + */ + public sendChatMessage(content?: string, options?: RawAxiosRequestConfig) { + return ChatApiFp(this.configuration).sendChatMessage(content, options).then((request) => request(this.axios, this.basePath)); + } +} + diff --git a/src/page/plugins/chat/api/base.ts b/src/page/plugins/chat/api/base.ts new file mode 100644 index 00000000..60439c98 --- /dev/null +++ b/src/page/plugins/chat/api/base.ts @@ -0,0 +1,86 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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 type { Configuration } from './configuration'; +// Some imports not used depending on template conditions +// @ts-ignore +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; + +export const BASE_PATH = "http://localhost:3000".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: RawAxiosRequestConfig; +} + +/** + * + * @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 ?? basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + constructor(public field: string, msg?: string) { + super(msg); + this.name = "RequiredError" + } +} + +interface ServerMap { + [key: string]: { + url: string, + description: string, + }[]; +} + +/** + * + * @export + */ +export const operationServerMap: ServerMap = { +} diff --git a/src/page/plugins/chat/api/common.ts b/src/page/plugins/chat/api/common.ts new file mode 100644 index 00000000..854e27fd --- /dev/null +++ b/src/page/plugins/chat/api/common.ts @@ -0,0 +1,150 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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 type { Configuration } from "./configuration"; +import type { RequestArgs } from "./base"; +import type { AxiosInstance, AxiosResponse } from 'axios'; +import { RequiredError } from "./base"; + +/** + * + * @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; + } +} + +function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { + if (parameter == null) return; + if (typeof parameter === "object") { + if (Array.isArray(parameter)) { + (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); + } + else { + Object.keys(parameter).forEach(currentKey => + setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) + ); + } + } + else { + if (urlSearchParams.has(key)) { + urlSearchParams.append(key, parameter); + } + else { + urlSearchParams.set(key, parameter); + } + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + setFlattenedQueryParams(searchParams, objects); + 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: (axios.defaults.baseURL ? '' : configuration?.basePath ?? basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/src/page/plugins/chat/api/configuration.ts b/src/page/plugins/chat/api/configuration.ts new file mode 100644 index 00000000..48054398 --- /dev/null +++ b/src/page/plugins/chat/api/configuration.ts @@ -0,0 +1,110 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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; + serverIndex?: number; + 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; + /** + * override server index + * + * @type {number} + * @memberof Configuration + */ + serverIndex?: number; + /** + * 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.serverIndex = param.serverIndex; + 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/page/plugins/chat/api/index.ts b/src/page/plugins/chat/api/index.ts new file mode 100644 index 00000000..77070e12 --- /dev/null +++ b/src/page/plugins/chat/api/index.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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"; +export * from "./models"; diff --git a/src/page/plugins/chat/api/models/error-message.ts b/src/page/plugins/chat/api/models/error-message.ts new file mode 100644 index 00000000..8764dd5d --- /dev/null +++ b/src/page/plugins/chat/api/models/error-message.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * n.eko REST API + * Next Gen Renderer Browser. + * + * The version of the OpenAPI document: 1.0.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 ErrorMessage + */ +export interface ErrorMessage { + /** + * + * @type {string} + * @memberof ErrorMessage + */ + 'message'?: string; +} + diff --git a/src/page/plugins/chat/api/models/index.ts b/src/page/plugins/chat/api/models/index.ts new file mode 100644 index 00000000..595296f1 --- /dev/null +++ b/src/page/plugins/chat/api/models/index.ts @@ -0,0 +1 @@ +export * from './error-message'; diff --git a/src/page/components/chat.vue b/src/page/plugins/chat/component.vue similarity index 70% rename from src/page/components/chat.vue rename to src/page/plugins/chat/component.vue index 0e4f85c8..76911f7b 100644 --- a/src/page/components/chat.vue +++ b/src/page/plugins/chat/component.vue @@ -1,5 +1,13 @@