Merge branch 'dev' into 'staging'
first deploy See merge request pena-services/hub_admin_backend_service!10
This commit is contained in:
commit
ed8b9970e5
@ -2,6 +2,10 @@
|
|||||||
HTTP_HOST=localhost
|
HTTP_HOST=localhost
|
||||||
HTTP_PORT=8080
|
HTTP_PORT=8080
|
||||||
|
|
||||||
|
# Auth service
|
||||||
|
AUTH_SERVICE_HOST=http://localhost
|
||||||
|
AUTH_SERVICE_PORT=8081
|
||||||
|
|
||||||
# Database Options
|
# Database Options
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=27017
|
DB_PORT=27017
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"props": true,
|
"props": true,
|
||||||
"ignorePropertyModificationsFor": ["accamulator"]
|
"ignorePropertyModificationsFor": ["accamulator", "request"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"object-shorthand": "off",
|
"object-shorthand": "off",
|
||||||
|
3
.gitlab-ci.yml
Normal file
3
.gitlab-ci.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
include:
|
||||||
|
- project: "devops/pena-continuous-integration"
|
||||||
|
file: "/nodejs/docker/nodejs.gitlab-ci.yml"
|
@ -1,4 +1,4 @@
|
|||||||
FROM node:16-alpine as dev
|
FROM node:19.1-alpine as dev
|
||||||
|
|
||||||
RUN apk update && rm -rf /var/cache/apk/*
|
RUN apk update && rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ RUN ls
|
|||||||
|
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM node:16-alpine as production
|
FROM node:19.1-alpine as production
|
||||||
|
|
||||||
RUN apk update && rm -rf /var/cache/apk/*
|
RUN apk update && rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
36
README.md
36
README.md
@ -1,37 +1,3 @@
|
|||||||
# Hub Admin Panel Backend Service
|
# Hub Admin Panel Backend Service
|
||||||
|
|
||||||
## Настройка и запуск
|
**Вся основная документация расположена в** [**Wiki**](https://penahub.gitlab.yandexcloud.net/pena-services/hub_admin_backend_service/-/wikis/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5)
|
||||||
|
|
||||||
```
|
|
||||||
1) yarn setup - загрузка всех зависимостей и инициализация husky
|
|
||||||
2) yarn dev - запуск проекта в режиме разработки
|
|
||||||
```
|
|
||||||
|
|
||||||
## Переменные окружения сервиса:
|
|
||||||
|
|
||||||
**Для конфигурации сервера**:
|
|
||||||
|
|
||||||
```
|
|
||||||
ENVIRONMENT - application environment
|
|
||||||
HTTP_HOST - service host
|
|
||||||
HTTP_PORT - service port
|
|
||||||
PUBLIC_ACCESS_SECRET_KEY - secret to verify private access secret key
|
|
||||||
```
|
|
||||||
|
|
||||||
**Для конфигурации базы данных**:
|
|
||||||
|
|
||||||
```
|
|
||||||
DB_HOST - mongo host
|
|
||||||
DB_PORT - mongo port
|
|
||||||
DB_USERNAME - mongo username
|
|
||||||
DB_PASSWORD - mongo password
|
|
||||||
DB_NAME - database name
|
|
||||||
```
|
|
||||||
|
|
||||||
## Среды окружения
|
|
||||||
|
|
||||||
```
|
|
||||||
development - среда для разработки
|
|
||||||
staging - среда для тестирования продукта
|
|
||||||
production - среда продакшена
|
|
||||||
```
|
|
||||||
|
28
deployments/staging/docker-compose.yaml
Normal file
28
deployments/staging/docker-compose.yaml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
version: "3.3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
admin:
|
||||||
|
container_name: hub-admin-backend-service
|
||||||
|
restart: unless-stopped
|
||||||
|
tty: true
|
||||||
|
image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||||
|
expose:
|
||||||
|
- 8005
|
||||||
|
networks:
|
||||||
|
- marketplace_penahub_frontend
|
||||||
|
- default
|
||||||
|
environment:
|
||||||
|
- DB_HOST=10.6.0.11
|
||||||
|
- DB_PORT=27017
|
||||||
|
- ENVIRONMENT=staging
|
||||||
|
- HTTP_HOST=0.0.0.0
|
||||||
|
- HTTP_PORT=8005
|
||||||
|
- AUTH_SERVICE_HOST=http://pena-auth-service
|
||||||
|
- AUTH_SERVICE_PORT=8000
|
||||||
|
- DB_USERNAME=$DB_USERNAME
|
||||||
|
- DB_PASSWORD=$DB_PASSWORD
|
||||||
|
- DB_NAME=administrator
|
||||||
|
- PUBLIC_ACCESS_SECRET_KEY=$PUBLIC_ACCESS_SECRET_KEY
|
||||||
|
networks:
|
||||||
|
marketplace_penahub_frontend:
|
||||||
|
external: true
|
14
docs/server/README.md
Normal file
14
docs/server/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Настройки сервера:
|
||||||
|
|
||||||
|
В папке `./src/constants` лежат два файла конфигурации:
|
||||||
|
|
||||||
|
- `configurations.ts`
|
||||||
|
- `default.ts`
|
||||||
|
|
||||||
|
**configurations.ts**
|
||||||
|
|
||||||
|
Хранит в себе конфигурации сервиса, загружаемые через `ENV`. В основном хранит в себе данные о подключении к БД и адреса прослушивания запросов сервером.
|
||||||
|
|
||||||
|
**default.ts**
|
||||||
|
|
||||||
|
Хранит в себе стандартные значения и настройки подключаемых модулей, такие как: `fastify`, `swagger`.
|
38
docs/swagger/README.md
Normal file
38
docs/swagger/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Swagger:
|
||||||
|
|
||||||
|
При запуске сервиса, документацию можно будет изучить по отдельной ссылке, которая выдаётся сервисом
|
||||||
|
|
||||||
|
**Ссылка на Swagger документацию**: `<hostname>/swagger`
|
||||||
|
|
||||||
|
## Архитектура Swagger документации (Для разработчиков):
|
||||||
|
|
||||||
|
```
|
||||||
|
├── privilege
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── inputs.ts
|
||||||
|
│ ├── models.ts
|
||||||
|
│ ├── responses.ts
|
||||||
|
├── tariff
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── inputs.ts
|
||||||
|
│ ├── models.ts
|
||||||
|
│ ├── responses.ts
|
||||||
|
├── role
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── inputs.ts
|
||||||
|
│ ├── models.ts
|
||||||
|
│ ├── responses.ts
|
||||||
|
├── account
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── inputs.ts
|
||||||
|
│ ├── models.ts
|
||||||
|
│ ├── responses.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
- Каждая из директорий является названием группы обработчиков (`routes`)
|
||||||
|
|
||||||
|
- `index` выдаёт все схемы для генерации документации
|
||||||
|
|
||||||
|
- `inputs` содержит в себе все входные данные, требуемые обработчику: _`params`_, _`querystring`_, _`body`_
|
||||||
|
|
||||||
|
- `models` хранит в себе все бизнес модели: _`user`_, _`tariff`_, _`role`_
|
@ -23,6 +23,7 @@
|
|||||||
"@fastify/cookie": "^8.3.0",
|
"@fastify/cookie": "^8.3.0",
|
||||||
"@fastify/cors": "^8.2.0",
|
"@fastify/cors": "^8.2.0",
|
||||||
"@fastify/jwt": "^6.3.3",
|
"@fastify/jwt": "^6.3.3",
|
||||||
|
"axios": "^1.2.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"fastify": "^4.9.2",
|
"fastify": "^4.9.2",
|
||||||
@ -36,6 +37,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.1.2",
|
"@commitlint/cli": "^17.1.2",
|
||||||
"@commitlint/config-conventional": "^17.1.0",
|
"@commitlint/config-conventional": "^17.1.0",
|
||||||
|
"@fastify/swagger": "^8.2.1",
|
||||||
|
"@fastify/swagger-ui": "^1.3.0",
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
"@types/jest": "^29.2.3",
|
"@types/jest": "^29.2.3",
|
||||||
"@types/jsonwebtoken": "^8.5.9",
|
"@types/jsonwebtoken": "^8.5.9",
|
||||||
|
16
src/clients/auth/index.ts
Normal file
16
src/clients/auth/index.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { authService } from "./instance";
|
||||||
|
|
||||||
|
import type { User } from "@/types/models/user.type";
|
||||||
|
import type { GetUserRequest } from "./types";
|
||||||
|
|
||||||
|
export const getUser = async (request: GetUserRequest): Promise<User | null> => {
|
||||||
|
try {
|
||||||
|
const { data } = await authService.get<User>(`/user/${request.id}`);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (nativeError) {
|
||||||
|
console.error(nativeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
7
src/clients/auth/instance.ts
Normal file
7
src/clients/auth/instance.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
import { CONFIGURATION } from "@/constants/configuration";
|
||||||
|
|
||||||
|
export const authService = axios.create({
|
||||||
|
baseURL: `${CONFIGURATION.authService.host}:${CONFIGURATION.authService.port}`,
|
||||||
|
});
|
3
src/clients/auth/types.ts
Normal file
3
src/clients/auth/types.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type GetUserRequest = {
|
||||||
|
id: string;
|
||||||
|
};
|
@ -1,8 +1,13 @@
|
|||||||
|
import { Router } from "@/server/router";
|
||||||
|
|
||||||
|
import { setAccountRoutes } from "@/routes/account.routes";
|
||||||
|
import { setPrivilegeRoutes } from "@/routes/privilege.routes";
|
||||||
import { setRoleRoutes } from "@/routes/role.routes";
|
import { setRoleRoutes } from "@/routes/role.routes";
|
||||||
|
import { setTariffRoutes } from "@/routes/tariff.routes";
|
||||||
|
|
||||||
import type { FastifyInstance } from "fastify";
|
export const combineRoutes = (router: Router): void => {
|
||||||
|
router.group("/role", setRoleRoutes);
|
||||||
export const combineRoutes = (server: FastifyInstance): void => {
|
router.group("/account", setAccountRoutes);
|
||||||
server.register(setRoleRoutes, { prefix: "/role" });
|
router.group("/privilege", setPrivilegeRoutes);
|
||||||
|
router.group("/tariff", setTariffRoutes);
|
||||||
};
|
};
|
||||||
|
@ -1,20 +1,7 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
|
||||||
import { DEFAULT } from "@/constants/default";
|
import { defineEnvironment } from "./define-environment";
|
||||||
|
|
||||||
import type { Environment } from "@/types/environment";
|
|
||||||
|
|
||||||
const defineEnvironment = (): Environment => {
|
|
||||||
const environments: Environment[] = ["development", "staging", "production"];
|
|
||||||
const environment = process.env.ENVIRONMENT as Environment | undefined;
|
|
||||||
|
|
||||||
if (environment && environments.includes(environment)) {
|
|
||||||
return environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DEFAULT.environment;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const configureENV = () => {
|
export const configureENV = () => {
|
||||||
const environment = defineEnvironment();
|
const environment = defineEnvironment();
|
||||||
|
14
src/configuration/define-environment.ts
Normal file
14
src/configuration/define-environment.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { DEFAULT } from "@/constants/default";
|
||||||
|
|
||||||
|
import type { Environment } from "@/types/environment";
|
||||||
|
|
||||||
|
export const defineEnvironment = (): Environment => {
|
||||||
|
const environments: Environment[] = ["development", "staging", "production"];
|
||||||
|
const environment = process.env.ENVIRONMENT as Environment | undefined;
|
||||||
|
|
||||||
|
if (environment && environments.includes(environment)) {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT.environment;
|
||||||
|
};
|
@ -1,9 +1,13 @@
|
|||||||
import cors from "@fastify/cors";
|
import cors from "@fastify/cors";
|
||||||
import cookie from "@fastify/cookie";
|
import cookie from "@fastify/cookie";
|
||||||
import jwt from "@fastify/jwt";
|
import jwt from "@fastify/jwt";
|
||||||
|
import swagger from "@fastify/swagger";
|
||||||
|
import swaggerUI from "@fastify/swagger-ui";
|
||||||
|
|
||||||
import printRoutes from "@/plugins/print-routes";
|
import printRoutes from "@/plugins/print-routes";
|
||||||
|
|
||||||
|
import { DEFAULT } from "@/constants/default";
|
||||||
|
|
||||||
import type { FastifyInstance } from "fastify";
|
import type { FastifyInstance } from "fastify";
|
||||||
import type { PluginsOptions } from "@/types/configuration/plugins-options";
|
import type { PluginsOptions } from "@/types/configuration/plugins-options";
|
||||||
|
|
||||||
@ -11,6 +15,8 @@ export const registerFastifyPlugins = (fastify: FastifyInstance, options: Plugin
|
|||||||
fastify.register(cors, options.cors);
|
fastify.register(cors, options.cors);
|
||||||
fastify.register(cookie, options.cookie);
|
fastify.register(cookie, options.cookie);
|
||||||
fastify.register(jwt, options.jwt);
|
fastify.register(jwt, options.jwt);
|
||||||
|
fastify.register(swagger, DEFAULT.swaggerOptions);
|
||||||
|
fastify.register(swaggerUI, DEFAULT.swaggerUIOptions);
|
||||||
fastify.register(printRoutes);
|
fastify.register(printRoutes);
|
||||||
|
|
||||||
return fastify;
|
return fastify;
|
||||||
|
@ -11,10 +11,11 @@ export const CONFIGURATION = {
|
|||||||
database: process.env.DB_NAME || "database",
|
database: process.env.DB_NAME || "database",
|
||||||
},
|
},
|
||||||
service: {
|
service: {
|
||||||
privateAccessSecretKey: process.env.PRIVATE_ACCESS_SECRET_KEY || "",
|
|
||||||
publicAccessSecretKey: process.env.PUBLIC_ACCESS_SECRET_KEY || "",
|
publicAccessSecretKey: process.env.PUBLIC_ACCESS_SECRET_KEY || "",
|
||||||
privateRefreshSecretKey: process.env.PRIVATE_REFRESH_SECRET_KEY || "",
|
|
||||||
publicRefreshSecretKey: process.env.PUBLIC_REFRESH_SECRET_KEY || "",
|
|
||||||
salt: Number(process.env.SALT) || 10,
|
salt: Number(process.env.SALT) || 10,
|
||||||
},
|
},
|
||||||
|
authService: {
|
||||||
|
host: process.env.AUTH_SERVICE_HOST || "",
|
||||||
|
port: Number(process.env.AUTH_SERVICE_PORT) || 8081,
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -1,10 +1,46 @@
|
|||||||
import type { Environment } from "@/types/environment";
|
import type { FastifyServerOptions } from "fastify";
|
||||||
|
import type { FastifyDynamicSwaggerOptions } from "@fastify/swagger";
|
||||||
|
import type { FastifySwaggerUiOptions } from "@fastify/swagger-ui";
|
||||||
|
|
||||||
type Default = {
|
type Default = {
|
||||||
readonly [key: string]: string;
|
readonly fastifyOptions: FastifyServerOptions;
|
||||||
readonly environment: Environment;
|
readonly swaggerOptions: FastifyDynamicSwaggerOptions;
|
||||||
|
readonly swaggerUIOptions: FastifySwaggerUiOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT: Default = {
|
export const DEFAULT: Default = {
|
||||||
environment: "development",
|
fastifyOptions: {
|
||||||
|
logger: true,
|
||||||
|
ajv: {
|
||||||
|
customOptions: { removeAdditional: "failing" },
|
||||||
|
},
|
||||||
|
bodyLimit: 30 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
swaggerOptions: {
|
||||||
|
openapi: {
|
||||||
|
info: {
|
||||||
|
title: "Hub Admin Backend",
|
||||||
|
description: "Тестирование сервиса админ панели хаба",
|
||||||
|
version: "0.1.0",
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
securitySchemes: {
|
||||||
|
bearer: {
|
||||||
|
description: "Authorization header token, sample: Bearer <token>",
|
||||||
|
type: "http",
|
||||||
|
bearerFormat: "JWT",
|
||||||
|
scheme: "bearer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hideUntagged: true,
|
||||||
|
},
|
||||||
|
swaggerUIOptions: {
|
||||||
|
routePrefix: "/swagger",
|
||||||
|
uiConfig: {
|
||||||
|
docExpansion: "full",
|
||||||
|
deepLinking: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
137
src/handlers/account/index.ts
Normal file
137
src/handlers/account/index.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
import { AccountModel } from "@/models/account.model";
|
||||||
|
import { RoleModel } from "@/models/role.model";
|
||||||
|
|
||||||
|
import { getUser } from "@/clients/auth";
|
||||||
|
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
||||||
|
|
||||||
|
import type { FastifyReply, FastifyRequest } from "fastify";
|
||||||
|
import type { GetAccountRequest, SetAccountRoleRequest } from "./types";
|
||||||
|
|
||||||
|
export const getAllAccounts = async () => AccountModel.find({}).lean();
|
||||||
|
|
||||||
|
export const createAccount = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
if (!Types.ObjectId.isValid(request.user.id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid user id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await AccountModel.findOne({ userId: request.user.id }).lean();
|
||||||
|
|
||||||
|
if (account) {
|
||||||
|
reply.status(409);
|
||||||
|
return new Error("account already exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await getUser({ id: request.user.id });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("user not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const createdAccount = new AccountModel({
|
||||||
|
userId: user._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return createdAccount.save();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAccount = async (request: GetAccountRequest, reply: FastifyReply) => {
|
||||||
|
const [getAccountRequestParams, error] = validateEmptyFields(request.params || {}, ["userId"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(getAccountRequestParams.userId)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid user id");
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccountModel.findOne({ userId: getAccountRequestParams.userId }).lean();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setAccountRole = async (request: SetAccountRoleRequest, reply: FastifyReply) => {
|
||||||
|
const [setAccountRoleBody, error] = validateEmptyFields(request.body || {}, ["userId", "role"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const role = await RoleModel.findOne({ name: setAccountRoleBody.role }).lean();
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("role not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await AccountModel.findOneAndUpdate(
|
||||||
|
{ userId: setAccountRoleBody.userId },
|
||||||
|
{ $set: { role: role.name } }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("account not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return account;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeAccount = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
if (!Types.ObjectId.isValid(request.user.id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid user id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await AccountModel.findOneAndUpdate(
|
||||||
|
{ userId: request.user.id },
|
||||||
|
{ $set: { isDeleted: true, deletedAt: new Date() } }
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("account not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return account;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteAccount = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
if (!Types.ObjectId.isValid(request.user.id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid user id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await AccountModel.findByIdAndDelete({ userId: request.user.id }).lean();
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("account not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return account;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreAccount = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
if (!Types.ObjectId.isValid(request.user.id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid user id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await AccountModel.findOneAndUpdate(
|
||||||
|
{ userId: request.user.id },
|
||||||
|
{ $set: { isDeleted: false } }
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("account not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return account;
|
||||||
|
};
|
14
src/handlers/account/types.ts
Normal file
14
src/handlers/account/types.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import type { FastifyRequest } from "fastify";
|
||||||
|
|
||||||
|
export type GetAccountRequest = FastifyRequest<{
|
||||||
|
Params?: {
|
||||||
|
userId?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type SetAccountRoleRequest = FastifyRequest<{
|
||||||
|
Body: {
|
||||||
|
userId?: string;
|
||||||
|
role?: string;
|
||||||
|
};
|
||||||
|
}>;
|
19
src/handlers/auth/middleware.ts
Normal file
19
src/handlers/auth/middleware.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import type { FastifyRequest, FastifyReply, HookHandlerDoneFunction as Done } from "fastify";
|
||||||
|
|
||||||
|
export const verifyUser = async (request: FastifyRequest, reply: FastifyReply, done: Done) => {
|
||||||
|
try {
|
||||||
|
const { id } = await request.jwtVerify<{ id?: string }>();
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
reply.status(401);
|
||||||
|
return reply.send("user id is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
request.user = { id };
|
||||||
|
} catch (nativeError) {
|
||||||
|
reply.status(401);
|
||||||
|
return reply.send(nativeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
28
src/handlers/privilege/helpers.ts
Normal file
28
src/handlers/privilege/helpers.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import type { Privilege } from "@/types/models/privilege.type";
|
||||||
|
import type { RawPrivilege } from "./types";
|
||||||
|
|
||||||
|
export const validatePrivilege = (privilege: RawPrivilege): Error | null => {
|
||||||
|
const typeValues: typeof privilege.type[] = ["count", "day", "full"];
|
||||||
|
|
||||||
|
if (!typeValues.includes(privilege.type)) {
|
||||||
|
return new Error("invalid <type> value");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(Number(privilege.price))) {
|
||||||
|
return new Error("price must be a number");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const convertPrivilegiesToMap = (privilegies: Privilege[]) => {
|
||||||
|
return privilegies.reduce<Record<string, Privilege[]>>((accamulator, privilege) => {
|
||||||
|
if (!accamulator[privilege.serviceKey]) {
|
||||||
|
accamulator[privilege.serviceKey] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
accamulator[privilege.serviceKey].push(privilege);
|
||||||
|
|
||||||
|
return accamulator;
|
||||||
|
}, {});
|
||||||
|
};
|
329
src/handlers/privilege/index.ts
Normal file
329
src/handlers/privilege/index.ts
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
import { PrivilegeModel } from "@/models/privilege.model";
|
||||||
|
|
||||||
|
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
||||||
|
import { convertPrivilegiesToMap, validatePrivilege } from "./helpers";
|
||||||
|
|
||||||
|
import type { FastifyReply } from "fastify";
|
||||||
|
import type {
|
||||||
|
GetServicePrivilegiesRequest,
|
||||||
|
RegisterPrivilegeRequest,
|
||||||
|
GetPrivilegeRequest,
|
||||||
|
RegisterPrivilegiesRequest,
|
||||||
|
RemovePrivilegeRequest,
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
|
export const registerPrivilegies = async (request: RegisterPrivilegiesRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, errorEmpty] = validateEmptyFields(request.body || {}, ["privilegies"]);
|
||||||
|
|
||||||
|
if (errorEmpty) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestBody.privilegies.length) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("empty privilege array");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const rawPrivilege of requestBody.privilegies) {
|
||||||
|
const errorInvalid = validatePrivilege(rawPrivilege);
|
||||||
|
|
||||||
|
if (errorInvalid) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatePrivilegeRequests = requestBody.privilegies.map(async (privilege) => {
|
||||||
|
await PrivilegeModel.updateOne(
|
||||||
|
{ privilegeId: privilege.privilegeId },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
name: privilege.name,
|
||||||
|
privilegeId: privilege.privilegeId,
|
||||||
|
serviceKey: privilege.serviceKey,
|
||||||
|
description: privilege.description,
|
||||||
|
type: privilege.type,
|
||||||
|
value: privilege.value,
|
||||||
|
price: privilege.price,
|
||||||
|
isDeleted: false,
|
||||||
|
createdAt: new Date(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ upsert: true }
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(updatePrivilegeRequests);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerPrivilege = async (request: RegisterPrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, errorEmpty] = validateEmptyFields(
|
||||||
|
request.body || {},
|
||||||
|
["name", "privilegeId", "serviceKey", "type", "description", "price", "value"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errorEmpty) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorInvalid = validatePrivilege(requestBody);
|
||||||
|
|
||||||
|
if (errorInvalid) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOne({ privilegeId: requestBody.privilegeId }).lean();
|
||||||
|
|
||||||
|
if (privilege) {
|
||||||
|
reply.status(409);
|
||||||
|
return new Error("privilege already exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPrivilege = new PrivilegeModel({
|
||||||
|
name: requestBody.name,
|
||||||
|
privilegeId: requestBody.privilegeId,
|
||||||
|
serviceKey: requestBody.serviceKey,
|
||||||
|
description: requestBody.description,
|
||||||
|
type: requestBody.type,
|
||||||
|
value: requestBody.value,
|
||||||
|
price: requestBody.price,
|
||||||
|
});
|
||||||
|
|
||||||
|
return newPrivilege.save();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAllPrivilegies = async () => PrivilegeModel.find({ isDeleted: false }).lean();
|
||||||
|
|
||||||
|
export const getAllPrivilegiesMap = async () => {
|
||||||
|
const privilegies = await PrivilegeModel.find({ isDeleted: false }).lean();
|
||||||
|
|
||||||
|
if (!privilegies.length) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertPrivilegiesToMap(privilegies);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getServicePrivilegies = async (request: GetServicePrivilegiesRequest, reply: FastifyReply) => {
|
||||||
|
const [requestParams, error] = validateEmptyFields(request.params || {}, ["serviceKey"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PrivilegeModel.find({ serviceKey: requestParams.serviceKey, isDeleted: false }).lean();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPrivilege = async (request: GetPrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [requestParams, error] = validateEmptyFields(request.params || {}, ["privilegeId"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(requestParams.privilegeId)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOne({ privilegeId: requestParams.privilegeId, isDeleted: false }).lean();
|
||||||
|
|
||||||
|
if (!privilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("privilege not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replacePrivilege = async (request: RegisterPrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, errorEmpty] = validateEmptyFields(
|
||||||
|
request.body || {},
|
||||||
|
["name", "privilegeId", "serviceKey", "type", "description", "price", "value"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errorEmpty) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorInvalid = validatePrivilege(requestBody);
|
||||||
|
|
||||||
|
if (errorInvalid) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOne({ privilegeId: requestBody.privilegeId });
|
||||||
|
|
||||||
|
if (!privilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("privilege not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
await privilege.replaceOne({
|
||||||
|
name: requestBody.name,
|
||||||
|
privilegeId: requestBody.privilegeId,
|
||||||
|
serviceKey: requestBody.serviceKey,
|
||||||
|
description: requestBody.description,
|
||||||
|
type: requestBody.type,
|
||||||
|
value: requestBody.value,
|
||||||
|
price: requestBody.price,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(replacePrivilegeRequests);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removePrivilege = async (request: RemovePrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [{ privilegeId }, error] = validateEmptyFields(request.body || {}, ["privilegeId"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(privilegeId)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOneAndUpdate(
|
||||||
|
{ privilegeId },
|
||||||
|
{ $set: { isDeleted: true, deletedAt: new Date() } }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!privilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("privilege not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restorePrivilege = async (request: RemovePrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [{ privilegeId }, error] = validateEmptyFields(request.body || {}, ["privilegeId"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(privilegeId)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOneAndUpdate({ privilegeId }, { $set: { isDeleted: false } });
|
||||||
|
|
||||||
|
if (!privilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("privilege not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replacePrivilegies = async (request: RegisterPrivilegiesRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, errorEmpty] = validateEmptyFields(request.body || {}, ["privilegies"]);
|
||||||
|
|
||||||
|
if (errorEmpty) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestBody.privilegies.length) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("empty privilege array");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const rawPrivilege of requestBody.privilegies) {
|
||||||
|
const errorInvalid = validatePrivilege(rawPrivilege);
|
||||||
|
|
||||||
|
if (errorInvalid) {
|
||||||
|
reply.status(400);
|
||||||
|
return errorInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const replacePrivilegeRequests = requestBody.privilegies.map(async (privilege) => {
|
||||||
|
await PrivilegeModel.replaceOne(
|
||||||
|
{ privilegeId: privilege.privilegeId },
|
||||||
|
{
|
||||||
|
name: privilege.name,
|
||||||
|
privilegeId: privilege.privilegeId,
|
||||||
|
serviceKey: privilege.serviceKey,
|
||||||
|
description: privilege.description,
|
||||||
|
type: privilege.type,
|
||||||
|
value: privilege.value,
|
||||||
|
price: privilege.price,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
isDeleted: false,
|
||||||
|
}
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(replacePrivilegeRequests);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removePrivilege = async (request: RemovePrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [{ privilegeId }, error] = validateEmptyFields(request.body || {}, ["privilegeId"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(privilegeId)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOneAndUpdate(
|
||||||
|
{ privilegeId },
|
||||||
|
{ $set: { isDeleted: true, deletedAt: new Date() } }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!privilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("privilege not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restorePrivilege = async (request: RemovePrivilegeRequest, reply: FastifyReply) => {
|
||||||
|
const [{ privilegeId }, error] = validateEmptyFields(request.body || {}, ["privilegeId"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(privilegeId)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilege = await PrivilegeModel.findOneAndUpdate({ privilegeId }, { $set: { isDeleted: false } });
|
||||||
|
|
||||||
|
if (!privilege) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("privilege not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return privilege;
|
||||||
|
};
|
39
src/handlers/privilege/types.ts
Normal file
39
src/handlers/privilege/types.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { FastifyRequest } from "fastify";
|
||||||
|
|
||||||
|
export type RawPrivilege = {
|
||||||
|
name?: string;
|
||||||
|
privilegeId?: string;
|
||||||
|
serviceKey?: string;
|
||||||
|
description?: string;
|
||||||
|
type?: string;
|
||||||
|
value?: string;
|
||||||
|
price?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RegisterPrivilegeRequest = FastifyRequest<{
|
||||||
|
Body?: RawPrivilege;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type RegisterPrivilegiesRequest = FastifyRequest<{
|
||||||
|
Body?: {
|
||||||
|
privilegies?: RawPrivilege[];
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type GetServicePrivilegiesRequest = FastifyRequest<{
|
||||||
|
Params?: {
|
||||||
|
serviceKey?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type GetPrivilegeRequest = FastifyRequest<{
|
||||||
|
Params?: {
|
||||||
|
privilegeId?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type RemovePrivilegeRequest = FastifyRequest<{
|
||||||
|
Body?: {
|
||||||
|
privilegeId?: string;
|
||||||
|
};
|
||||||
|
}>;
|
@ -73,33 +73,32 @@ export const removeRole = async (request: RemoveRoleRequest, reply: FastifyReply
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => {
|
export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => {
|
||||||
const { name, id } = request.body || {};
|
|
||||||
const { query } = request.params || {};
|
const { query } = request.params || {};
|
||||||
|
|
||||||
if (!name && !id && !query) {
|
|
||||||
reply.status(400);
|
|
||||||
return new Error("either name or id must be filled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name || id) {
|
|
||||||
return RoleModel.findOne({
|
|
||||||
$or: [
|
|
||||||
{ name, isDeleted: false },
|
|
||||||
{ id, isDeleted: false },
|
|
||||||
],
|
|
||||||
}).lean();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!query) {
|
if (!query) {
|
||||||
reply.status(400);
|
reply.status(400);
|
||||||
return new Error("query is empty");
|
return new Error("query is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Types.ObjectId.isValid(query)) {
|
if (Types.ObjectId.isValid(query)) {
|
||||||
return RoleModel.findOne({ _id: new Types.ObjectId(query), isDeleted: false }).lean();
|
const role = await RoleModel.findOne({ _id: new Types.ObjectId(query), isDeleted: false }).lean();
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("role not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RoleModel.findOne({ name: query, isDeleted: false }).lean();
|
const role = await RoleModel.findOne({ name: query, isDeleted: false }).lean();
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("role not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return role;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyReply) => {
|
export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyReply) => {
|
||||||
|
@ -9,9 +9,6 @@ export type CreateRoleRequest = FastifyRequest<{ Body: RoleRequest }>;
|
|||||||
export type RemoveRoleRequest = FastifyRequest<{ Body: { id?: string } }>;
|
export type RemoveRoleRequest = FastifyRequest<{ Body: { id?: string } }>;
|
||||||
|
|
||||||
export type GetRoleRequest = FastifyRequest<{
|
export type GetRoleRequest = FastifyRequest<{
|
||||||
Body?: Pick<RoleRequest, "name"> & {
|
|
||||||
id?: string;
|
|
||||||
};
|
|
||||||
Params: {
|
Params: {
|
||||||
query?: string;
|
query?: string;
|
||||||
};
|
};
|
||||||
|
22
src/handlers/tariff/helpers.ts
Normal file
22
src/handlers/tariff/helpers.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
||||||
|
|
||||||
|
import type { TariffMessage } from "@/types/messages/tariff-message.type";
|
||||||
|
import type { ObjectWithRequiredFields } from "@/types/object-with-required-fields";
|
||||||
|
|
||||||
|
export const validateTariff = (tariff?: TariffMessage): [ObjectWithRequiredFields<TariffMessage>, Error | null] => {
|
||||||
|
const [validatedTariff, errorEmpty] = validateEmptyFields(
|
||||||
|
tariff || {},
|
||||||
|
["isCustom", "name", "price", "privilegieIDArray"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errorEmpty) {
|
||||||
|
return [validatedTariff, errorEmpty];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(Number(validatedTariff.price))) {
|
||||||
|
return [validatedTariff, new Error("invalid 'price' value")];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [validatedTariff, null];
|
||||||
|
};
|
200
src/handlers/tariff/index.ts
Normal file
200
src/handlers/tariff/index.ts
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
import { TariffModel } from "@/models/tariff.model";
|
||||||
|
import { PrivilegeModel } from "@/models/privilege.model";
|
||||||
|
|
||||||
|
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
||||||
|
import { validateTariff } from "./helpers";
|
||||||
|
|
||||||
|
import type { FastifyReply } from "fastify";
|
||||||
|
|
||||||
|
import type { Privilege } from "@/types/models/privilege.type";
|
||||||
|
import type { CreateTariffRequest, GetTariffRequest, ReplaceTariffRequest, RemoveTariffRequest } from "./types";
|
||||||
|
|
||||||
|
export const getTariffs = async () => TariffModel.find({}).lean();
|
||||||
|
|
||||||
|
export const getTariff = async (request: GetTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [requestParams, error] = validateEmptyFields(request.params || {}, ["id"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(requestParams.id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findById(requestParams.id).lean();
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createTariff = async (request: CreateTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, error] = validateTariff(request.body);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const privilegeId of requestBody.privilegieIDArray) {
|
||||||
|
if (!Types.ObjectId.isValid(privilegeId)) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error(`privilege id <${privilegeId}> invalid`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilegies = await PrivilegeModel.find({ privilegeId: requestBody.privilegieIDArray }).lean();
|
||||||
|
|
||||||
|
const privilegiesMap = requestBody.privilegieIDArray.reduce<Record<string, Privilege>>((accamulator, privilegeId) => {
|
||||||
|
const findedPrivilege = privilegies.find((privilege) => privilege.privilegeId === privilegeId);
|
||||||
|
|
||||||
|
if (!findedPrivilege) {
|
||||||
|
return accamulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
accamulator[privilegeId] = findedPrivilege;
|
||||||
|
|
||||||
|
return accamulator;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const newTariff = new TariffModel({
|
||||||
|
name: requestBody.name,
|
||||||
|
price: requestBody.price,
|
||||||
|
isCustom: requestBody.isCustom,
|
||||||
|
privilegies: privilegiesMap,
|
||||||
|
});
|
||||||
|
|
||||||
|
await newTariff.save();
|
||||||
|
|
||||||
|
return newTariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceTariff = async (request: ReplaceTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [requestBody, error] = validateTariff(request.body || {});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(request.params?.id || "")) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findById(request.params?.id);
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const privilegeId of requestBody.privilegieIDArray) {
|
||||||
|
if (!Types.ObjectId.isValid(privilegeId)) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error(`privilege id <${privilegeId}> invalid`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const privilegies = await PrivilegeModel.find({ privilegeId: requestBody.privilegieIDArray }).lean();
|
||||||
|
|
||||||
|
const privilegiesMap = requestBody.privilegieIDArray.reduce<Record<string, Privilege>>((accamulator, privilegeId) => {
|
||||||
|
const findedPrivilege = privilegies.find((privilege) => privilege.privilegeId === privilegeId);
|
||||||
|
|
||||||
|
if (!findedPrivilege) {
|
||||||
|
return accamulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
accamulator[privilegeId] = findedPrivilege;
|
||||||
|
|
||||||
|
return accamulator;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
await tariff.replaceOne({
|
||||||
|
name: requestBody.name,
|
||||||
|
price: requestBody.price,
|
||||||
|
isCustom: requestBody.isCustom,
|
||||||
|
privilegies: privilegiesMap,
|
||||||
|
});
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [{ id }, error] = validateEmptyFields(request.body || {}, ["id"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findByIdAndUpdate(id, {
|
||||||
|
$set: { isDeleted: true, deletedAt: new Date() },
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [{ id }, error] = validateEmptyFields(request.body || {}, ["id"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findByIdAndDelete(id).lean();
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => {
|
||||||
|
const [{ id }, error] = validateEmptyFields(request.body || {}, ["id"]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reply.status(400);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Types.ObjectId.isValid(id)) {
|
||||||
|
reply.status(400);
|
||||||
|
return new Error("invalid id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tariff = await TariffModel.findByIdAndUpdate(id, { $set: { isDeleted: false } }).lean();
|
||||||
|
|
||||||
|
if (!tariff) {
|
||||||
|
reply.status(404);
|
||||||
|
return new Error("tariff not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tariff;
|
||||||
|
};
|
23
src/handlers/tariff/types.ts
Normal file
23
src/handlers/tariff/types.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type { FastifyRequest } from "fastify";
|
||||||
|
import type { TariffMessage } from "@/types/messages/tariff-message.type";
|
||||||
|
|
||||||
|
export type GetTariffRequest = FastifyRequest<{
|
||||||
|
Params?: {
|
||||||
|
id?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type RemoveTariffRequest = FastifyRequest<{
|
||||||
|
Body?: {
|
||||||
|
id?: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type CreateTariffRequest = FastifyRequest<{
|
||||||
|
Body?: TariffMessage;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type ReplaceTariffRequest = FastifyRequest<{
|
||||||
|
Body?: TariffMessage;
|
||||||
|
Params?: { id?: string };
|
||||||
|
}>;
|
@ -15,7 +15,11 @@ const server = new Server({
|
|||||||
jwt: {
|
jwt: {
|
||||||
secret: {
|
secret: {
|
||||||
public: CONFIGURATION.service.publicAccessSecretKey,
|
public: CONFIGURATION.service.publicAccessSecretKey,
|
||||||
private: CONFIGURATION.service.privateAccessSecretKey,
|
private: "secret",
|
||||||
|
},
|
||||||
|
verify: {
|
||||||
|
allowedIss: "pena-auth-service",
|
||||||
|
allowedAud: "pena",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
35
src/models/account.model.ts
Normal file
35
src/models/account.model.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
|
import { eloquentSchema } from "./eloquent.schema";
|
||||||
|
|
||||||
|
import type { Account } from "@/types/models/account.type";
|
||||||
|
|
||||||
|
const schema: SchemaDefinition<Account> = {
|
||||||
|
userId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
nickname: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "nickname",
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default: "/media/img/no-avatar.png",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
default: "user",
|
||||||
|
},
|
||||||
|
...eloquentSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
const schemaSettings = {
|
||||||
|
versionKey: false,
|
||||||
|
collection: "accounts",
|
||||||
|
};
|
||||||
|
|
||||||
|
const AccountSchema = new Schema<Account>(schema, schemaSettings);
|
||||||
|
|
||||||
|
export const AccountModel = model("Account", AccountSchema);
|
@ -1,7 +1,8 @@
|
|||||||
import type { SchemaDefinition } from "mongoose";
|
import { SchemaDefinition } from "mongoose";
|
||||||
import type { EloquentModel } from "@/types/models/eloquent-model";
|
|
||||||
|
|
||||||
export const eloquentModelSchema: SchemaDefinition<EloquentModel> = {
|
import type { Eloquent } from "@/types/models/eloquent.type";
|
||||||
|
|
||||||
|
export const eloquentSchema: SchemaDefinition<Eloquent> = {
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true,
|
50
src/models/privilege.model.ts
Normal file
50
src/models/privilege.model.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
|
import { eloquentSchema } from "./eloquent.schema";
|
||||||
|
|
||||||
|
import type { Privilege } from "@/types/models/privilege.type";
|
||||||
|
|
||||||
|
const schema: SchemaDefinition<Privilege> = {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
privilegeId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
serviceKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "count",
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "1",
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
...eloquentSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
const schemaSettings = {
|
||||||
|
versionKey: false,
|
||||||
|
collection: "privilegies",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PrivilegeSchema = new Schema<Privilege>(schema, schemaSettings);
|
||||||
|
|
||||||
|
export const PrivilegeModel = model("Privilege", PrivilegeSchema);
|
@ -1,6 +1,6 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
import { eloquentModelSchema } from "./eloquent-model.schema";
|
import { eloquentSchema } from "./eloquent.schema";
|
||||||
|
|
||||||
import type { Role } from "@/types/models/role.type";
|
import type { Role } from "@/types/models/role.type";
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ const schema: SchemaDefinition<Role> = {
|
|||||||
of: Boolean,
|
of: Boolean,
|
||||||
default: {},
|
default: {},
|
||||||
},
|
},
|
||||||
...eloquentModelSchema,
|
...eloquentSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemaSettings = {
|
const schemaSettings = {
|
||||||
|
36
src/models/tariff.model.ts
Normal file
36
src/models/tariff.model.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Schema, model, SchemaDefinition } from "mongoose";
|
||||||
|
|
||||||
|
import { eloquentSchema } from "./eloquent.schema";
|
||||||
|
import { PrivilegeSchema } from "./privilege.model";
|
||||||
|
|
||||||
|
import type { Tariff } from "@/types/models/tariff.type";
|
||||||
|
|
||||||
|
const schema: SchemaDefinition<Tariff> = {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isCustom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
privilegies: {
|
||||||
|
type: Map,
|
||||||
|
of: PrivilegeSchema,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
...eloquentSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
const schemaSettings = {
|
||||||
|
versionKey: false,
|
||||||
|
collection: "tariffs",
|
||||||
|
};
|
||||||
|
|
||||||
|
const TariffSchema = new Schema<Tariff>(schema, schemaSettings);
|
||||||
|
|
||||||
|
export const TariffModel = model("Tariff", TariffSchema);
|
@ -1,23 +0,0 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
|
||||||
|
|
||||||
import type { Token } from "@/types/models/token.type";
|
|
||||||
|
|
||||||
const schema: SchemaDefinition<Token> = {
|
|
||||||
userId: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
refreshToken: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaSettings = {
|
|
||||||
versionKey: false,
|
|
||||||
collection: "tokens",
|
|
||||||
};
|
|
||||||
|
|
||||||
const TokenSchema = new Schema<Token>(schema, schemaSettings);
|
|
||||||
|
|
||||||
export const TokenModel = model("Token", TokenSchema);
|
|
@ -1,42 +0,0 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
|
||||||
|
|
||||||
import { eloquentModelSchema } from "./eloquent-model.schema";
|
|
||||||
|
|
||||||
import type { User } from "@/types/models/user.type";
|
|
||||||
|
|
||||||
const schema: SchemaDefinition<User> = {
|
|
||||||
login: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
password: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
phoneNumber: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
avatar: {
|
|
||||||
type: String,
|
|
||||||
default: "/media/img/no-avatar.png",
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
type: String,
|
|
||||||
default: "user",
|
|
||||||
},
|
|
||||||
...eloquentModelSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaSettings = {
|
|
||||||
versionKey: false,
|
|
||||||
collection: "users",
|
|
||||||
};
|
|
||||||
|
|
||||||
const UserSchema = new Schema<User>(schema, schemaSettings);
|
|
||||||
|
|
||||||
export const UserModel = model("User", UserSchema);
|
|
@ -8,7 +8,7 @@ type PrintRoutesRouteOptions = {
|
|||||||
|
|
||||||
const METHODS_ORDER = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS"];
|
const METHODS_ORDER = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS"];
|
||||||
|
|
||||||
const printRoutes = (routes: Array<RouteOptions & PrintRoutesRouteOptions> = []) => {
|
const printRoutes = (routes: Array<RouteOptions & PrintRoutesRouteOptions> = [], isSwagger = false) => {
|
||||||
if (routes.length === 0) {
|
if (routes.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -21,8 +21,9 @@ const printRoutes = (routes: Array<RouteOptions & PrintRoutesRouteOptions> = [])
|
|||||||
|
|
||||||
return accamulator + `${methodsValue}\t${route.url}\n`;
|
return accamulator + `${methodsValue}\t${route.url}\n`;
|
||||||
}, "");
|
}, "");
|
||||||
|
const swaggerOutput = isSwagger ? "GET\t/swagger\n" : "";
|
||||||
|
|
||||||
console.info(`\n\nAvailable routes:\n${output}`);
|
console.info(`\n\nAvailable routes:\n${output + swaggerOutput}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fastifyPlugin(
|
export default fastifyPlugin(
|
||||||
@ -34,7 +35,7 @@ export default fastifyPlugin(
|
|||||||
});
|
});
|
||||||
|
|
||||||
instance.addHook("onReady", (next) => {
|
instance.addHook("onReady", (next) => {
|
||||||
printRoutes(routes);
|
printRoutes(routes, !!instance.swagger);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
32
src/routes/account.routes.ts
Normal file
32
src/routes/account.routes.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Router } from "@/server/router";
|
||||||
|
|
||||||
|
import {
|
||||||
|
createAccount,
|
||||||
|
getAccount,
|
||||||
|
setAccountRole,
|
||||||
|
getAllAccounts,
|
||||||
|
deleteAccount,
|
||||||
|
removeAccount,
|
||||||
|
restoreAccount,
|
||||||
|
} from "@/handlers/account";
|
||||||
|
import { verifyUser } from "@/handlers/auth/middleware";
|
||||||
|
|
||||||
|
import {
|
||||||
|
createAccountSchema,
|
||||||
|
getAccountSchema,
|
||||||
|
setAccountRoleSchema,
|
||||||
|
getAccountsSchema,
|
||||||
|
removeAccountSchema,
|
||||||
|
restoreAccountSchema,
|
||||||
|
deleteAccountSchema,
|
||||||
|
} from "@/swagger/account";
|
||||||
|
|
||||||
|
export const setAccountRoutes = (router: Router): void => {
|
||||||
|
router.get("/", getAllAccounts, { schema: getAccountsSchema });
|
||||||
|
router.get("/:userId", getAccount, { schema: getAccountSchema });
|
||||||
|
router.post("/", createAccount, { preHandler: [verifyUser], schema: createAccountSchema });
|
||||||
|
router.post("/restore", restoreAccount, { preHandler: [verifyUser], schema: restoreAccountSchema });
|
||||||
|
router.patch("/role", setAccountRole, { preHandler: [verifyUser], schema: setAccountRoleSchema });
|
||||||
|
router.delete("/", removeAccount, { preHandler: [verifyUser], schema: removeAccountSchema });
|
||||||
|
router.delete("/delete", deleteAccount, { preHandler: [verifyUser], schema: deleteAccountSchema });
|
||||||
|
};
|
40
src/routes/privilege.routes.ts
Normal file
40
src/routes/privilege.routes.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Router } from "@/server/router";
|
||||||
|
|
||||||
|
import {
|
||||||
|
registerPrivilege,
|
||||||
|
getAllPrivilegies,
|
||||||
|
getAllPrivilegiesMap,
|
||||||
|
getPrivilege,
|
||||||
|
getServicePrivilegies,
|
||||||
|
replacePrivilege,
|
||||||
|
registerPrivilegies,
|
||||||
|
removePrivilege,
|
||||||
|
replacePrivilegies,
|
||||||
|
restorePrivilege,
|
||||||
|
} from "@/handlers/privilege";
|
||||||
|
|
||||||
|
import {
|
||||||
|
getPrivilegiesSchema,
|
||||||
|
getPrivilegiesMapSchema,
|
||||||
|
getPrivilegeSchema,
|
||||||
|
getServicePrivilegiesSchema,
|
||||||
|
registerPrivilegeSchema,
|
||||||
|
registerPrivilegiesSchema,
|
||||||
|
replacePrivilegeSchema,
|
||||||
|
replacePrivilegiesSchema,
|
||||||
|
removePrivilegeSchema,
|
||||||
|
restorePrivilegeSchema,
|
||||||
|
} from "@/swagger/privilege";
|
||||||
|
|
||||||
|
export const setPrivilegeRoutes = (router: Router): void => {
|
||||||
|
router.get("/", getAllPrivilegies, { schema: getPrivilegiesSchema });
|
||||||
|
router.get("/service", getAllPrivilegiesMap, { schema: getPrivilegiesMapSchema });
|
||||||
|
router.get("/:privilegeId", getPrivilege, { schema: getPrivilegeSchema });
|
||||||
|
router.get("/service/:serviceKey", getServicePrivilegies, { schema: getServicePrivilegiesSchema });
|
||||||
|
router.post("/", registerPrivilege, { schema: registerPrivilegeSchema });
|
||||||
|
router.post("/many", registerPrivilegies, { schema: registerPrivilegiesSchema });
|
||||||
|
router.post("/restore/", restorePrivilege, { schema: restorePrivilegeSchema });
|
||||||
|
router.put("/", replacePrivilege, { schema: replacePrivilegeSchema });
|
||||||
|
router.put("/many", replacePrivilegies, { schema: replacePrivilegiesSchema });
|
||||||
|
router.delete("/", removePrivilege, { schema: removePrivilegeSchema });
|
||||||
|
};
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Router } from "@/server/router";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getRole,
|
getRole,
|
||||||
getAllRoles,
|
getAllRoles,
|
||||||
@ -9,17 +11,24 @@ import {
|
|||||||
restoreRole,
|
restoreRole,
|
||||||
} from "@/handlers/roles";
|
} from "@/handlers/roles";
|
||||||
|
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from "fastify";
|
import {
|
||||||
|
getRolesSchema,
|
||||||
|
getRoleSchema,
|
||||||
|
createRoleSchema,
|
||||||
|
restoreRoleSchema,
|
||||||
|
updateRoleSchema,
|
||||||
|
replaceRoleSchema,
|
||||||
|
removeRoleSchema,
|
||||||
|
deleteRoleSchema,
|
||||||
|
} from "@/swagger/role";
|
||||||
|
|
||||||
export const setRoleRoutes = <T = FastifyPluginOptions>(server: FastifyInstance, opts: T, done: () => void): void => {
|
export const setRoleRoutes = (router: Router): void => {
|
||||||
server.get("/all", getAllRoles);
|
router.get("/", getAllRoles, { schema: getRolesSchema });
|
||||||
server.get("/:query", getRole);
|
router.get("/:query", getRole, { schema: getRoleSchema });
|
||||||
server.post("/", createRole);
|
router.post("/", createRole, { schema: createRoleSchema });
|
||||||
server.post("/restore", restoreRole);
|
router.post("/restore", restoreRole, { schema: restoreRoleSchema });
|
||||||
server.patch("/:query", updateRole);
|
router.patch("/:query", updateRole, { schema: updateRoleSchema });
|
||||||
server.put("/:query", replaceRole);
|
router.put("/:query", replaceRole, { schema: replaceRoleSchema });
|
||||||
server.delete("/", removeRole);
|
router.delete("/", removeRole, { schema: removeRoleSchema });
|
||||||
server.delete("/delete", deleteRole);
|
router.delete("/delete", deleteRole, { schema: deleteRoleSchema });
|
||||||
|
|
||||||
done();
|
|
||||||
};
|
};
|
||||||
|
32
src/routes/tariff.routes.ts
Normal file
32
src/routes/tariff.routes.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Router } from "@/server/router";
|
||||||
|
|
||||||
|
import {
|
||||||
|
createTariff,
|
||||||
|
replaceTariff,
|
||||||
|
getTariff,
|
||||||
|
getTariffs,
|
||||||
|
removeTariff,
|
||||||
|
restoreTariff,
|
||||||
|
deleteTariff,
|
||||||
|
} from "@/handlers/tariff";
|
||||||
|
import { verifyUser } from "@/handlers/auth/middleware";
|
||||||
|
|
||||||
|
import {
|
||||||
|
getTariffSchema,
|
||||||
|
getTariffsSchema,
|
||||||
|
createTariffsSchema,
|
||||||
|
replaceTariffsSchema,
|
||||||
|
removeTariffsSchema,
|
||||||
|
restoreTariffsSchema,
|
||||||
|
deleteTariffsSchema,
|
||||||
|
} from "@/swagger/tariff";
|
||||||
|
|
||||||
|
export const setTariffRoutes = (router: Router): void => {
|
||||||
|
router.get("/", getTariffs, { schema: getTariffsSchema });
|
||||||
|
router.get("/:id", getTariff, { schema: getTariffSchema });
|
||||||
|
router.post("/", createTariff, { preHandler: [verifyUser], schema: createTariffsSchema });
|
||||||
|
router.post("/restore", restoreTariff, { preHandler: [verifyUser], schema: restoreTariffsSchema });
|
||||||
|
router.put("/:id", replaceTariff, { preHandler: [verifyUser], schema: replaceTariffsSchema });
|
||||||
|
router.delete("/", removeTariff, { preHandler: [verifyUser], schema: removeTariffsSchema });
|
||||||
|
router.delete("/delete", deleteTariff, { preHandler: [verifyUser], schema: deleteTariffsSchema });
|
||||||
|
};
|
@ -1,10 +1,14 @@
|
|||||||
import fastify, { FastifyInstance } from "fastify";
|
import fastify, { FastifyInstance } from "fastify";
|
||||||
import { connect as mongoConnect } from "mongoose";
|
import { connect as mongoConnect } from "mongoose";
|
||||||
|
|
||||||
|
import { Router } from "./router";
|
||||||
|
|
||||||
import { registerFastifyPlugins } from "@/configuration/register-fastify-plugins";
|
import { registerFastifyPlugins } from "@/configuration/register-fastify-plugins";
|
||||||
import { combineRoutes } from "@/configuration/combine-routes";
|
import { combineRoutes } from "@/configuration/combine-routes";
|
||||||
import { constituteMongoURI } from "@/configuration/constitute-mongo-uri";
|
import { constituteMongoURI } from "@/configuration/constitute-mongo-uri";
|
||||||
|
|
||||||
|
import { DEFAULT } from "@/constants/default";
|
||||||
|
|
||||||
import type { PluginsOptions } from "@/types/configuration/plugins-options";
|
import type { PluginsOptions } from "@/types/configuration/plugins-options";
|
||||||
import type { DatabaseOptions } from "@/types/configuration/database-options";
|
import type { DatabaseOptions } from "@/types/configuration/database-options";
|
||||||
|
|
||||||
@ -34,16 +38,13 @@ export class Server {
|
|||||||
constructor({ serverOptions, databaseOptions, pluginsOptions }: ServerArgs) {
|
constructor({ serverOptions, databaseOptions, pluginsOptions }: ServerArgs) {
|
||||||
this.serverOptions = serverOptions;
|
this.serverOptions = serverOptions;
|
||||||
this.databaseOptions = databaseOptions;
|
this.databaseOptions = databaseOptions;
|
||||||
this.fastify = fastify({
|
this.fastify = fastify(DEFAULT.fastifyOptions);
|
||||||
logger: false,
|
|
||||||
bodyLimit: 30 * 1024 * 1024,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (pluginsOptions) {
|
if (pluginsOptions) {
|
||||||
registerFastifyPlugins(this.fastify, pluginsOptions);
|
registerFastifyPlugins(this.fastify, pluginsOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
combineRoutes(this.fastify);
|
combineRoutes(new Router(this.fastify));
|
||||||
}
|
}
|
||||||
|
|
||||||
public start = async () => {
|
public start = async () => {
|
||||||
@ -51,9 +52,10 @@ export class Server {
|
|||||||
const databaseConnection = this.databaseOptions ? mongoConnect(constituteMongoURI(this.databaseOptions)) : null;
|
const databaseConnection = this.databaseOptions ? mongoConnect(constituteMongoURI(this.databaseOptions)) : null;
|
||||||
|
|
||||||
await Promise.all([databaseConnection, fasticyConnection])
|
await Promise.all([databaseConnection, fasticyConnection])
|
||||||
.then(() => console.info(`server started on ${this.serverOptions?.host}:${this.serverOptions?.port}`))
|
.then(() => {
|
||||||
|
this.fastify.swagger();
|
||||||
|
console.info(`server started on ${this.serverOptions?.host}:${this.serverOptions?.port}`);
|
||||||
|
})
|
||||||
.catch((reason) => console.error(reason));
|
.catch((reason) => console.error(reason));
|
||||||
};
|
};
|
||||||
|
|
||||||
public getFastifyInstance = () => this.fastify;
|
|
||||||
}
|
}
|
||||||
|
77
src/server/router.ts
Normal file
77
src/server/router.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import type {
|
||||||
|
FastifyInstance,
|
||||||
|
RouteHandlerMethod,
|
||||||
|
RawRequestDefaultExpression,
|
||||||
|
RawReplyDefaultExpression,
|
||||||
|
RouteShorthandOptions,
|
||||||
|
FastifyPluginOptions,
|
||||||
|
RawServerDefault,
|
||||||
|
RouteGenericInterface,
|
||||||
|
} from "fastify";
|
||||||
|
|
||||||
|
type HandlerMethod<T extends RouteGenericInterface> = RouteHandlerMethod<
|
||||||
|
RawServerDefault,
|
||||||
|
RawRequestDefaultExpression<RawServerDefault>,
|
||||||
|
RawReplyDefaultExpression<RawServerDefault>,
|
||||||
|
T
|
||||||
|
>;
|
||||||
|
|
||||||
|
export class Router {
|
||||||
|
private fastifyInstance: FastifyInstance;
|
||||||
|
|
||||||
|
constructor(fastifyInstance: FastifyInstance) {
|
||||||
|
this.fastifyInstance = fastifyInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public group = (path: string, combineRoutes: (router: Router) => void) => {
|
||||||
|
this.fastifyInstance.register(
|
||||||
|
(server: FastifyInstance, opts: FastifyPluginOptions, done: () => void) => {
|
||||||
|
const router = new Router(server);
|
||||||
|
|
||||||
|
combineRoutes(router);
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
{ prefix: path }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
public get = <T extends RouteGenericInterface>(
|
||||||
|
path: string,
|
||||||
|
handler: HandlerMethod<T>,
|
||||||
|
options: RouteShorthandOptions = {}
|
||||||
|
) => {
|
||||||
|
this.fastifyInstance.get(path, options, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
public post = <T extends RouteGenericInterface>(
|
||||||
|
path: string,
|
||||||
|
handler: HandlerMethod<T>,
|
||||||
|
options: RouteShorthandOptions = {}
|
||||||
|
) => {
|
||||||
|
this.fastifyInstance.post(path, options, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
public put = <T extends RouteGenericInterface>(
|
||||||
|
path: string,
|
||||||
|
handler: HandlerMethod<T>,
|
||||||
|
options: RouteShorthandOptions = {}
|
||||||
|
) => {
|
||||||
|
this.fastifyInstance.put(path, options, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
public patch = <T extends RouteGenericInterface>(
|
||||||
|
path: string,
|
||||||
|
handler: HandlerMethod<T>,
|
||||||
|
options: RouteShorthandOptions = {}
|
||||||
|
) => {
|
||||||
|
this.fastifyInstance.patch(path, options, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
public delete = <T extends RouteGenericInterface>(
|
||||||
|
path: string,
|
||||||
|
handler: HandlerMethod<T>,
|
||||||
|
options: RouteShorthandOptions = {}
|
||||||
|
) => {
|
||||||
|
this.fastifyInstance.delete(path, options, handler);
|
||||||
|
};
|
||||||
|
}
|
154
src/swagger.json
154
src/swagger.json
@ -1,154 +0,0 @@
|
|||||||
{
|
|
||||||
"openapi": "3.0.3",
|
|
||||||
"info": {
|
|
||||||
"title": "PenaHub Server",
|
|
||||||
"version": "1.0.11",
|
|
||||||
"license": {
|
|
||||||
"name": "Apache 2.0",
|
|
||||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"externalDocs": {
|
|
||||||
"description": "Find out more about Swagger",
|
|
||||||
"url": "http://swagger.io"
|
|
||||||
},
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"url": "http://84.201.155.77:8080"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"/": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"summary": "Список пользователей",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/auth": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"summary": "Страница регистрации",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth": {
|
|
||||||
"post": {
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"summary": "Регистрация нового пользователя",
|
|
||||||
"requestBody": {
|
|
||||||
"content": {
|
|
||||||
"application/urlencoded": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"login": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "valera24"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "valera24@mail.com"
|
|
||||||
},
|
|
||||||
"phoneNumber": {
|
|
||||||
"type": "string",
|
|
||||||
"example": 79993337733
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "secret"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/login": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"login"
|
|
||||||
],
|
|
||||||
"summary": "Страница авторизации",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "return",
|
|
||||||
"in": "query",
|
|
||||||
"description": "URL на который будет перенаправлен пользователь после авторизации",
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/login": {
|
|
||||||
"post": {
|
|
||||||
"tags": [
|
|
||||||
"login"
|
|
||||||
],
|
|
||||||
"summary": "Авторизация пользователя",
|
|
||||||
"requestBody": {
|
|
||||||
"content": {
|
|
||||||
"application/urlencoded": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"email": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "valera24@mail.com"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "secret"
|
|
||||||
},
|
|
||||||
"goto": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "http://penahub.quiz/signedup"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful (Если не передан goto)"
|
|
||||||
},
|
|
||||||
"304": {
|
|
||||||
"description": "Successful (Если передан goto)"
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "password incorrect"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "User not found"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
64
src/swagger/account/index.ts
Normal file
64
src/swagger/account/index.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { getAccountParams, setAccountRoleBody } from "./inputs";
|
||||||
|
import {
|
||||||
|
getAccountResponse,
|
||||||
|
createAccountResponse,
|
||||||
|
setAccountRoleResponse,
|
||||||
|
getAccountsResponse,
|
||||||
|
removeRoleResponse,
|
||||||
|
} from "./responses";
|
||||||
|
|
||||||
|
import type { SwaggerSchema } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getAccountsSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение информации об аккаунтах",
|
||||||
|
description: "Получение всех аккаунтов из БД",
|
||||||
|
tags: ["account"],
|
||||||
|
response: getAccountsResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAccountSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение информации об аккаунте",
|
||||||
|
description: "Получение аккаунта по ID",
|
||||||
|
tags: ["account"],
|
||||||
|
params: getAccountParams,
|
||||||
|
response: getAccountResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createAccountSchema: SwaggerSchema = {
|
||||||
|
summary: "Создание аккаунта",
|
||||||
|
tags: ["account"],
|
||||||
|
response: createAccountResponse,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setAccountRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Присвоение роли пользователя",
|
||||||
|
tags: ["account"],
|
||||||
|
body: setAccountRoleBody,
|
||||||
|
response: setAccountRoleResponse,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeAccountSchema: SwaggerSchema = {
|
||||||
|
summary: "Удаление аккаунта",
|
||||||
|
description: "Помечает аккаунт удалённым, но не удаляет его из БД",
|
||||||
|
tags: ["account"],
|
||||||
|
response: removeRoleResponse,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteAccountSchema: SwaggerSchema = {
|
||||||
|
summary: "Удаление аккаунта",
|
||||||
|
description: "Удаляет аккаунт из БД окончательно",
|
||||||
|
tags: ["account"],
|
||||||
|
response: removeRoleResponse,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreAccountSchema: SwaggerSchema = {
|
||||||
|
summary: "Восстановление аккаунта",
|
||||||
|
description: "Восстанавливает аккаунт, который не был удалён окончательно",
|
||||||
|
tags: ["account"],
|
||||||
|
response: removeRoleResponse,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
};
|
27
src/swagger/account/inputs.ts
Normal file
27
src/swagger/account/inputs.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getAccountParams: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["userId"],
|
||||||
|
properties: {
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
description: "ID пользователя",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setAccountRoleBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["userId", "role"],
|
||||||
|
properties: {
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
description: "ID пользователя",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: "string",
|
||||||
|
description: "название роли",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
49
src/swagger/account/models.ts
Normal file
49
src/swagger/account/models.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const account: SwaggerMessage = {
|
||||||
|
description: "Аккаунт",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
_id: { type: "string" },
|
||||||
|
userId: { type: "string" },
|
||||||
|
nickname: { type: "string" },
|
||||||
|
avatar: { type: "string" },
|
||||||
|
role: { type: "string" },
|
||||||
|
isDeleted: { type: "boolean" },
|
||||||
|
createdAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
deletedAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
_id: "807f1f77bcf81cd799439011",
|
||||||
|
userId: "507f1f77bcf86cd799439011",
|
||||||
|
nickname: "Ivanov Ivan Ivanovich",
|
||||||
|
avatar: "/media/avatar/default-avatar.jpg",
|
||||||
|
role: "user",
|
||||||
|
isDeleted: false,
|
||||||
|
createdAt: "2017-07-21T17:32:28Z",
|
||||||
|
updatedAt: "2017-07-21T17:32:28Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: "807f1f77bcf81cd799439011",
|
||||||
|
userId: "507f1f77bcf86cd799439011",
|
||||||
|
nickname: "Ivanov Ivan Ivanovich",
|
||||||
|
avatar: "/media/avatar/default-avatar.jpg",
|
||||||
|
role: "user",
|
||||||
|
isDeleted: true,
|
||||||
|
createdAt: "2017-07-21T17:32:28Z",
|
||||||
|
updatedAt: "2019-04-14T15:32:15Z",
|
||||||
|
deletedAt: "2021-08-17T13:23:44Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
40
src/swagger/account/responses.ts
Normal file
40
src/swagger/account/responses.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { swaggerError } from "@/utils/swagger-error";
|
||||||
|
|
||||||
|
import { account } from "./models";
|
||||||
|
|
||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getAccountsResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив аккаунтов",
|
||||||
|
items: account,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAccountResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: account,
|
||||||
|
400: swaggerError(400, "invalid user id"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createAccountResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: account,
|
||||||
|
400: swaggerError(400, "invalid user id"),
|
||||||
|
401: swaggerError(401, "invalid token"),
|
||||||
|
404: swaggerError(404, "user not found"),
|
||||||
|
409: swaggerError(409, "account already exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setAccountRoleResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: account,
|
||||||
|
400: swaggerError(400, "invalid user id"),
|
||||||
|
401: swaggerError(401, "invalid token"),
|
||||||
|
404: swaggerError(404, "user not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeRoleResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: account,
|
||||||
|
400: swaggerError(400, "invalid user id"),
|
||||||
|
401: swaggerError(401, "invalid token"),
|
||||||
|
404: swaggerError(404, "user not found"),
|
||||||
|
};
|
84
src/swagger/privilege/index.ts
Normal file
84
src/swagger/privilege/index.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { privilegeBody, registerPrivilegiesBody, getPrivilegeParams, getServicePrivilegiesParams } from "./inputs";
|
||||||
|
import {
|
||||||
|
getPrivilegeReponse,
|
||||||
|
getPrivilegiesReponse,
|
||||||
|
getAllPrivilegiesMapReponse,
|
||||||
|
getAllPrivilegiesReponse,
|
||||||
|
registerPrivilegeResponse,
|
||||||
|
replacePrivilegeResponse,
|
||||||
|
registerPrivilegiesResponse,
|
||||||
|
replacePrivilegiesResponse,
|
||||||
|
removePrivilegeResponse,
|
||||||
|
} from "./responses";
|
||||||
|
|
||||||
|
import type { SwaggerSchema } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getPrivilegiesSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение всех привелегий",
|
||||||
|
description: "Получение всех привелегий в виде массива",
|
||||||
|
tags: ["privilege"],
|
||||||
|
response: getAllPrivilegiesReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPrivilegiesMapSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение всех привелегий",
|
||||||
|
description: "Получение всех привелегий в виде объекта ключ-значение, где ключём является serviceKey",
|
||||||
|
tags: ["privilege"],
|
||||||
|
response: getAllPrivilegiesMapReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPrivilegeSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение привилегии по ID",
|
||||||
|
tags: ["privilege"],
|
||||||
|
params: getPrivilegeParams,
|
||||||
|
response: getPrivilegeReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getServicePrivilegiesSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение привилегий сервиса",
|
||||||
|
tags: ["privilege"],
|
||||||
|
params: getServicePrivilegiesParams,
|
||||||
|
response: getPrivilegiesReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerPrivilegeSchema: SwaggerSchema = {
|
||||||
|
summary: "Регистрация привелегии сервиса",
|
||||||
|
tags: ["privilege"],
|
||||||
|
body: privilegeBody,
|
||||||
|
response: registerPrivilegeResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerPrivilegiesSchema: SwaggerSchema = {
|
||||||
|
summary: "Регистрация привелегий сервиса",
|
||||||
|
tags: ["privilege"],
|
||||||
|
body: registerPrivilegiesBody,
|
||||||
|
response: registerPrivilegiesResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replacePrivilegeSchema: SwaggerSchema = {
|
||||||
|
summary: "Замена привилегии сервиса",
|
||||||
|
tags: ["privilege"],
|
||||||
|
body: privilegeBody,
|
||||||
|
response: replacePrivilegeResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replacePrivilegiesSchema: SwaggerSchema = {
|
||||||
|
summary: "Замена привилегий сервиса",
|
||||||
|
tags: ["privilege"],
|
||||||
|
body: registerPrivilegiesBody,
|
||||||
|
response: replacePrivilegiesResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removePrivilegeSchema: SwaggerSchema = {
|
||||||
|
summary: "Удаление привелегии",
|
||||||
|
tags: ["privilege"],
|
||||||
|
body: getPrivilegeParams,
|
||||||
|
response: removePrivilegeResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restorePrivilegeSchema: SwaggerSchema = {
|
||||||
|
summary: "Восстановление привилегии",
|
||||||
|
tags: ["privilege"],
|
||||||
|
body: getPrivilegeParams,
|
||||||
|
response: removePrivilegeResponse,
|
||||||
|
};
|
62
src/swagger/privilege/inputs.ts
Normal file
62
src/swagger/privilege/inputs.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const privilegeBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["name", "privilegeId", "serviceKey", "description", "type", "value", "price"],
|
||||||
|
properties: {
|
||||||
|
name: { type: "string" },
|
||||||
|
privilegeId: { type: "string" },
|
||||||
|
serviceKey: { type: "string" },
|
||||||
|
description: { type: "string" },
|
||||||
|
type: { type: "string" },
|
||||||
|
value: { type: "string" },
|
||||||
|
price: { type: "number" },
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
name: "Количество попыток использования",
|
||||||
|
privilegeId: "507f1f77bcf86cd799439011",
|
||||||
|
serviceKey: "docx-templater-service",
|
||||||
|
description: "Количество попыток использования",
|
||||||
|
type: "count",
|
||||||
|
value: "200",
|
||||||
|
price: 12300,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const privilegiesBody: SwaggerMessage = {
|
||||||
|
type: "array",
|
||||||
|
items: privilegeBody,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerPrivilegiesBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
privilegies: privilegiesBody,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPrivilegeParams: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["privilegeId"],
|
||||||
|
properties: {
|
||||||
|
privilegeId: {
|
||||||
|
type: "string",
|
||||||
|
description: "ID привилегии (privilegeId)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ privilegeId: "507f1f77bcf86cd799439011" }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getServicePrivilegiesParams: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["serviceKey"],
|
||||||
|
properties: {
|
||||||
|
serviceKey: {
|
||||||
|
type: "string",
|
||||||
|
description: "Ключ сервиса",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ serviceKey: "docx-templater-service" }],
|
||||||
|
};
|
46
src/swagger/privilege/models.ts
Normal file
46
src/swagger/privilege/models.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import type { SwaggerMessage, SwaggerValueType } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
const privilegeExamples: SwaggerValueType[] = [
|
||||||
|
{
|
||||||
|
_id: "207f1f67bcf86cd799439011",
|
||||||
|
name: "Количество попыток использования",
|
||||||
|
privilegeId: "507f1f77bcf86cd799439011",
|
||||||
|
serviceKey: "docx-templater-service",
|
||||||
|
description: "Количество попыток использования",
|
||||||
|
type: "count",
|
||||||
|
value: "200",
|
||||||
|
price: 12300,
|
||||||
|
isDeleted: false,
|
||||||
|
createdAt: "2017-07-21T17:32:28Z",
|
||||||
|
updatedAt: "2017-07-21T17:32:28Z",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const privilege: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
description: "Привилегия",
|
||||||
|
properties: {
|
||||||
|
_id: { type: "string" },
|
||||||
|
name: { type: "string" },
|
||||||
|
privilegeId: { type: "string" },
|
||||||
|
serviceKey: { type: "string" },
|
||||||
|
description: { type: "string" },
|
||||||
|
type: { type: "string" },
|
||||||
|
value: { type: "string" },
|
||||||
|
price: { type: "number" },
|
||||||
|
isDeleted: { type: "boolean" },
|
||||||
|
createdAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
deletedAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: privilegeExamples,
|
||||||
|
};
|
95
src/swagger/privilege/responses.ts
Normal file
95
src/swagger/privilege/responses.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { swaggerError } from "@/utils/swagger-error";
|
||||||
|
|
||||||
|
import { privilege } from "./models";
|
||||||
|
|
||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getAllPrivilegiesReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Привилегии",
|
||||||
|
items: privilege,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAllPrivilegiesMapReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "object",
|
||||||
|
description: "Привилегии",
|
||||||
|
properties: {
|
||||||
|
additionalProperties: {
|
||||||
|
type: "array",
|
||||||
|
description: "Привилегии",
|
||||||
|
items: privilege,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
additionalProperties: true,
|
||||||
|
example: {
|
||||||
|
"docx-templater-service": [
|
||||||
|
{
|
||||||
|
_id: "63a7b01f1f4117cf861d6d1e",
|
||||||
|
name: "Количество попыток использования",
|
||||||
|
privilegeId: "507f1f77bcf86cd799439011",
|
||||||
|
serviceKey: "docx-templater-service",
|
||||||
|
description: "Количество попыток использования",
|
||||||
|
type: "count",
|
||||||
|
value: "200",
|
||||||
|
price: 12300,
|
||||||
|
updatedAt: "2022-12-25T02:47:52.405Z",
|
||||||
|
isDeleted: false,
|
||||||
|
createdAt: "2022-12-25T02:47:52.406Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPrivilegiesReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив привилегий",
|
||||||
|
items: privilege,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPrivilegeReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: privilege,
|
||||||
|
400: swaggerError(400, "invalid id"),
|
||||||
|
404: swaggerError(404, "privilege not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerPrivilegeResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: privilege,
|
||||||
|
400: swaggerError(400, "price must be a number"),
|
||||||
|
409: swaggerError(409, "privilege already exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerPrivilegiesResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив привилегий",
|
||||||
|
items: privilege,
|
||||||
|
},
|
||||||
|
400: swaggerError(400, "price must be a number"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replacePrivilegeResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: privilege,
|
||||||
|
400: swaggerError(400, "invalid 'type' value"),
|
||||||
|
404: swaggerError(404, "privilege not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replacePrivilegiesResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив привилегий",
|
||||||
|
items: privilege,
|
||||||
|
},
|
||||||
|
400: swaggerError(400, "invalid 'type' value"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removePrivilegeResponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: privilege,
|
||||||
|
400: swaggerError(400, "invalid id"),
|
||||||
|
404: swaggerError(404, "privilege not found"),
|
||||||
|
};
|
71
src/swagger/role/index.ts
Normal file
71
src/swagger/role/index.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { getRoleParams, roleBody, getRoleByIdBody, updateRoleBody } from "./inputs";
|
||||||
|
import {
|
||||||
|
getRolesReponse,
|
||||||
|
getRoleReponse,
|
||||||
|
createRoleReponse,
|
||||||
|
restoreRoleReponse,
|
||||||
|
updateRoleReponse,
|
||||||
|
removeRoleReponse,
|
||||||
|
} from "./responses";
|
||||||
|
|
||||||
|
import type { SwaggerSchema } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getRolesSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение всех ролей",
|
||||||
|
tags: ["role"],
|
||||||
|
response: getRolesReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение роли",
|
||||||
|
tags: ["role"],
|
||||||
|
params: getRoleParams,
|
||||||
|
response: getRoleReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Создание роли",
|
||||||
|
tags: ["role"],
|
||||||
|
body: roleBody,
|
||||||
|
response: createRoleReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Восстановление удалённой роли",
|
||||||
|
description: "Восстанавливает удалённую роль, которая ещё существует в БД",
|
||||||
|
tags: ["role"],
|
||||||
|
body: getRoleByIdBody,
|
||||||
|
response: restoreRoleReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Обновление роли",
|
||||||
|
tags: ["role"],
|
||||||
|
params: getRoleParams,
|
||||||
|
body: updateRoleBody,
|
||||||
|
response: updateRoleReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Замена роли",
|
||||||
|
tags: ["role"],
|
||||||
|
params: getRoleParams,
|
||||||
|
body: roleBody,
|
||||||
|
response: updateRoleReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Удаление роли",
|
||||||
|
description: "Помечает роль удалённой, но не удаляет её окончательно",
|
||||||
|
tags: ["role"],
|
||||||
|
body: getRoleByIdBody,
|
||||||
|
response: removeRoleReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteRoleSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение всех ролей",
|
||||||
|
description: "Удаляет роль окончательно",
|
||||||
|
tags: ["role"],
|
||||||
|
body: getRoleByIdBody,
|
||||||
|
response: getRolesReponse,
|
||||||
|
};
|
58
src/swagger/role/inputs.ts
Normal file
58
src/swagger/role/inputs.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getRoleParams: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["query"],
|
||||||
|
properties: {
|
||||||
|
query: {
|
||||||
|
type: "string",
|
||||||
|
description: "query может принимать как id, так и name роли",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ query: "507f1f77bcf86cd799439011" }, { query: "admin" }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const roleBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["name", "permissions"],
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
description: "Название роли",
|
||||||
|
},
|
||||||
|
permissions: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив разрешений",
|
||||||
|
items: { type: "string" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ name: "admin", permissions: ["read", "write"] }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateRoleBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
description: "Название роли",
|
||||||
|
},
|
||||||
|
permissions: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив разрешений",
|
||||||
|
items: { type: "string" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ name: "admin", permissions: ["read", "write"] }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRoleByIdBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["id"],
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
description: "ID роли",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ id: "507f1f77bcf86cd799439011" }],
|
||||||
|
};
|
32
src/swagger/role/models.ts
Normal file
32
src/swagger/role/models.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const role: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
description: "Роль",
|
||||||
|
properties: {
|
||||||
|
_id: { type: "string" },
|
||||||
|
name: { type: "string" },
|
||||||
|
permissions: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: { type: "boolean" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
_id: "638388e120c70c17eb123d37",
|
||||||
|
name: "user",
|
||||||
|
permissions: {
|
||||||
|
read: true,
|
||||||
|
write: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: "638388f720c70c17eb123d3a",
|
||||||
|
name: "admin",
|
||||||
|
permissions: {
|
||||||
|
read: true,
|
||||||
|
write: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
51
src/swagger/role/responses.ts
Normal file
51
src/swagger/role/responses.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { swaggerError } from "@/utils/swagger-error";
|
||||||
|
|
||||||
|
import { role } from "./models";
|
||||||
|
|
||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getRolesReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив ролей",
|
||||||
|
items: role,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRoleReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: role,
|
||||||
|
400: swaggerError(400, "query is empty"),
|
||||||
|
404: swaggerError(404, "role not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createRoleReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: role,
|
||||||
|
400: swaggerError(400, "field <name> is empty"),
|
||||||
|
409: swaggerError(409, "role already exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreRoleReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: role,
|
||||||
|
400: swaggerError(400, "wrong id"),
|
||||||
|
404: swaggerError(404, "role by id not found"),
|
||||||
|
409: swaggerError(409, "role not removed"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateRoleReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: role,
|
||||||
|
400: swaggerError(400, "either name or permissions must be filled"),
|
||||||
|
404: swaggerError(404, "role not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeRoleReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: role,
|
||||||
|
400: swaggerError(400, "wrong id"),
|
||||||
|
404: swaggerError(404, "role by id not found"),
|
||||||
|
409: swaggerError(409, "role already deleted"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteRoleReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: role,
|
||||||
|
400: swaggerError(400, "wrong id"),
|
||||||
|
404: swaggerError(404, "role not found"),
|
||||||
|
};
|
66
src/swagger/tariff/index.ts
Normal file
66
src/swagger/tariff/index.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { getTariffParams, tariffBody, replaceTariffParams } from "./inputs";
|
||||||
|
import {
|
||||||
|
getTariffReponse,
|
||||||
|
getTariffsReponse,
|
||||||
|
createTariffReponse,
|
||||||
|
replaceTariffReponse,
|
||||||
|
removeTariffReponse,
|
||||||
|
} from "./responses";
|
||||||
|
|
||||||
|
import type { SwaggerSchema } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getTariffSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение тарифа",
|
||||||
|
tags: ["tariff"],
|
||||||
|
params: getTariffParams,
|
||||||
|
response: getTariffReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTariffsSchema: SwaggerSchema = {
|
||||||
|
summary: "Получение списка тарифов",
|
||||||
|
tags: ["tariff"],
|
||||||
|
response: getTariffsReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createTariffsSchema: SwaggerSchema = {
|
||||||
|
summary: "Создание тарифа",
|
||||||
|
tags: ["tariff"],
|
||||||
|
body: tariffBody,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
response: createTariffReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceTariffsSchema: SwaggerSchema = {
|
||||||
|
summary: "Замена тарифа",
|
||||||
|
tags: ["tariff"],
|
||||||
|
params: replaceTariffParams,
|
||||||
|
body: tariffBody,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
response: replaceTariffReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeTariffsSchema: SwaggerSchema = {
|
||||||
|
summary: "Удаление тарифа",
|
||||||
|
description: "Помечает тариф удалённым, но не удаляет его из БД",
|
||||||
|
tags: ["tariff"],
|
||||||
|
body: getTariffParams,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
response: removeTariffReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteTariffsSchema: SwaggerSchema = {
|
||||||
|
summary: "Удаление тарифа",
|
||||||
|
description: "Удаляет тариф из БД окончательно",
|
||||||
|
tags: ["tariff"],
|
||||||
|
body: getTariffParams,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
response: removeTariffReponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreTariffsSchema: SwaggerSchema = {
|
||||||
|
summary: "Восстановление тарифа",
|
||||||
|
tags: ["tariff"],
|
||||||
|
body: getTariffParams,
|
||||||
|
security: [{ bearer: [] }],
|
||||||
|
response: removeTariffReponse,
|
||||||
|
};
|
48
src/swagger/tariff/inputs.ts
Normal file
48
src/swagger/tariff/inputs.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getTariffParams: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["id"],
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
description: "ID тарифа",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ id: "507f1f77bcf86cd799439011" }],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tariffBody: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
description: "Тариф",
|
||||||
|
required: ["name", "price", "isCustom", "privilegieIDArray"],
|
||||||
|
properties: {
|
||||||
|
name: { type: "string" },
|
||||||
|
price: { type: "number" },
|
||||||
|
isCustom: { type: "boolean" },
|
||||||
|
privilegieIDArray: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
name: "Использование сервисов",
|
||||||
|
price: 14000,
|
||||||
|
isCustom: false,
|
||||||
|
privilegieIDArray: ["507f1f77bcf86cd799439011"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceTariffParams: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
required: ["id"],
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
description: "ID тарифа",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [{ id: "63a7d47ba24613f98562bafa" }],
|
||||||
|
};
|
97
src/swagger/tariff/models.ts
Normal file
97
src/swagger/tariff/models.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
const privilege: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
description: "Привилегия",
|
||||||
|
properties: {
|
||||||
|
_id: { type: "string" },
|
||||||
|
name: { type: "string" },
|
||||||
|
privilegeId: { type: "string" },
|
||||||
|
serviceKey: { type: "string" },
|
||||||
|
description: { type: "string" },
|
||||||
|
type: { type: "string" },
|
||||||
|
value: { type: "string" },
|
||||||
|
price: { type: "number" },
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
_id: "507f1f77bcf86cd799439011",
|
||||||
|
name: "Количество попыток использования",
|
||||||
|
privilegeId: "507f1f77bcf86cd799439011",
|
||||||
|
serviceKey: "docx-templater-service",
|
||||||
|
description: "Количество попыток использования сервиса генерации шаблонов",
|
||||||
|
type: "count",
|
||||||
|
value: "200",
|
||||||
|
price: 12300,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tariff: SwaggerMessage = {
|
||||||
|
type: "object",
|
||||||
|
description: "Тариф",
|
||||||
|
properties: {
|
||||||
|
_id: { type: "string" },
|
||||||
|
name: { type: "string" },
|
||||||
|
price: { type: "number" },
|
||||||
|
isCustom: { type: "boolean" },
|
||||||
|
privilegies: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: privilege,
|
||||||
|
},
|
||||||
|
isDeleted: { type: "boolean" },
|
||||||
|
createdAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
deletedAt: {
|
||||||
|
type: "string",
|
||||||
|
format: "date-time",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
name: "Использование сервисов",
|
||||||
|
price: 14000,
|
||||||
|
isCustom: false,
|
||||||
|
privilegies: {
|
||||||
|
"507f1f77bcf86cd799439011": {
|
||||||
|
name: "507f1f77bcf86cd799439011",
|
||||||
|
privilegeId: "507f1f77bcf86cd799439011",
|
||||||
|
serviceKey: "docx-templater-service",
|
||||||
|
description: "Количество попыток использования",
|
||||||
|
type: "count",
|
||||||
|
value: "200",
|
||||||
|
price: 12300,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isDeleted: false,
|
||||||
|
createdAt: "2017-07-21T17:32:28Z",
|
||||||
|
updatedAt: "2017-07-21T17:32:28Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
price: 14000,
|
||||||
|
isCustom: false,
|
||||||
|
privilegies: {
|
||||||
|
"507f1f77bcf86cd799439011": {
|
||||||
|
name: "507f1f77bcf86cd799439011",
|
||||||
|
privilegeId: "507f1f77bcf86cd799439011",
|
||||||
|
serviceKey: "docx-templater-service",
|
||||||
|
description: "Количество попыток использования",
|
||||||
|
type: "count",
|
||||||
|
value: "200",
|
||||||
|
price: 12300,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isDeleted: true,
|
||||||
|
createdAt: "2017-07-21T17:32:28Z",
|
||||||
|
updatedAt: "2019-04-14T15:32:15Z",
|
||||||
|
deletedAt: "2021-08-17T13:23:44Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
40
src/swagger/tariff/responses.ts
Normal file
40
src/swagger/tariff/responses.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { swaggerError } from "@/utils/swagger-error";
|
||||||
|
|
||||||
|
import { tariff } from "./models";
|
||||||
|
|
||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
export const getTariffReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: tariff,
|
||||||
|
400: swaggerError(400, "invalid id"),
|
||||||
|
404: swaggerError(404, "tariff not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTariffsReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: {
|
||||||
|
type: "array",
|
||||||
|
description: "Массив тарифов",
|
||||||
|
items: tariff,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createTariffReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: tariff,
|
||||||
|
400: swaggerError(400, "invalid 'price' value"),
|
||||||
|
401: swaggerError(400, "invalid user id"),
|
||||||
|
404: swaggerError(404, "privilege with id <privilegeId> not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceTariffReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: tariff,
|
||||||
|
400: swaggerError(400, "invalid id"),
|
||||||
|
401: swaggerError(400, "invalid user id"),
|
||||||
|
404: swaggerError(404, "tariff not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeTariffReponse: Record<string, SwaggerMessage> = {
|
||||||
|
200: tariff,
|
||||||
|
400: swaggerError(400, "invalid id"),
|
||||||
|
401: swaggerError(400, "invalid user id"),
|
||||||
|
404: swaggerError(404, "tariff not found"),
|
||||||
|
};
|
8
src/types/fastify-jwt.d.ts
vendored
Normal file
8
src/types/fastify-jwt.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import "@fastify/jwt";
|
||||||
|
|
||||||
|
declare module "@fastify/jwt" {
|
||||||
|
interface FastifyJWT {
|
||||||
|
payload: { id: string };
|
||||||
|
user: { id: string };
|
||||||
|
}
|
||||||
|
}
|
9
src/types/messages/tariff-message.type.ts
Normal file
9
src/types/messages/tariff-message.type.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { Eloquent } from "../models/eloquent.type";
|
||||||
|
import type { Tariff } from "../models/tariff.type";
|
||||||
|
import type { ObjectWithPossibleFields } from "../object-with-possible-fields";
|
||||||
|
|
||||||
|
export type TariffMessage = ObjectWithPossibleFields<
|
||||||
|
Omit<Tariff, keyof Eloquent | "privilegies"> & {
|
||||||
|
privilegieIDArray: string[];
|
||||||
|
}
|
||||||
|
>;
|
8
src/types/models/account.type.ts
Normal file
8
src/types/models/account.type.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import type { Eloquent } from "./eloquent.type";
|
||||||
|
|
||||||
|
export type Account = Eloquent & {
|
||||||
|
userId: string;
|
||||||
|
nickname: string;
|
||||||
|
avatar: string;
|
||||||
|
role: string;
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
export type EloquentModel = {
|
export type Eloquent = {
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
deletedAt: Date;
|
deletedAt: Date;
|
11
src/types/models/privilege.type.ts
Normal file
11
src/types/models/privilege.type.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type { Eloquent } from "./eloquent.type";
|
||||||
|
|
||||||
|
export type Privilege = Eloquent & {
|
||||||
|
name: string;
|
||||||
|
privilegeId: string;
|
||||||
|
serviceKey: string;
|
||||||
|
description: string;
|
||||||
|
type: "count" | "day" | "full";
|
||||||
|
value: string;
|
||||||
|
price: number;
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import type { EloquentModel } from "./eloquent-model";
|
import type { Eloquent } from "./eloquent.type";
|
||||||
|
|
||||||
export type Role = EloquentModel & {
|
export type Role = Eloquent & {
|
||||||
name: string;
|
name: string;
|
||||||
permissions: Record<string, boolean>;
|
permissions: Record<string, boolean>;
|
||||||
};
|
};
|
||||||
|
9
src/types/models/tariff.type.ts
Normal file
9
src/types/models/tariff.type.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { Privilege } from "./privilege.type";
|
||||||
|
import type { Eloquent } from "./eloquent.type";
|
||||||
|
|
||||||
|
export type Tariff = Eloquent & {
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
isCustom: boolean;
|
||||||
|
privilegies: Record<string, Omit<Privilege, keyof Eloquent>>;
|
||||||
|
};
|
8
src/types/models/user.type.ts
Normal file
8
src/types/models/user.type.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import type { Eloquent } from "./eloquent.type";
|
||||||
|
|
||||||
|
export type User = Eloquent & {
|
||||||
|
_id: string;
|
||||||
|
login: string;
|
||||||
|
email: string;
|
||||||
|
phoneNumber: string;
|
||||||
|
};
|
3
src/types/object-with-possible-fields.ts
Normal file
3
src/types/object-with-possible-fields.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type ObjectWithPossibleFields<KeyValue extends Record<string, unknown>> = {
|
||||||
|
[Key in keyof KeyValue]?: KeyValue[Key];
|
||||||
|
};
|
50
src/types/swagger.type.ts
Normal file
50
src/types/swagger.type.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import type { FastifySchema } from "fastify";
|
||||||
|
|
||||||
|
export type SwaggerValueType =
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null
|
||||||
|
| SwaggerValueType[]
|
||||||
|
| { [key: string]: SwaggerValueType };
|
||||||
|
|
||||||
|
type SwaggerMediaType = "object" | "string" | "integer" | "boolean" | "array" | "number";
|
||||||
|
type SwaggerMediaFormat =
|
||||||
|
| "binary"
|
||||||
|
| "base64"
|
||||||
|
| "uuid"
|
||||||
|
| "email"
|
||||||
|
| "date"
|
||||||
|
| "date-time"
|
||||||
|
| "password"
|
||||||
|
| "byte"
|
||||||
|
| "uri"
|
||||||
|
| "hostname"
|
||||||
|
| "ipv4"
|
||||||
|
| "ipv6";
|
||||||
|
|
||||||
|
export type SwaggerMessage = {
|
||||||
|
type?: SwaggerMediaType;
|
||||||
|
description?: string;
|
||||||
|
format?: SwaggerMediaFormat;
|
||||||
|
pattern?: string;
|
||||||
|
nullable?: boolean;
|
||||||
|
uniqueItems?: boolean;
|
||||||
|
writeOnly?: boolean;
|
||||||
|
readOnly?: boolean;
|
||||||
|
items?: SwaggerMessage;
|
||||||
|
additionalProperties?: SwaggerMessage | boolean;
|
||||||
|
properties?: Record<string, SwaggerMessage | Record<string, SwaggerValueType>>;
|
||||||
|
examples?: SwaggerValueType[];
|
||||||
|
example?: SwaggerValueType;
|
||||||
|
required?: string[];
|
||||||
|
oneOf?: SwaggerMessage[];
|
||||||
|
allOf?: SwaggerMessage[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SwaggerSchema = FastifySchema & {
|
||||||
|
params?: SwaggerMessage;
|
||||||
|
body?: SwaggerMessage;
|
||||||
|
querystring?: SwaggerMessage;
|
||||||
|
response?: Record<number, SwaggerMessage>;
|
||||||
|
};
|
20
src/utils/swagger-error.ts
Normal file
20
src/utils/swagger-error.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { SwaggerMessage } from "@/types/swagger.type";
|
||||||
|
|
||||||
|
const STATUS_CODE_MAP: Record<number, string> = {
|
||||||
|
400: "Bad Request",
|
||||||
|
401: "Unauthorized",
|
||||||
|
404: "Not Found",
|
||||||
|
409: "Conflict",
|
||||||
|
500: "Internal Server Error",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const swaggerError = (code: number, message: string): SwaggerMessage => ({
|
||||||
|
type: "object",
|
||||||
|
description: STATUS_CODE_MAP[code],
|
||||||
|
properties: {
|
||||||
|
statusCode: { type: "integer" },
|
||||||
|
error: { type: "string" },
|
||||||
|
message: { type: "string" },
|
||||||
|
},
|
||||||
|
examples: [{ statusCode: code, error: STATUS_CODE_MAP[code], message: message }],
|
||||||
|
});
|
@ -2,14 +2,23 @@ import type { ObjectWithRequiredFields } from "@/types/object-with-required-fiel
|
|||||||
|
|
||||||
type KeyValue = Record<string, unknown>;
|
type KeyValue = Record<string, unknown>;
|
||||||
type Keys<T> = Array<keyof T>;
|
type Keys<T> = Array<keyof T>;
|
||||||
type ValidateEmptyFields<T extends KeyValue> = [ObjectWithRequiredFields<T> | undefined, Error | null];
|
type ValidateEmptyFields<T extends KeyValue> = [ObjectWithRequiredFields<T>, Error | null];
|
||||||
|
|
||||||
|
export const validateEmptyFields = <T extends KeyValue>(
|
||||||
|
record: T,
|
||||||
|
keys: Keys<T> = [],
|
||||||
|
strict = true
|
||||||
|
): ValidateEmptyFields<T> => {
|
||||||
|
const validatedRecord = record as ObjectWithRequiredFields<T>;
|
||||||
|
|
||||||
export const validateEmptyFields = <T extends KeyValue>(record: T, keys: Keys<T> = []): ValidateEmptyFields<T> => {
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
if (!record[key]) {
|
if (strict && !record[key]) {
|
||||||
return [undefined, new Error(`field <${key as string}> is empty`)];
|
return [validatedRecord, new Error(`field <${key as string}> is empty`)];
|
||||||
|
}
|
||||||
|
if (!strict && (record[key] === undefined || record[key] === null)) {
|
||||||
|
return [validatedRecord, new Error(`field <${key as string}> is empty`)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [record as ObjectWithRequiredFields<T>, null];
|
return [validatedRecord, null];
|
||||||
};
|
};
|
||||||
|
265
yarn.lock
265
yarn.lock
@ -1204,6 +1204,11 @@
|
|||||||
minimatch "^3.1.2"
|
minimatch "^3.1.2"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
|
"@fastify/accept-negotiator@^1.0.0":
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz#c1c66b3b771c09742a54dd5bc87c582f6b0630ff"
|
||||||
|
integrity sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==
|
||||||
|
|
||||||
"@fastify/ajv-compiler@^3.3.1":
|
"@fastify/ajv-compiler@^3.3.1":
|
||||||
version "3.4.0"
|
version "3.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-3.4.0.tgz#e001b7e234b5b704654b1d617d69fa63c348f2a7"
|
resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-3.4.0.tgz#e001b7e234b5b704654b1d617d69fa63c348f2a7"
|
||||||
@ -1257,6 +1262,41 @@
|
|||||||
fastify-plugin "^4.0.0"
|
fastify-plugin "^4.0.0"
|
||||||
steed "^1.1.3"
|
steed "^1.1.3"
|
||||||
|
|
||||||
|
"@fastify/static@^6.0.0":
|
||||||
|
version "6.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fastify/static/-/static-6.6.0.tgz#763244583abf7a4734bff7b1d1aef0ef445393fb"
|
||||||
|
integrity sha512-UiYSN2dUmDZ48M40xdIwY1dPwSSYD7c+wtoIQP8y7wyxCwcUtf1YT5/Q4n1uJsBF1fySvuo9njQZKlHeiKy4HQ==
|
||||||
|
dependencies:
|
||||||
|
"@fastify/accept-negotiator" "^1.0.0"
|
||||||
|
content-disposition "^0.5.3"
|
||||||
|
fastify-plugin "^4.0.0"
|
||||||
|
glob "^8.0.1"
|
||||||
|
p-limit "^3.1.0"
|
||||||
|
readable-stream "^4.0.0"
|
||||||
|
send "^0.18.0"
|
||||||
|
|
||||||
|
"@fastify/swagger-ui@^1.3.0":
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fastify/swagger-ui/-/swagger-ui-1.3.0.tgz#967afd8bfa87a539b83ae6bc986f3589e9fdb98a"
|
||||||
|
integrity sha512-Q6vvIyTd1gj0h0IoDAAUX3SBBiL1pybXP0FmFbD4yLMcACIZ7xm8oHCf5lMc3rNC69KhbywuSst3iHgp23x8SA==
|
||||||
|
dependencies:
|
||||||
|
"@fastify/static" "^6.0.0"
|
||||||
|
fastify-plugin "^4.0.0"
|
||||||
|
openapi-types "^12.0.2"
|
||||||
|
rfdc "^1.3.0"
|
||||||
|
yaml "^2.1.3"
|
||||||
|
|
||||||
|
"@fastify/swagger@^8.2.1":
|
||||||
|
version "8.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fastify/swagger/-/swagger-8.2.1.tgz#a5f744868c25c49bde2469f5412ce0405aac150a"
|
||||||
|
integrity sha512-nYP/3ncrI5YmaGiJf6m+CLdFrdlWSsASHBPqP9uN9/oFFwDJwdUtq0ylmvObxzqWNVt9zT50iT/uvIndVEsvbg==
|
||||||
|
dependencies:
|
||||||
|
fastify-plugin "^4.0.0"
|
||||||
|
json-schema-resolver "^2.0.0"
|
||||||
|
openapi-types "^12.0.0"
|
||||||
|
rfdc "^1.3.0"
|
||||||
|
yaml "^2.1.1"
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.6":
|
"@humanwhocodes/config-array@^0.11.6":
|
||||||
version "0.11.7"
|
version "0.11.7"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.7.tgz#38aec044c6c828f6ed51d5d7ae3d9b9faf6dbb0f"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.7.tgz#38aec044c6c828f6ed51d5d7ae3d9b9faf6dbb0f"
|
||||||
@ -2049,6 +2089,11 @@ async-mutex@^0.3.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.3.1"
|
tslib "^2.3.1"
|
||||||
|
|
||||||
|
asynckit@^0.4.0:
|
||||||
|
version "0.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||||
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||||
|
|
||||||
atomic-sleep@^1.0.0:
|
atomic-sleep@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
|
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
|
||||||
@ -2063,6 +2108,15 @@ avvio@^8.2.0:
|
|||||||
debug "^4.0.0"
|
debug "^4.0.0"
|
||||||
fastq "^1.6.1"
|
fastq "^1.6.1"
|
||||||
|
|
||||||
|
axios@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a"
|
||||||
|
integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.15.0"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
babel-jest@^29.3.1:
|
babel-jest@^29.3.1:
|
||||||
version "29.3.1"
|
version "29.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.3.1.tgz#05c83e0d128cd48c453eea851482a38782249f44"
|
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.3.1.tgz#05c83e0d128cd48c453eea851482a38782249f44"
|
||||||
@ -2170,6 +2224,13 @@ brace-expansion@^1.1.7:
|
|||||||
balanced-match "^1.0.0"
|
balanced-match "^1.0.0"
|
||||||
concat-map "0.0.1"
|
concat-map "0.0.1"
|
||||||
|
|
||||||
|
brace-expansion@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
||||||
|
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
|
||||||
|
dependencies:
|
||||||
|
balanced-match "^1.0.0"
|
||||||
|
|
||||||
braces@^3.0.2, braces@~3.0.2:
|
braces@^3.0.2, braces@~3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||||
@ -2366,6 +2427,13 @@ color-name@~1.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
|
combined-stream@^1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
|
dependencies:
|
||||||
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
commander@^9.0.0:
|
commander@^9.0.0:
|
||||||
version "9.4.1"
|
version "9.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd"
|
||||||
@ -2389,6 +2457,13 @@ concat-map@0.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||||
|
|
||||||
|
content-disposition@^0.5.3:
|
||||||
|
version "0.5.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
|
||||||
|
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "5.2.1"
|
||||||
|
|
||||||
conventional-changelog-angular@^5.0.11:
|
conventional-changelog-angular@^5.0.11:
|
||||||
version "5.0.13"
|
version "5.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c"
|
resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c"
|
||||||
@ -2468,6 +2543,13 @@ dargs@^7.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc"
|
resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc"
|
||||||
integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==
|
integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==
|
||||||
|
|
||||||
|
debug@2.6.9, debug@^2.6.9:
|
||||||
|
version "2.6.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
|
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||||
|
dependencies:
|
||||||
|
ms "2.0.0"
|
||||||
|
|
||||||
debug@4, debug@4.x, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
|
debug@4, debug@4.x, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
@ -2475,13 +2557,6 @@ debug@4, debug@4.x, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debu
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "2.1.2"
|
ms "2.1.2"
|
||||||
|
|
||||||
debug@^2.6.9:
|
|
||||||
version "2.6.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
|
||||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
|
||||||
dependencies:
|
|
||||||
ms "2.0.0"
|
|
||||||
|
|
||||||
debug@^3.2.7:
|
debug@^3.2.7:
|
||||||
version "3.2.7"
|
version "3.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||||
@ -2530,11 +2605,26 @@ define-properties@^1.1.3, define-properties@^1.1.4:
|
|||||||
has-property-descriptors "^1.0.0"
|
has-property-descriptors "^1.0.0"
|
||||||
object-keys "^1.1.1"
|
object-keys "^1.1.1"
|
||||||
|
|
||||||
|
delayed-stream@~1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
|
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||||
|
|
||||||
denque@^2.1.0:
|
denque@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
|
resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
|
||||||
integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
|
integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
|
||||||
|
|
||||||
|
depd@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||||
|
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||||
|
|
||||||
|
destroy@1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
|
||||||
|
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
|
||||||
|
|
||||||
detect-newline@^3.0.0:
|
detect-newline@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
|
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
|
||||||
@ -2590,6 +2680,11 @@ ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
|
ee-first@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||||
|
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
|
||||||
|
|
||||||
electron-to-chromium@^1.4.251:
|
electron-to-chromium@^1.4.251:
|
||||||
version "1.4.284"
|
version "1.4.284"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
|
||||||
@ -2605,6 +2700,11 @@ emoji-regex@^8.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||||
|
|
||||||
|
encodeurl@~1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||||
|
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
|
||||||
|
|
||||||
end-of-stream@^1.4.1:
|
end-of-stream@^1.4.1:
|
||||||
version "1.4.4"
|
version "1.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||||
@ -2678,6 +2778,11 @@ escalade@^3.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||||
|
|
||||||
|
escape-html@~1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||||
|
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||||
|
|
||||||
escape-string-regexp@^1.0.5:
|
escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
@ -2873,6 +2978,11 @@ esutils@^2.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||||
|
|
||||||
|
etag@~1.8.1:
|
||||||
|
version "1.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
|
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||||
|
|
||||||
event-target-shim@^5.0.0:
|
event-target-shim@^5.0.0:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||||
@ -3134,11 +3244,30 @@ flatted@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
|
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
|
||||||
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
|
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
|
||||||
|
|
||||||
|
follow-redirects@^1.15.0:
|
||||||
|
version "1.15.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||||
|
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||||
|
|
||||||
|
form-data@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||||
|
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
forwarded@0.2.0:
|
forwarded@0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||||
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||||
|
|
||||||
|
fresh@0.5.2:
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||||
|
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
|
||||||
|
|
||||||
fs-constants@^1.0.0:
|
fs-constants@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||||
@ -3267,6 +3396,17 @@ glob@^7.1.3, glob@^7.1.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
|
glob@^8.0.1:
|
||||||
|
version "8.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e"
|
||||||
|
integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==
|
||||||
|
dependencies:
|
||||||
|
fs.realpath "^1.0.0"
|
||||||
|
inflight "^1.0.4"
|
||||||
|
inherits "2"
|
||||||
|
minimatch "^5.0.1"
|
||||||
|
once "^1.3.0"
|
||||||
|
|
||||||
global-dirs@^0.1.1:
|
global-dirs@^0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
|
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
|
||||||
@ -3392,6 +3532,17 @@ html-escaper@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
|
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
|
||||||
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
||||||
|
|
||||||
|
http-errors@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
|
||||||
|
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
|
||||||
|
dependencies:
|
||||||
|
depd "2.0.0"
|
||||||
|
inherits "2.0.4"
|
||||||
|
setprototypeof "1.2.0"
|
||||||
|
statuses "2.0.1"
|
||||||
|
toidentifier "1.0.1"
|
||||||
|
|
||||||
https-proxy-agent@^5.0.1:
|
https-proxy-agent@^5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
|
||||||
@ -3459,7 +3610,7 @@ inflight@^1.0.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
|
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
@ -4091,6 +4242,15 @@ json-parse-even-better-errors@^2.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||||
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
||||||
|
|
||||||
|
json-schema-resolver@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/json-schema-resolver/-/json-schema-resolver-2.0.0.tgz#d17fdf53560e6bc9af084b930fee27f6ce4a03b6"
|
||||||
|
integrity sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.1.1"
|
||||||
|
rfdc "^1.1.4"
|
||||||
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
json-schema-traverse@^0.4.1:
|
json-schema-traverse@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||||
@ -4357,6 +4517,23 @@ micromatch@^4.0.4:
|
|||||||
braces "^3.0.2"
|
braces "^3.0.2"
|
||||||
picomatch "^2.3.1"
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
|
mime-db@1.52.0:
|
||||||
|
version "1.52.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||||
|
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||||
|
|
||||||
|
mime-types@^2.1.12:
|
||||||
|
version "2.1.35"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||||
|
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||||
|
dependencies:
|
||||||
|
mime-db "1.52.0"
|
||||||
|
|
||||||
|
mime@1.6.0:
|
||||||
|
version "1.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||||
|
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||||
|
|
||||||
mimic-fn@^2.1.0:
|
mimic-fn@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||||
@ -4379,6 +4556,13 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
|
minimatch@^5.0.1:
|
||||||
|
version "5.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.2.tgz#0939d7d6f0898acbd1508abe534d1929368a8fff"
|
||||||
|
integrity sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==
|
||||||
|
dependencies:
|
||||||
|
brace-expansion "^2.0.1"
|
||||||
|
|
||||||
minimist-options@4.1.0:
|
minimist-options@4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
|
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
|
||||||
@ -4617,6 +4801,13 @@ on-exit-leak-free@^2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4"
|
resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4"
|
||||||
integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==
|
integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==
|
||||||
|
|
||||||
|
on-finished@2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
|
||||||
|
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
|
||||||
|
dependencies:
|
||||||
|
ee-first "1.1.1"
|
||||||
|
|
||||||
once@^1.3.0, once@^1.4.0:
|
once@^1.3.0, once@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||||
@ -4640,6 +4831,11 @@ open@^8.4.0:
|
|||||||
is-docker "^2.1.1"
|
is-docker "^2.1.1"
|
||||||
is-wsl "^2.2.0"
|
is-wsl "^2.2.0"
|
||||||
|
|
||||||
|
openapi-types@^12.0.0, openapi-types@^12.0.2:
|
||||||
|
version "12.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.0.tgz#bd01acc937b73c9f6db2ac2031bf0231e21ebff0"
|
||||||
|
integrity sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==
|
||||||
|
|
||||||
optionator@^0.9.1:
|
optionator@^0.9.1:
|
||||||
version "0.9.1"
|
version "0.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
|
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
|
||||||
@ -4843,6 +5039,11 @@ proxy-addr@^2.0.7:
|
|||||||
forwarded "0.2.0"
|
forwarded "0.2.0"
|
||||||
ipaddr.js "1.9.1"
|
ipaddr.js "1.9.1"
|
||||||
|
|
||||||
|
proxy-from-env@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
pstree.remy@^1.1.8:
|
pstree.remy@^1.1.8:
|
||||||
version "1.1.8"
|
version "1.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
|
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
|
||||||
@ -4878,6 +5079,11 @@ quick-lru@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
|
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
|
||||||
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
|
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
|
||||||
|
|
||||||
|
range-parser@~1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||||
|
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
|
||||||
|
|
||||||
react-is@^18.0.0:
|
react-is@^18.0.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||||
@ -5013,7 +5219,7 @@ reusify@^1.0.0, reusify@^1.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||||
|
|
||||||
rfdc@^1.2.0, rfdc@^1.3.0:
|
rfdc@^1.1.4, rfdc@^1.2.0, rfdc@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
|
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
|
||||||
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
|
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
|
||||||
@ -5032,7 +5238,7 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
safe-buffer@^5.0.1, safe-buffer@~5.2.0:
|
safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
@ -5104,11 +5310,35 @@ semver@~7.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
||||||
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
||||||
|
|
||||||
|
send@^0.18.0:
|
||||||
|
version "0.18.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
|
||||||
|
integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
|
||||||
|
dependencies:
|
||||||
|
debug "2.6.9"
|
||||||
|
depd "2.0.0"
|
||||||
|
destroy "1.2.0"
|
||||||
|
encodeurl "~1.0.2"
|
||||||
|
escape-html "~1.0.3"
|
||||||
|
etag "~1.8.1"
|
||||||
|
fresh "0.5.2"
|
||||||
|
http-errors "2.0.0"
|
||||||
|
mime "1.6.0"
|
||||||
|
ms "2.1.3"
|
||||||
|
on-finished "2.4.1"
|
||||||
|
range-parser "~1.2.1"
|
||||||
|
statuses "2.0.1"
|
||||||
|
|
||||||
set-cookie-parser@^2.4.1:
|
set-cookie-parser@^2.4.1:
|
||||||
version "2.5.1"
|
version "2.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz#ddd3e9a566b0e8e0862aca974a6ac0e01349430b"
|
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz#ddd3e9a566b0e8e0862aca974a6ac0e01349430b"
|
||||||
integrity sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==
|
integrity sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==
|
||||||
|
|
||||||
|
setprototypeof@1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||||
|
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||||
|
|
||||||
shebang-command@^2.0.0:
|
shebang-command@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||||
@ -5261,6 +5491,11 @@ stack-utils@^2.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
escape-string-regexp "^2.0.0"
|
escape-string-regexp "^2.0.0"
|
||||||
|
|
||||||
|
statuses@2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||||
|
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||||
|
|
||||||
steed@^1.1.3:
|
steed@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/steed/-/steed-1.1.3.tgz#f1525dd5adb12eb21bf74749537668d625b9abc5"
|
resolved "https://registry.yarnpkg.com/steed/-/steed-1.1.3.tgz#f1525dd5adb12eb21bf74749537668d625b9abc5"
|
||||||
@ -5489,6 +5724,11 @@ to-regex-range@^5.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-number "^7.0.0"
|
is-number "^7.0.0"
|
||||||
|
|
||||||
|
toidentifier@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||||
|
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||||
|
|
||||||
touch@^3.1.0:
|
touch@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
|
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
|
||||||
@ -5790,6 +6030,11 @@ yaml@^1.10.0:
|
|||||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||||
|
|
||||||
|
yaml@^2.1.1, yaml@^2.1.3:
|
||||||
|
version "2.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.3.tgz#9b3a4c8aff9821b696275c79a8bee8399d945207"
|
||||||
|
integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==
|
||||||
|
|
||||||
yargs-parser@^20.2.3:
|
yargs-parser@^20.2.3:
|
||||||
version "20.2.9"
|
version "20.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
||||||
|
Loading…
Reference in New Issue
Block a user