diff --git a/messages/JsonMessages/AdminApiData.ts b/messages/JsonMessages/AdminApiData.ts index a0469f5a..b06d624d 100644 --- a/messages/JsonMessages/AdminApiData.ts +++ b/messages/JsonMessages/AdminApiData.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import {extendApi} from "@anatine/zod-openapi"; +import { extendApi } from "@anatine/zod-openapi"; /* * WARNING! The original file is in /messages/JsonMessages. @@ -8,10 +8,16 @@ import {extendApi} from "@anatine/zod-openapi"; export const isAdminApiData = z.object({ // @ts-ignore - userUuid: extendApi(z.string(), {example: '998ce839-3dea-4698-8b41-ebbdf7688ad9'}), - email: extendApi(z.nullable(z.string()), {description: 'The email of the current user.', example: 'example@workadventu.re'}), - roomUrl: extendApi(z.string(), {example: '/@/teamSlug/worldSlug/roomSlug'}), - mapUrlStart: extendApi(z.string(), {description: 'The full URL to the JSON map file', example: 'https://myuser.github.io/myrepo/map.json'}), + userUuid: extendApi(z.string(), { example: "998ce839-3dea-4698-8b41-ebbdf7688ad9" }), + email: extendApi(z.nullable(z.string()), { + description: "The email of the current user.", + example: "example@workadventu.re", + }), + roomUrl: extendApi(z.string(), { example: "/@/teamSlug/worldSlug/roomSlug" }), + mapUrlStart: extendApi(z.string(), { + description: "The full URL to the JSON map file", + example: "https://myuser.github.io/myrepo/map.json", + }), messages: z.optional(z.array(z.unknown())), }); diff --git a/messages/JsonMessages/ErrorApiData.ts b/messages/JsonMessages/ErrorApiData.ts index 9dc8dbbe..39334e25 100644 --- a/messages/JsonMessages/ErrorApiData.ts +++ b/messages/JsonMessages/ErrorApiData.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import {extendApi} from "@anatine/zod-openapi"; +import { extendApi } from "@anatine/zod-openapi"; /* * WARNING! The original file is in /messages/JsonMessages. @@ -10,60 +10,120 @@ export const isErrorApiErrorData = extendApi( // @ts-ignore z.object({ type: z.literal("error"), - code: extendApi(z.string(), {description: 'The system code of an error, it must be in SCREAMING_SNAKE_CASE.', example: 'ROOM_NOT_FOUND'}), - title: extendApi(z.string(), {description: "Big title displayed on the error screen.", example: "ERROR"}), - subtitle: extendApi(z.string(), {description: "Subtitle displayed to let the user know what is the main subject of the error.", example: "The room was not found."}), - details: extendApi(z.string(), {description: "Some others details on what the user can do if he don't understand the error.", example: "If you would like more information, you can contact the administrator or us at example@workadventu.re."}), - image: extendApi(z.string(), {description: "The URL of the image displayed just under the logo in the error screen.", example: 'https://example.com/error.png'}), + code: extendApi(z.string(), { + description: "The system code of an error, it must be in SCREAMING_SNAKE_CASE.", + example: "ROOM_NOT_FOUND", + }), + title: extendApi(z.string(), { description: "Big title displayed on the error screen.", example: "ERROR" }), + subtitle: extendApi(z.string(), { + description: "Subtitle displayed to let the user know what is the main subject of the error.", + example: "The room was not found.", + }), + details: extendApi(z.string(), { + description: "Some others details on what the user can do if he don't understand the error.", + example: + "If you would like more information, you can contact the administrator or us at example@workadventu.re.", + }), + image: extendApi(z.string(), { + description: "The URL of the image displayed just under the logo in the error screen.", + example: "https://example.com/error.png", + }), }), { - description: 'This is an error that can be returned by the API, its type must be equal to "error".\n If such an error is caught, an error screen will be displayed.', + description: + 'This is an error that can be returned by the API, its type must be equal to "error".\n If such an error is caught, an error screen will be displayed.', } ); export const isErrorApiRetryData = extendApi( z.object({ type: z.literal("retry"), - code: extendApi(z.string(), {description: 'The system code of an error, it must be in SCREAMING_SNAKE_CASE. \n It will not be displayed to the user.', example: 'WORLD_FULL'}), - title: extendApi(z.string(), {description: "Big title displayed on the error screen.", example: "ERROR"}), - subtitle: extendApi(z.string(), {description: "Subtitle displayed to let the user know what is the main subject of the error.", example: "Too successful, your WorkAdventure world is full!"}), - details: extendApi(z.string(), {description: "Some others details on what the user can do if he don't understand the error.", example: "New automatic attempt in 30 seconds"}), - image: extendApi(z.string(), {description: "The URL of the image displayed just under the logo in the waiting screen.", example: 'https://example.com/wait.png'}), - buttonTitle: extendApi(z.optional(z.nullable(z.string())), {description: "If this is not defined the button and the parameter canRetryManual is set to true, the button will be not displayed at all.", example: "Retry"}), - timeToRetry: extendApi(z.number(), {description: "This is the time (in millisecond) between the next auto refresh of the page.", example: 30_000}), - canRetryManual: extendApi(z.boolean(), {description: "This boolean show or hide the button to let the user refresh manually the current page.", example: true}), + code: extendApi(z.string(), { + description: + "The system code of an error, it must be in SCREAMING_SNAKE_CASE. \n It will not be displayed to the user.", + example: "WORLD_FULL", + }), + title: extendApi(z.string(), { description: "Big title displayed on the error screen.", example: "ERROR" }), + subtitle: extendApi(z.string(), { + description: "Subtitle displayed to let the user know what is the main subject of the error.", + example: "Too successful, your WorkAdventure world is full!", + }), + details: extendApi(z.string(), { + description: "Some others details on what the user can do if he don't understand the error.", + example: "New automatic attempt in 30 seconds", + }), + image: extendApi(z.string(), { + description: "The URL of the image displayed just under the logo in the waiting screen.", + example: "https://example.com/wait.png", + }), + buttonTitle: extendApi(z.optional(z.nullable(z.string())), { + description: + "If this is not defined the button and the parameter canRetryManual is set to true, the button will be not displayed at all.", + example: "Retry", + }), + timeToRetry: extendApi(z.number(), { + description: "This is the time (in millisecond) between the next auto refresh of the page.", + example: 30_000, + }), + canRetryManual: extendApi(z.boolean(), { + description: "This boolean show or hide the button to let the user refresh manually the current page.", + example: true, + }), }), { - description: 'This is an error that can be returned by the API, its type must be equal to "retry".\n' + - 'If such an error is caught, a waiting screen will be displayed.', + description: + 'This is an error that can be returned by the API, its type must be equal to "retry".\n' + + "If such an error is caught, a waiting screen will be displayed.", } ); export const isErrorApiRedirectData = extendApi( z.object({ type: z.literal("redirect"), - urlToRedirect: extendApi(z.string(), {description: 'A URL specified to redirect the user onto it directly', example: '/contact-us'}), + urlToRedirect: extendApi(z.string(), { + description: "A URL specified to redirect the user onto it directly", + example: "/contact-us", + }), }), { - description: 'This is an error that can be returned by the API, its type must be equal to "redirect".\n' + - 'If such an error is caught, the user will be automatically redirected to urlToRedirect.', + description: + 'This is an error that can be returned by the API, its type must be equal to "redirect".\n' + + "If such an error is caught, the user will be automatically redirected to urlToRedirect.", } ); export const isErrorApiUnauthorizedData = extendApi( z.object({ type: z.literal("unauthorized"), - code: extendApi(z.string(), {description: "This is the system code of an error, it must be in SCREAMING_SNAKE_CASE.", example: "USER_ACCESS_FORBIDDEN"}), - title: extendApi(z.string(), {description: "Big title displayed on the error screen.", example: "ERROR"}), - subtitle: extendApi(z.string(), {description: "Subtitle displayed to let the user know what is the main subject of the error.", example: "You can't access this place."}), - details: extendApi(z.string(), {description: "Some others details on what the user can do if he don't understand the error.", example: "If you would like more information, you can contact the administrator or us at example@workadventu.re."}), - image: extendApi(z.string(), {description: "The URL of the image displayed just under the logo in the error screen.", example: 'https://example.com/error.png'}), - buttonTitle: extendApi(z.optional(z.nullable(z.string())), {description: "If this is not defined the button to logout will be not displayed.", example: "Log out"}), + code: extendApi(z.string(), { + description: "This is the system code of an error, it must be in SCREAMING_SNAKE_CASE.", + example: "USER_ACCESS_FORBIDDEN", + }), + title: extendApi(z.string(), { description: "Big title displayed on the error screen.", example: "ERROR" }), + subtitle: extendApi(z.string(), { + description: "Subtitle displayed to let the user know what is the main subject of the error.", + example: "You can't access this place.", + }), + details: extendApi(z.string(), { + description: "Some others details on what the user can do if he don't understand the error.", + example: + "If you would like more information, you can contact the administrator or us at example@workadventu.re.", + }), + image: extendApi(z.string(), { + description: "The URL of the image displayed just under the logo in the error screen.", + example: "https://example.com/error.png", + }), + buttonTitle: extendApi(z.optional(z.nullable(z.string())), { + description: "If this is not defined the button to logout will be not displayed.", + example: "Log out", + }), }), { - description: 'This is an error that can be returned by the API, its type must be equal to "unauthorized".\n' + - 'If such an error is caught, an error screen will be displayed with a button to let him logout and go to login page.', - }); + description: + 'This is an error that can be returned by the API, its type must be equal to "unauthorized".\n' + + "If such an error is caught, an error screen will be displayed with a button to let him logout and go to login page.", + } +); export const isErrorApiData = z.discriminatedUnion("type", [ isErrorApiErrorData, diff --git a/messages/JsonMessages/MapDetailsData.ts b/messages/JsonMessages/MapDetailsData.ts index 2c8a119d..5df1bc7f 100644 --- a/messages/JsonMessages/MapDetailsData.ts +++ b/messages/JsonMessages/MapDetailsData.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import {extendApi} from "@anatine/zod-openapi"; +import { extendApi } from "@anatine/zod-openapi"; /* * WARNING! The original file is in /messages/JsonMessages. @@ -8,20 +8,47 @@ import {extendApi} from "@anatine/zod-openapi"; export const isMapDetailsData = z.object({ // @ts-ignore - mapUrl: extendApi(z.string(), {description: 'The full URL to the JSON map file', example: 'https://myuser.github.io/myrepo/map.json'}), - authenticationMandatory: extendApi(z.optional(z.nullable(z.boolean())), {description: 'Whether the authentication is mandatory or not for this map', example: true}), - group: extendApi(z.nullable(z.string()), {description: 'The group this room is part of (maps the notion of "world" in WorkAdventure SAAS)', example: 'myorg/myworld'}), + mapUrl: extendApi(z.string(), { + description: "The full URL to the JSON map file", + example: "https://myuser.github.io/myrepo/map.json", + }), + authenticationMandatory: extendApi(z.optional(z.nullable(z.boolean())), { + description: "Whether the authentication is mandatory or not for this map", + example: true, + }), + group: extendApi(z.nullable(z.string()), { + description: 'The group this room is part of (maps the notion of "world" in WorkAdventure SAAS)', + example: "myorg/myworld", + }), - contactPage: extendApi(z.optional(z.nullable(z.string())), {description: 'The URL to the contact page', example: 'https://mycompany.com/contact-us'}), - iframeAuthentication: extendApi(z.optional(z.nullable(z.string())), {description: 'The URL of the authentication Iframe', example: 'https://mycompany.com/authc'}), + contactPage: extendApi(z.optional(z.nullable(z.string())), { + description: "The URL to the contact page", + example: "https://mycompany.com/contact-us", + }), + iframeAuthentication: extendApi(z.optional(z.nullable(z.string())), { + description: "The URL of the authentication Iframe", + example: "https://mycompany.com/authc", + }), // The date (in ISO 8601 format) at which the room will expire - expireOn: extendApi(z.optional(z.string()), {description: 'The date (in ISO 8601 format) at which the room will expire', example: '2022-11-05T08:15:30-05:00'}), + expireOn: extendApi(z.optional(z.string()), { + description: "The date (in ISO 8601 format) at which the room will expire", + example: "2022-11-05T08:15:30-05:00", + }), // Whether the "report" feature is enabled or not on this room - canReport: extendApi(z.optional(z.boolean()), {description: 'Whether the "report" feature is enabled or not on this room', example: true}), + canReport: extendApi(z.optional(z.boolean()), { + description: 'Whether the "report" feature is enabled or not on this room', + example: true, + }), // The URL of the logo image on the loading screen - loadingLogo: extendApi(z.optional(z.nullable(z.string())), {description: 'The URL of the image to be used on the loading page', example: 'https://example.com/logo.png'}), + loadingLogo: extendApi(z.optional(z.nullable(z.string())), { + description: "The URL of the image to be used on the loading page", + example: "https://example.com/logo.png", + }), // The URL of the logo image on "LoginScene" - loginSceneLogo: extendApi(z.optional(z.nullable(z.string())), {description: 'The URL of the image to be used on the LoginScene', example: 'https://example.com/logo_login.png'}), + loginSceneLogo: extendApi(z.optional(z.nullable(z.string())), { + description: "The URL of the image to be used on the LoginScene", + example: "https://example.com/logo_login.png", + }), }); export type MapDetailsData = z.infer; diff --git a/pusher/src/Controller/SwaggerController.ts b/pusher/src/Controller/SwaggerController.ts index 8a2b0f72..f840551b 100644 --- a/pusher/src/Controller/SwaggerController.ts +++ b/pusher/src/Controller/SwaggerController.ts @@ -33,27 +33,27 @@ export class SwaggerController extends BaseHttpController { info: { title: "WorkAdventure Pusher", version: "1.0.0", - description: "This is a documentation about the endpoints called by the pusher. \n You can find out more about WorkAdventure on [github](https://github.com/thecodingmachine/workadventure).", - contact: - { - email: "hello@workadventu.re" - } + description: + "This is a documentation about the endpoints called by the pusher. \n You can find out more about WorkAdventure on [github](https://github.com/thecodingmachine/workadventure).", + contact: { + email: "hello@workadventu.re", + }, }, - "host": "pusher." + ADMIN_URL.replace('//',''), - "tags": [ + host: "pusher." + ADMIN_URL.replace("//", ""), + tags: [ { - "name": "AdminAPI", - "description": "Access to end points of the admin from the pusher" + name: "AdminAPI", + description: "Access to end points of the admin from the pusher", }, ], - "securityDefinitions": { - "Bearer": { - "type": "apiKey", - "name": "Authorization", - "in": "header" + securityDefinitions: { + Bearer: { + type: "apiKey", + name: "Authorization", + in: "header", }, }, - ...SwaggerGenerator.definitions() + ...SwaggerGenerator.definitions(), }, apis: ["./src/Services/*.ts"], }; @@ -81,11 +81,14 @@ export class SwaggerController extends BaseHttpController { } const urls = [ - {url: "/openapi/pusher", name: "Front -> Pusher"}, - {url: "/openapi/admin", name: "Pusher <- Admin"}, + { url: "/openapi/pusher", name: "Front -> Pusher" }, + { url: "/openapi/admin", name: "Pusher <- Admin" }, ]; - const result = data.replace(/url: "https:\/\/petstore\.swagger\.io\/v2\/swagger.json"/g, `urls: ${JSON.stringify(urls)}, "urls.primaryName": "Pusher <- Admin"`); + const result = data.replace( + /url: "https:\/\/petstore\.swagger\.io\/v2\/swagger.json"/g, + `urls: ${JSON.stringify(urls)}, "urls.primaryName": "Pusher <- Admin"` + ); response.send(result); return; diff --git a/pusher/src/Model/Websocket/Admin/AdminMessages.ts b/pusher/src/Model/Websocket/Admin/AdminMessages.ts index 15b5e58e..40fc3208 100644 --- a/pusher/src/Model/Websocket/Admin/AdminMessages.ts +++ b/pusher/src/Model/Websocket/Admin/AdminMessages.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import {extendApi} from "@anatine/zod-openapi"; +import { extendApi } from "@anatine/zod-openapi"; export const isBanBannedAdminMessageInterface = z.object({ type: z.enum(["ban", "banned"]), @@ -9,7 +9,7 @@ export const isBanBannedAdminMessageInterface = z.object({ export const isUserMessageAdminMessageInterface = z.object({ event: z.enum(["user-message"]), - message: extendApi(isBanBannedAdminMessageInterface, {$ref: "#/definitions/BanBannedAdminMessageInterface"}), + message: extendApi(isBanBannedAdminMessageInterface, { $ref: "#/definitions/BanBannedAdminMessageInterface" }), world: z.string(), jwt: z.string(), }); diff --git a/pusher/src/Services/AdminApi.ts b/pusher/src/Services/AdminApi.ts index eddd3832..cdd2e35b 100644 --- a/pusher/src/Services/AdminApi.ts +++ b/pusher/src/Services/AdminApi.ts @@ -9,7 +9,7 @@ import qs from "qs"; import { AdminInterface } from "./AdminInterface"; import { AuthTokenData, jwtTokenManager } from "./JWTTokenManager"; import { InvalidTokenError } from "../Controller/InvalidTokenError"; -import {extendApi} from "@anatine/zod-openapi"; +import { extendApi } from "@anatine/zod-openapi"; export interface AdminBannedData { is_banned: boolean; @@ -18,15 +18,30 @@ export interface AdminBannedData { export const isFetchMemberDataByUuidResponse = z.object({ // @ts-ignore - email: extendApi(z.string(), {description: 'The email of the fetched user, it can be an email, an uuid or undefined.', example: "example@workadventu.re"}), - userUuid: extendApi(z.string(), {description: 'The uuid of the fetched user, it can be an email, an uuid or undefined.', example: "998ce839-3dea-4698-8b41-ebbdf7688ad9"}), - tags: extendApi(z.array(z.string()), {description: 'List of tags related to the user fetched.', example: ['editor']}), - visitCardUrl: extendApi(z.nullable(z.string()), {description: 'URL of the visitCard of the user fetched.', example: 'https://mycompany.com/contact/me'}), - textures: extendApi(z.array(isWokaDetail), {$ref: "#/definitions/WokaDetail"}), - messages: extendApi(z.array(z.unknown()), {description: 'List of user\'s messages.'}), + email: extendApi(z.string(), { + description: "The email of the fetched user, it can be an email, an uuid or undefined.", + example: "example@workadventu.re", + }), + userUuid: extendApi(z.string(), { + description: "The uuid of the fetched user, it can be an email, an uuid or undefined.", + example: "998ce839-3dea-4698-8b41-ebbdf7688ad9", + }), + tags: extendApi(z.array(z.string()), { + description: "List of tags related to the user fetched.", + example: ["editor"], + }), + visitCardUrl: extendApi(z.nullable(z.string()), { + description: "URL of the visitCard of the user fetched.", + example: "https://mycompany.com/contact/me", + }), + textures: extendApi(z.array(isWokaDetail), { $ref: "#/definitions/WokaDetail" }), + messages: extendApi(z.array(z.unknown()), { description: "List of user's messages." }), - anonymous: extendApi(z.optional(z.boolean()), {description: 'Whether the user if logged as anonymous or not', example: false}), - userRoomToken: extendApi(z.optional(z.string()), {description: '', example: ''}), + anonymous: extendApi(z.optional(z.boolean()), { + description: "Whether the user if logged as anonymous or not", + example: false, + }), + userRoomToken: extendApi(z.optional(z.string()), { description: "", example: "" }), }); export type FetchMemberDataByUuidResponse = z.infer; diff --git a/pusher/src/Services/SwaggerGenerator.ts b/pusher/src/Services/SwaggerGenerator.ts index 15fe9d4a..fcda50d0 100644 --- a/pusher/src/Services/SwaggerGenerator.ts +++ b/pusher/src/Services/SwaggerGenerator.ts @@ -1,40 +1,33 @@ -import {generateSchema} from "@anatine/zod-openapi"; -import {isAdminApiData} from "../Messages/JsonMessages/AdminApiData"; +import { generateSchema } from "@anatine/zod-openapi"; +import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData"; import { isErrorApiErrorData, isErrorApiRedirectData, isErrorApiRetryData, - isErrorApiUnauthorizedData + isErrorApiUnauthorizedData, } from "../Messages/JsonMessages/ErrorApiData"; -import {isMapDetailsData} from "../Messages/JsonMessages/MapDetailsData"; -import {isRegisterData} from "../Messages/JsonMessages/RegisterData"; -import {isRoomRedirect} from "../Messages/JsonMessages/RoomRedirect"; -import {isFetchMemberDataByUuidResponse} from "./AdminApi"; -import { - isBanBannedAdminMessageInterface, isListenRoomsMessageInterface, - isUserMessageAdminMessageInterface -} from "../Model/Websocket/Admin/AdminMessages"; -import {isWokaDetail} from "../Messages/JsonMessages/PlayerTextures"; +import { isMapDetailsData } from "../Messages/JsonMessages/MapDetailsData"; +import { isFetchMemberDataByUuidResponse } from "./AdminApi"; +import { isWokaDetail } from "../Messages/JsonMessages/PlayerTextures"; class SwaggerGenerator { definitions() { return { - definitions: - { - AdminApiData: generateSchema(isAdminApiData), - //BanBannedAdminMessageInterface: generateSchema(isBanBannedAdminMessageInterface), - ErrorApiErrorData: generateSchema(isErrorApiErrorData), - ErrorApiRedirectData: generateSchema(isErrorApiRedirectData), - ErrorApiRetryData: generateSchema(isErrorApiRetryData), - ErrorApiUnauthorizedData: generateSchema(isErrorApiUnauthorizedData), - FetchMemberDataByUuidResponse: generateSchema(isFetchMemberDataByUuidResponse), - //ListenRoomsMessageInterface: generateSchema(isListenRoomsMessageInterface), - MapDetailsData: generateSchema(isMapDetailsData), - //RegisterData: generateSchema(isRegisterData), - //RoomRedirect: generateSchema(isRoomRedirect), - //UserMessageAdminMessageInterface: generateSchema(isUserMessageAdminMessageInterface), - WokaDetail: generateSchema(isWokaDetail), - } + definitions: { + AdminApiData: generateSchema(isAdminApiData), + //BanBannedAdminMessageInterface: generateSchema(isBanBannedAdminMessageInterface), + ErrorApiErrorData: generateSchema(isErrorApiErrorData), + ErrorApiRedirectData: generateSchema(isErrorApiRedirectData), + ErrorApiRetryData: generateSchema(isErrorApiRetryData), + ErrorApiUnauthorizedData: generateSchema(isErrorApiUnauthorizedData), + FetchMemberDataByUuidResponse: generateSchema(isFetchMemberDataByUuidResponse), + //ListenRoomsMessageInterface: generateSchema(isListenRoomsMessageInterface), + MapDetailsData: generateSchema(isMapDetailsData), + //RegisterData: generateSchema(isRegisterData), + //RoomRedirect: generateSchema(isRoomRedirect), + //UserMessageAdminMessageInterface: generateSchema(isUserMessageAdminMessageInterface), + WokaDetail: generateSchema(isWokaDetail), + }, }; } }