Add new Swagger Doc for the pusher
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import { BaseHttpController } from "./BaseHttpController";
|
||||
import * as fs from "fs";
|
||||
import { ADMIN_URL } from "../Enum/EnvironmentVariable";
|
||||
import SwaggerGenerator from "../Services/SwaggerGenerator";
|
||||
import swaggerJsdoc from "swagger-jsdoc";
|
||||
|
||||
export class SwaggerController extends BaseHttpController {
|
||||
routes() {
|
||||
this.app.get("/openapi", (req, res) => {
|
||||
this.app.get("/openapi/pusher", (req, res) => {
|
||||
// Let's load the module dynamically (it may not exist in prod because part of the -dev packages)
|
||||
const swaggerJsdoc = require("swagger-jsdoc");
|
||||
const options = {
|
||||
@@ -20,6 +23,43 @@ export class SwaggerController extends BaseHttpController {
|
||||
res.json(swaggerJsdoc(options));
|
||||
});
|
||||
|
||||
this.app.get("/openapi/admin", (req, res) => {
|
||||
// Let's load the module dynamically (it may not exist in prod because part of the -dev packages)
|
||||
const swaggerJsdoc = require("swagger-jsdoc");
|
||||
const options = {
|
||||
swaggerDefinition: {
|
||||
swagger: "2.0",
|
||||
//openapi: "3.0.0",
|
||||
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"
|
||||
}
|
||||
},
|
||||
"host": "pusher." + ADMIN_URL.replace('//',''),
|
||||
"tags": [
|
||||
{
|
||||
"name": "AdminAPI",
|
||||
"description": "Access to end points of the admin from the pusher"
|
||||
},
|
||||
],
|
||||
"securityDefinitions": {
|
||||
"Bearer": {
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
},
|
||||
...SwaggerGenerator.definitions()
|
||||
},
|
||||
apis: ["./src/Services/*.ts"],
|
||||
};
|
||||
res.json(swaggerJsdoc(options));
|
||||
});
|
||||
|
||||
// Create a LiveDirectory instance to virtualize directory with our assets
|
||||
// @ts-ignore
|
||||
const LiveDirectory = require("live-directory");
|
||||
@@ -39,8 +79,13 @@ export class SwaggerController extends BaseHttpController {
|
||||
if (err) {
|
||||
return response.status(500).send(err.message);
|
||||
}
|
||||
const result = data.replace(/https:\/\/petstore\.swagger\.io\/v2\/swagger.json/g, "/openapi");
|
||||
|
||||
const urls = [
|
||||
{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"`);
|
||||
response.send(result);
|
||||
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import {extendApi} from "@anatine/zod-openapi";
|
||||
|
||||
export const isBanBannedAdminMessageInterface = z.object({
|
||||
type: z.enum(["ban", "banned"]),
|
||||
@@ -8,7 +9,7 @@ export const isBanBannedAdminMessageInterface = z.object({
|
||||
|
||||
export const isUserMessageAdminMessageInterface = z.object({
|
||||
event: z.enum(["user-message"]),
|
||||
message: isBanBannedAdminMessageInterface,
|
||||
message: extendApi(isBanBannedAdminMessageInterface, {$ref: "#/definitions/BanBannedAdminMessageInterface"}),
|
||||
world: z.string(),
|
||||
jwt: z.string(),
|
||||
});
|
||||
|
||||
+252
-12
@@ -9,6 +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";
|
||||
|
||||
export interface AdminBannedData {
|
||||
is_banned: boolean;
|
||||
@@ -16,15 +17,16 @@ export interface AdminBannedData {
|
||||
}
|
||||
|
||||
export const isFetchMemberDataByUuidResponse = z.object({
|
||||
email: z.string(),
|
||||
userUuid: z.string(),
|
||||
tags: z.array(z.string()),
|
||||
visitCardUrl: z.nullable(z.string()),
|
||||
textures: z.array(isWokaDetail),
|
||||
messages: z.array(z.unknown()),
|
||||
// @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.'}),
|
||||
|
||||
anonymous: z.optional(z.boolean()),
|
||||
userRoomToken: z.optional(z.string()),
|
||||
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<typeof isFetchMemberDataByUuidResponse>;
|
||||
@@ -69,6 +71,47 @@ class AdminApi implements AdminInterface {
|
||||
userId,
|
||||
};
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /api/map:
|
||||
* get:
|
||||
* tags: ["AdminAPI"]
|
||||
* description: Returns a map mapping map name to file name of the map
|
||||
* security:
|
||||
* - Bearer: []
|
||||
* produces:
|
||||
* - "application/json"
|
||||
* parameters:
|
||||
* - name: "playUri"
|
||||
* in: "query"
|
||||
* description: "The full URL of WorkAdventure"
|
||||
* required: true
|
||||
* type: "string"
|
||||
* example: "http://play.workadventure.localhost/@/teamSlug/worldSLug/roomSlug"
|
||||
* - name: "userId"
|
||||
* in: "query"
|
||||
* description: "The identifier of the current user \n It can be undefined or an uuid or an email"
|
||||
* type: "string"
|
||||
* example: "998ce839-3dea-4698-8b41-ebbdf7688ad9"
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The details of the member
|
||||
* schema:
|
||||
* $ref: "#/definitions/MapDetailsData"
|
||||
* 401:
|
||||
* description: Error while retrieving the data because you are not authorized
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiRedirectData'
|
||||
* 403:
|
||||
* description: Error while retrieving the data because you are not authorized
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiUnauthorizedData'
|
||||
* 404:
|
||||
* description: Error while retrieving the data
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiErrorData'
|
||||
*
|
||||
*/
|
||||
const res = await Axios.get<unknown, AxiosResponse<unknown>>(ADMIN_API_URL + "/api/map", {
|
||||
headers: { Authorization: `${ADMIN_API_TOKEN}`, "Accept-Language": locale ?? "en" },
|
||||
params,
|
||||
@@ -99,6 +142,58 @@ class AdminApi implements AdminInterface {
|
||||
characterLayers: string[],
|
||||
locale?: string
|
||||
): Promise<FetchMemberDataByUuidResponse> {
|
||||
/**
|
||||
* @openapi
|
||||
* /api/room/access:
|
||||
* get:
|
||||
* tags: ["AdminAPI"]
|
||||
* description: Returns member's informations if he can access this room
|
||||
* security:
|
||||
* - Bearer: []
|
||||
* produces:
|
||||
* - "application/json"
|
||||
* parameters:
|
||||
* - name: "userIdentifier"
|
||||
* in: "query"
|
||||
* description: "The identifier of the current user \n It can be undefined or an uuid or an email"
|
||||
* type: "string"
|
||||
* example: "998ce839-3dea-4698-8b41-ebbdf7688ad9"
|
||||
* - name: "playUri"
|
||||
* in: "query"
|
||||
* description: "The full URL of WorkAdventure"
|
||||
* required: true
|
||||
* type: "string"
|
||||
* example: "http://play.workadventure.localhost/@/teamSlug/worldSLug/roomSlug"
|
||||
* - name: "ipAddress"
|
||||
* in: "query"
|
||||
* required: true
|
||||
* type: "string"
|
||||
* example: "127.0.0.1"
|
||||
* - name: "characterLayers"
|
||||
* in: "query"
|
||||
* type: "array"
|
||||
* items:
|
||||
* type: string
|
||||
* example: ["male1"]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The details of the member
|
||||
* schema:
|
||||
* $ref: "#/definitions/FetchMemberDataByUuidResponse"
|
||||
* 401:
|
||||
* description: Error while retrieving the data because you are not authorized
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiRedirectData'
|
||||
* 403:
|
||||
* description: Error while retrieving the data because you are not authorized
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiUnauthorizedData'
|
||||
* 404:
|
||||
* description: Error while retrieving the data
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiErrorData'
|
||||
*
|
||||
*/
|
||||
const res = await Axios.get<unknown, AxiosResponse<unknown>>(ADMIN_API_URL + "/api/room/access", {
|
||||
params: {
|
||||
userIdentifier,
|
||||
@@ -130,6 +225,42 @@ class AdminApi implements AdminInterface {
|
||||
playUri: string | null,
|
||||
locale?: string
|
||||
): Promise<AdminApiData> {
|
||||
/**
|
||||
* @openapi
|
||||
* /api/login-url/{organizationMemberToken}:
|
||||
* get:
|
||||
* tags: ["AdminAPI"]
|
||||
* description: Returns a member from the token
|
||||
* security:
|
||||
* - Bearer: []
|
||||
* produces:
|
||||
* - "application/json"
|
||||
* parameters:
|
||||
* - name: "organizationMemberToken"
|
||||
* in: "path"
|
||||
* description: "The token of member in the organization"
|
||||
* type: "string"
|
||||
* - name: "playUri"
|
||||
* in: "query"
|
||||
* description: "The full URL of WorkAdventure"
|
||||
* required: true
|
||||
* type: "string"
|
||||
* example: "http://play.workadventure.localhost/@/teamSlug/worldSLug/roomSlug"
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The details of the member
|
||||
* schema:
|
||||
* $ref: "#/definitions/AdminApiData"
|
||||
* 401:
|
||||
* description: Error while retrieving the data because you are not authorized
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiRedirectData'
|
||||
* 404:
|
||||
* description: Error while retrieving the data
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiErrorData'
|
||||
*
|
||||
*/
|
||||
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
|
||||
const res = await Axios.get(ADMIN_API_URL + "/api/login-url/" + organizationMemberToken, {
|
||||
params: { playUri },
|
||||
@@ -154,6 +285,41 @@ class AdminApi implements AdminInterface {
|
||||
reportWorldSlug: string,
|
||||
locale?: string
|
||||
) {
|
||||
/**
|
||||
* @openapi
|
||||
* /api/report:
|
||||
* post:
|
||||
* tags: ["AdminAPI"]
|
||||
* description: Report one user with a comment
|
||||
* security:
|
||||
* - Bearer: []
|
||||
* produces:
|
||||
* - "application/json"
|
||||
* parameters:
|
||||
* - name: "reportedUserUuid"
|
||||
* in: "query"
|
||||
* description: "The identifier of the reported user \n It can be an uuid or an email"
|
||||
* type: "string"
|
||||
* example: "998ce839-3dea-4698-8b41-ebbdf7688ad9"
|
||||
* - name: "reportedUserComment"
|
||||
* in: "query"
|
||||
* description: "The comment of the report"
|
||||
* required: true
|
||||
* type: "string"
|
||||
* - name: "reporterUserUuid"
|
||||
* in: "query"
|
||||
* description: "The identifier of the reporter user \n It can be an uuid or an email"
|
||||
* type: "string"
|
||||
* example: "998ce839-3dea-4698-8b41-ebbdf7688ad8"
|
||||
* - name: "reportWorldSlug"
|
||||
* in: "query"
|
||||
* description: "The slug of the world where the report is made"
|
||||
* type: "string"
|
||||
* example: "/@/teamSlug/worldSlug/roomSlug"
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The report has been successfully saved
|
||||
*/
|
||||
return Axios.post(
|
||||
`${ADMIN_API_URL}/api/report`,
|
||||
{
|
||||
@@ -174,6 +340,53 @@ class AdminApi implements AdminInterface {
|
||||
roomUrl: string,
|
||||
locale?: string
|
||||
): Promise<AdminBannedData> {
|
||||
/**
|
||||
* @openapi
|
||||
* /api/ban:
|
||||
* get:
|
||||
* tags: ["AdminAPI"]
|
||||
* description: Check if user is banned or not
|
||||
* security:
|
||||
* - Bearer: []
|
||||
* produces:
|
||||
* - "application/json"
|
||||
* parameters:
|
||||
* - name: "ipAddress"
|
||||
* in: "query"
|
||||
* type: "string"
|
||||
* required: true
|
||||
* example: "127.0.0.1"
|
||||
* - name: "token"
|
||||
* in: "query"
|
||||
* description: "The uuid of the user \n It can be an uuid or an email"
|
||||
* type: "string"
|
||||
* required: true
|
||||
* example: "998ce839-3dea-4698-8b41-ebbdf7688ad8"
|
||||
* - name: "roomUrl"
|
||||
* in: "query"
|
||||
* description: "The slug of the world where to check if the user is banned"
|
||||
* type: "string"
|
||||
* required: true
|
||||
* example: "/@/teamSlug/worldSlug/roomSlug"
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The user is banned or not
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* required:
|
||||
* - is_banned
|
||||
* properties:
|
||||
* is_banned:
|
||||
* type: boolean
|
||||
* description: Whether the user is banned or not
|
||||
* example: true
|
||||
* 404:
|
||||
* description: Error while retrieving the data
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiErrorData'
|
||||
*/
|
||||
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
|
||||
return Axios.get(
|
||||
ADMIN_API_URL +
|
||||
@@ -191,6 +404,37 @@ class AdminApi implements AdminInterface {
|
||||
}
|
||||
|
||||
async getUrlRoomsFromSameWorld(roomUrl: string, locale?: string): Promise<string[]> {
|
||||
/**
|
||||
* @openapi
|
||||
* /api/room/sameWorld:
|
||||
* get:
|
||||
* tags: ["AdminAPI"]
|
||||
* description: Get all URLs of the rooms from the world specified
|
||||
* security:
|
||||
* - Bearer: []
|
||||
* produces:
|
||||
* - "application/json"
|
||||
* parameters:
|
||||
* - name: "roomUrl"
|
||||
* in: "query"
|
||||
* description: "The slug of the room"
|
||||
* type: "string"
|
||||
* required: true
|
||||
* example: "/@/teamSlug/worldSlug/roomSlug"
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The list of URL of the rooms from the same world
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* description: URL of a room
|
||||
* example: "http://example.com/@/teamSlug/worldSlug/room2Slug"
|
||||
* 404:
|
||||
* description: Error while retrieving the data
|
||||
* schema:
|
||||
* $ref: '#/definitions/ErrorApiErrorData'
|
||||
*/
|
||||
return Axios.get(ADMIN_API_URL + "/api/room/sameWorld" + "?roomUrl=" + encodeURIComponent(roomUrl), {
|
||||
headers: { Authorization: `${ADMIN_API_TOKEN}`, "Accept-Language": locale ?? "en" },
|
||||
}).then((data) => {
|
||||
@@ -204,10 +448,6 @@ class AdminApi implements AdminInterface {
|
||||
}
|
||||
return `${OPID_PROFILE_SCREEN_PROVIDER}?accessToken=${accessToken}`;
|
||||
}
|
||||
|
||||
async logoutOauth(token: string): Promise<void> {
|
||||
await Axios.get(ADMIN_API_URL + `/oauth/logout?token=${token}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const adminApi = new AdminApi();
|
||||
|
||||
@@ -74,9 +74,4 @@ export interface AdminInterface {
|
||||
* @return string
|
||||
*/
|
||||
getProfileUrl(accessToken: string): string;
|
||||
|
||||
/**
|
||||
* @param token
|
||||
*/
|
||||
logoutOauth(token: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -87,10 +87,6 @@ class LocalAdmin implements AdminInterface {
|
||||
new Error("No admin backoffice set!");
|
||||
return "";
|
||||
}
|
||||
|
||||
async logoutOauth(token: string): Promise<void> {
|
||||
return Promise.reject(new Error("No admin backoffice set!"));
|
||||
}
|
||||
}
|
||||
|
||||
export const localAdmin = new LocalAdmin();
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import {generateSchema} from "@anatine/zod-openapi";
|
||||
import {isAdminApiData} from "../Messages/JsonMessages/AdminApiData";
|
||||
import {
|
||||
isErrorApiErrorData,
|
||||
isErrorApiRedirectData,
|
||||
isErrorApiRetryData,
|
||||
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";
|
||||
|
||||
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),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default new SwaggerGenerator();
|
||||
Reference in New Issue
Block a user