init bones go pj
This commit is contained in:
parent
481fe2bcfc
commit
148e8de6be
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": ["@commitlint/config-conventional"],
|
|
||||||
"rules": {
|
|
||||||
"type-enum": [2, "always", ["feat", "fix", "docs", "style", "refactor", "revert", "chore", "build", "ci", "test"]]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
jest.config.js
|
|
145
.eslintrc
145
.eslintrc
@ -1,145 +0,0 @@
|
|||||||
{
|
|
||||||
"root": true,
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2022": true,
|
|
||||||
"jest": true
|
|
||||||
},
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"plugins": ["@typescript-eslint", "prettier", "import"],
|
|
||||||
"extends": [
|
|
||||||
"prettier",
|
|
||||||
"eslint:recommended",
|
|
||||||
"eslint-config-prettier",
|
|
||||||
"plugin:import/recommended",
|
|
||||||
"plugin:import/typescript",
|
|
||||||
"plugin:prettier/recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:@typescript-eslint/eslint-recommended"
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"import/resolver": {
|
|
||||||
"node": {
|
|
||||||
"extensions": [".js", ".ts"],
|
|
||||||
"paths": ["./src"]
|
|
||||||
},
|
|
||||||
"typescript": {
|
|
||||||
"alwaysTryTypes": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"import/parsers": {
|
|
||||||
"@typescript-eslint/parser": [".ts"]
|
|
||||||
},
|
|
||||||
"extensions": [".js", ".ts"],
|
|
||||||
"import/ignore": ["node_modules"]
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2022,
|
|
||||||
"sourceType": "module",
|
|
||||||
"project": ["./tsconfig.json"],
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": false,
|
|
||||||
"arrowFunctions": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/explicit-function-return-type": "off",
|
|
||||||
"@typescript-eslint/no-var-requires": "error",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
|
||||||
"@typescript-eslint/quotes": ["error", "double"],
|
|
||||||
"@typescript-eslint/no-use-before-define": "off",
|
|
||||||
"@typescript-eslint/no-empty-interface": "error",
|
|
||||||
"@typescript-eslint/no-explicit-any": "warn",
|
|
||||||
"@typescript-eslint/ban-ts-comment": 0,
|
|
||||||
"@typescript-eslint/no-shadow": "error",
|
|
||||||
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
|
||||||
"@typescript-eslint/lines-between-class-members": ["error", { "exceptAfterOverload": true }],
|
|
||||||
"@typescript-eslint/naming-convention": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"selector": "default",
|
|
||||||
"format": ["camelCase", "UPPER_CASE", "PascalCase", "snake_case"],
|
|
||||||
"leadingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "variable",
|
|
||||||
"format": ["camelCase", "UPPER_CASE", "PascalCase", "snake_case"],
|
|
||||||
"leadingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"selector": "typeLike",
|
|
||||||
"format": ["camelCase", "UPPER_CASE", "PascalCase", "snake_case"],
|
|
||||||
"leadingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "enumMember",
|
|
||||||
"format": ["camelCase", "UPPER_CASE", "PascalCase", "snake_case"],
|
|
||||||
"leadingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "objectLiteralProperty",
|
|
||||||
"format": [],
|
|
||||||
"leadingUnderscore": "allow"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"import/no-named-default": 0,
|
|
||||||
"import/prefer-default-export": "off",
|
|
||||||
"import/no-dynamic-require": "off",
|
|
||||||
"import/no-duplicates": "off",
|
|
||||||
"import/no-unresolved": "error",
|
|
||||||
"import/no-cycle": "off",
|
|
||||||
"import/extensions": [
|
|
||||||
"error",
|
|
||||||
"ignorePackages",
|
|
||||||
{
|
|
||||||
"js": "never",
|
|
||||||
"jsx": "never",
|
|
||||||
"ts": "never",
|
|
||||||
"tsx": "never"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
|
|
||||||
"import/order": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"newlines-between": "always-and-inside-groups",
|
|
||||||
"groups": [["builtin", "external"], ["internal", "sibling"], "type"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"prettier/prettier": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"endOfLine": "auto"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"comma-dangle": "off",
|
|
||||||
"class-methods-use-this": "off",
|
|
||||||
"func-names": "off",
|
|
||||||
"function-paren-newline": "off",
|
|
||||||
"global-require": "off",
|
|
||||||
"implicit-arrow-linebreak": 0,
|
|
||||||
"no-use-before-define": "off",
|
|
||||||
"no-inner-declarations": "off",
|
|
||||||
"no-console": ["warn", { "allow": ["error", "info"] }],
|
|
||||||
"consistent-return": "off",
|
|
||||||
"no-alert": "error",
|
|
||||||
"no-process-exit": "error",
|
|
||||||
"no-shadow": "error",
|
|
||||||
"no-param-reassign": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"props": true,
|
|
||||||
"ignorePropertyModificationsFor": ["accamulator", "request"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"object-shorthand": "off",
|
|
||||||
"quotes": ["error", "double"]
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"window": false,
|
|
||||||
"FormData": false,
|
|
||||||
"Blob": true,
|
|
||||||
"document": false
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npx --no -- commitlint --edit ${1}
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
yarn run code:format && yarn run lint && yarn run code:check && git add .
|
|
12
.prettierrc
12
.prettierrc
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"semi": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"singleQuote": false,
|
|
||||||
"printWidth": 120,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"endOfLine": "auto",
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"arrowParens": "always",
|
|
||||||
"jsxSingleQuote": false
|
|
||||||
}
|
|
32
cmd/main.go
Normal file
32
cmd/main.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"hub_admin_backend_service/internal/app"
|
||||||
|
"hub_admin_backend_service/internal/initialize"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logger, err := zap.NewProduction()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to initialize logger: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := initialize.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("Failed to load config", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
if err = app.Run(ctx, *config, logger); err != nil {
|
||||||
|
logger.Fatal("App exited with error", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
22
go.mod
Normal file
22
go.mod
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module hub_admin_backend_service
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 // indirect
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.4 // indirect
|
||||||
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||||
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
|
golang.org/x/sys v0.15.0 // indirect
|
||||||
|
)
|
35
go.sum
Normal file
35
go.sum
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||||
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
|
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||||
|
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||||
|
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||||
|
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||||
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
|
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
|
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
20
internal/app/app.go
Normal file
20
internal/app/app.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"hub_admin_backend_service/internal/initialize"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Error("Recovered from a panic", zap.Any("error", r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger.Info("Starting application", zap.String("AppName", cfg.AppName))
|
||||||
|
|
||||||
|
logger.Info("Application has stopped")
|
||||||
|
return nil
|
||||||
|
}
|
11
internal/controller/privilege_external/controller.go
Normal file
11
internal/controller/privilege_external/controller.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package privilege_external
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivilegeExternal struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPrivilegeExternal(deps Deps) *PrivilegeExternal {
|
||||||
|
return &PrivilegeExternal{}
|
||||||
|
}
|
18
internal/controller/privilege_external/route.go
Normal file
18
internal/controller/privilege_external/route.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package privilege_external
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *PrivilegeExternal) Register(router fiber.Router) {
|
||||||
|
router.Get("/privilege/service", p.GetAllService)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeExternal) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeExternal) GetAllService(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
52
internal/controller/privilege_internal/controller.go
Normal file
52
internal/controller/privilege_internal/controller.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package privilege_internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivilegeInternal struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPrivilegeInternal(deps Deps) *PrivilegeInternal {
|
||||||
|
return &PrivilegeInternal{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Get(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Create(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Update(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Delete(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) GetByID(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) GetByService(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) PostMany(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) UpdateMany(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Restore(c *fiber.Ctx) error {
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
}
|
20
internal/controller/privilege_internal/route.go
Normal file
20
internal/controller/privilege_internal/route.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package privilege_internal
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Register(router fiber.Router) {
|
||||||
|
router.Get("/privilege", p.Get)
|
||||||
|
router.Post("/privilege", p.Create)
|
||||||
|
router.Put("/privilege", p.Update)
|
||||||
|
router.Delete("/privilege", p.Delete)
|
||||||
|
router.Get("/privilege/:privilegeId", p.GetByID)
|
||||||
|
router.Get("/privilege/service/:serviceKey", p.GetByService)
|
||||||
|
router.Post("/privilege/many", p.PostMany)
|
||||||
|
router.Put("/privilege/many", p.UpdateMany)
|
||||||
|
router.Post("/privilege/restore", p.Restore)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivilegeInternal) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
30
internal/initialize/config.go
Normal file
30
internal/initialize/config.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caarlos0/env/v8"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
AppName string `env:"APP_NAME" envDefault:"hub-admin-backend-service"`
|
||||||
|
HTTPHost string `env:"HTTP_HOST" envDefault:"localhost"`
|
||||||
|
HTTPPort string `env:"HTTP_PORT" envDefault:"3000"`
|
||||||
|
MongoHost string `env:"MONGO_HOST" envDefault:"127.0.0.1"`
|
||||||
|
MongoPort string `env:"MONGO_PORT" envDefault:"27020"`
|
||||||
|
MongoUser string `env:"MONGO_USER" envDefault:"test"`
|
||||||
|
MongoPassword string `env:"MONGO_PASSWORD" envDefault:"test"`
|
||||||
|
MongoDatabase string `env:"MONGO_DB" envDefault:"admin"`
|
||||||
|
MongoAuth string `env:"MONGO_AUTH" envDefault:"admin"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig() (*Config, error) {
|
||||||
|
if err := godotenv.Load(); err != nil {
|
||||||
|
log.Print("No .env file found")
|
||||||
|
}
|
||||||
|
var config Config
|
||||||
|
if err := env.Parse(&config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &config, nil
|
||||||
|
}
|
65
internal/server/http/http.go
Normal file
65
internal/server/http/http.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
Controllers []Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
Controllers []Controller
|
||||||
|
app *fiber.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(config ServerConfig) *Server {
|
||||||
|
app := fiber.New()
|
||||||
|
s := &Server{
|
||||||
|
Logger: config.Logger,
|
||||||
|
Controllers: config.Controllers,
|
||||||
|
app: app,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.registerRoutes()
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start(addr string) error {
|
||||||
|
if err := s.app.Listen(addr); err != nil {
|
||||||
|
s.Logger.Error("Failed to start server", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
|
return s.app.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) registerRoutes() {
|
||||||
|
for _, c := range s.Controllers {
|
||||||
|
router := s.app.Group(c.Name())
|
||||||
|
c.Register(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller interface {
|
||||||
|
Register(router fiber.Router)
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListRoutes() {
|
||||||
|
fmt.Println("Registered routes:")
|
||||||
|
for _, stack := range s.app.Stack() {
|
||||||
|
for _, route := range stack {
|
||||||
|
fmt.Printf("%s %s\n", route.Method, route.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
import type { Config } from "jest";
|
|
||||||
|
|
||||||
const config: Config = {
|
|
||||||
preset: "ts-jest",
|
|
||||||
testEnvironment: "node",
|
|
||||||
moduleDirectories: ["node_modules", "<rootDir>"],
|
|
||||||
moduleNameMapper: {
|
|
||||||
"@/(.*)": "<rootDir>/src/$1",
|
|
||||||
},
|
|
||||||
testTimeout: 15000,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default config;
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"ignore": ["test", ".git", "node_modules"],
|
|
||||||
"watch": ["src"],
|
|
||||||
"exec": "npm run start",
|
|
||||||
"ext": "ts",
|
|
||||||
"env": {
|
|
||||||
"ENVIRONMENT": "development"
|
|
||||||
}
|
|
||||||
}
|
|
74
package.json
74
package.json
@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "auth-server",
|
|
||||||
"version": "1.1.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"author": "DevMArt",
|
|
||||||
"license": "ISC",
|
|
||||||
"scripts": {
|
|
||||||
"setup": "yarn & husky install",
|
|
||||||
"start": "ts-node ./src/index.ts",
|
|
||||||
"start:prod": "node -r ts-node/register/transpile-only -r tsconfig-paths/register ./src/index.js",
|
|
||||||
"dev": "nodemon",
|
|
||||||
"test": "jest --coverage",
|
|
||||||
"test:watch": "jest --watch",
|
|
||||||
"build": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
|
|
||||||
"compose:dev:start": "docker-compose -f deployments/dev/docker-compose.yaml up -d",
|
|
||||||
"compose:dev:stop": "docker-compose -f deployments/dev/docker-compose.yaml down --volumes --rmi local",
|
|
||||||
"compose:test:start": "docker-compose -f deployments/test/docker-compose.yaml up -d",
|
|
||||||
"compose:test:stop": "docker-compose -f deployments/test/docker-compose.yaml down --volumes --rmi local",
|
|
||||||
"code:check": "prettier --check \"src/**/*.{ts,tsx,js,css,scss,html}\"",
|
|
||||||
"code:format": "prettier --write \"src/**/*.{ts,tsx,js,css,scss,html}\"",
|
|
||||||
"code:format:specific-file": "prettier --write",
|
|
||||||
"lint": "eslint .",
|
|
||||||
"lint:fix": "eslint --fix ."
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@fastify/cookie": "^9.0.4",
|
|
||||||
"@fastify/jwt": "^7.2.0",
|
|
||||||
"@fastify/swagger": "^8.9.0",
|
|
||||||
"@fastify/swagger-ui": "^1.9.3",
|
|
||||||
"axios": "^1.4.0",
|
|
||||||
"bcryptjs": "^2.4.3",
|
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"fastify": "^4.21.0",
|
|
||||||
"fastify-plugin": "^4.5.1",
|
|
||||||
"fastify-print-routes": "^2.1.0",
|
|
||||||
"jsonwebtoken": "^9.0.1",
|
|
||||||
"mongoose": "^7.4.4",
|
|
||||||
"nodemon": "^3.0.1",
|
|
||||||
"ts-node": "^10.9.1",
|
|
||||||
"tsconfig-paths": "^4.2.0",
|
|
||||||
"typescript-transform-paths": "^3.4.6"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@commitlint/cli": "^17.7.1",
|
|
||||||
"@commitlint/config-conventional": "^17.7.0",
|
|
||||||
"@types/bcryptjs": "^2.4.2",
|
|
||||||
"@types/jest": "^29.5.4",
|
|
||||||
"@types/jsonwebtoken": "^9.0.2",
|
|
||||||
"@types/node": "^20.5.3",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^6.4.1",
|
|
||||||
"@typescript-eslint/parser": "^6.4.1",
|
|
||||||
"eslint": "^8.47.0",
|
|
||||||
"eslint-config-prettier": "^9.0.0",
|
|
||||||
"eslint-import-resolver-node": "^0.3.9",
|
|
||||||
"eslint-import-resolver-typescript": "^3.6.0",
|
|
||||||
"eslint-plugin-import": "^2.28.1",
|
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
|
||||||
"husky": "^8.0.3",
|
|
||||||
"jest": "^29.6.3",
|
|
||||||
"jest-mock-extended": "^3.0.5",
|
|
||||||
"nodemon": "^3.0.1",
|
|
||||||
"prettier": "^3.0.2",
|
|
||||||
"ts-jest": "^29.1.1",
|
|
||||||
"tsc-alias": "^1.8.7",
|
|
||||||
"typescript": "^5.1.6"
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"./src/**/*.{ts,js,jsx,tsx}": [
|
|
||||||
"eslint --ignore-path .gitignore --fix",
|
|
||||||
"prettier --ignore-path .gitignore --write"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
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;
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
|
|
||||||
import { CONFIGURATION } from "@/constants/configuration";
|
|
||||||
|
|
||||||
export const authService = axios.create({
|
|
||||||
baseURL: `${CONFIGURATION.authService.host}:${CONFIGURATION.authService.port}`,
|
|
||||||
});
|
|
@ -1,3 +0,0 @@
|
|||||||
export type GetUserRequest = {
|
|
||||||
id: string;
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
import { Router } from "@/server/router";
|
|
||||||
|
|
||||||
import { setAccountRoutes } from "@/routes/account.routes";
|
|
||||||
import { setPrivilegeRoutes } from "@/routes/privilege.routes";
|
|
||||||
import { setRoleRoutes } from "@/routes/role.routes";
|
|
||||||
import { setTariffRoutes } from "@/routes/tariff.routes";
|
|
||||||
import { setPermissionRoutes } from "@/routes/permission.routes";
|
|
||||||
|
|
||||||
export const combineRoutes = (router: Router): void => {
|
|
||||||
router.group("/role", setRoleRoutes);
|
|
||||||
router.group("/account", setAccountRoutes);
|
|
||||||
router.group("/privilege", setPrivilegeRoutes);
|
|
||||||
router.group("/tariff", setTariffRoutes);
|
|
||||||
router.group("/permission", setPermissionRoutes);
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import path from "path";
|
|
||||||
import * as dotenv from "dotenv";
|
|
||||||
|
|
||||||
import { defineEnvironment } from "./define-environment";
|
|
||||||
|
|
||||||
export const configureENV = () => {
|
|
||||||
const environment = defineEnvironment();
|
|
||||||
|
|
||||||
if (environment === "development") {
|
|
||||||
return dotenv.config({
|
|
||||||
debug: true,
|
|
||||||
path: path.resolve(process.env.PWD || "", ".env.example"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return dotenv.config();
|
|
||||||
};
|
|
||||||
|
|
||||||
configureENV();
|
|
@ -1,7 +0,0 @@
|
|||||||
import type { DatabaseOptions } from "@/types/configuration/database-options";
|
|
||||||
|
|
||||||
export const constituteMongoURI = ({ username, password, host, port, database }: DatabaseOptions) => {
|
|
||||||
const dbConnection = `mongodb://${username}:${password}@${host}:${port}`;
|
|
||||||
|
|
||||||
return database ? `${dbConnection}/${database}` : dbConnection;
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
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 "development";
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
import cookie from "@fastify/cookie";
|
|
||||||
import jwt from "@fastify/jwt";
|
|
||||||
import swagger from "@fastify/swagger";
|
|
||||||
import swaggerUI from "@fastify/swagger-ui";
|
|
||||||
|
|
||||||
import printRoutes from "@/plugins/print-routes";
|
|
||||||
|
|
||||||
import { DEFAULT } from "@/constants/default";
|
|
||||||
|
|
||||||
import type { FastifyInstance } from "fastify";
|
|
||||||
import type { PluginsOptions } from "@/types/configuration/plugins-options";
|
|
||||||
|
|
||||||
export const registerFastifyPlugins = (fastify: FastifyInstance, options: PluginsOptions) => {
|
|
||||||
fastify.register(cookie, options.cookie);
|
|
||||||
fastify.register(jwt, options.jwt);
|
|
||||||
fastify.register(swagger, DEFAULT.swaggerOptions);
|
|
||||||
fastify.register(swaggerUI, DEFAULT.swaggerUIOptions);
|
|
||||||
fastify.register(printRoutes);
|
|
||||||
|
|
||||||
return fastify;
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
export const CONFIGURATION = {
|
|
||||||
http: {
|
|
||||||
host: process.env.HTTP_HOST || "",
|
|
||||||
port: Number(process.env.HTTP_PORT) || 8080,
|
|
||||||
},
|
|
||||||
db: {
|
|
||||||
host: process.env.DB_HOST || "",
|
|
||||||
port: Number(process.env.DB_PORT) || 3000,
|
|
||||||
username: process.env.DB_USERNAME || "admin",
|
|
||||||
password: process.env.DB_PASSWORD || "admin",
|
|
||||||
database: process.env.DB_NAME || "database",
|
|
||||||
},
|
|
||||||
service: {
|
|
||||||
publicAccessSecretKey: process.env.PUBLIC_ACCESS_SECRET_KEY || "",
|
|
||||||
salt: Number(process.env.SALT) || 10,
|
|
||||||
},
|
|
||||||
authService: {
|
|
||||||
host: process.env.AUTH_SERVICE_HOST || "",
|
|
||||||
port: Number(process.env.AUTH_SERVICE_PORT) || 8081,
|
|
||||||
},
|
|
||||||
} as const;
|
|
@ -1,46 +0,0 @@
|
|||||||
import type { FastifyServerOptions } from "fastify";
|
|
||||||
import type { FastifyDynamicSwaggerOptions } from "@fastify/swagger";
|
|
||||||
import type { FastifySwaggerUiOptions } from "@fastify/swagger-ui";
|
|
||||||
|
|
||||||
type Default = {
|
|
||||||
readonly fastifyOptions: FastifyServerOptions;
|
|
||||||
readonly swaggerOptions: FastifyDynamicSwaggerOptions;
|
|
||||||
readonly swaggerUIOptions: FastifySwaggerUiOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DEFAULT: Default = {
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
import type { Permission } from "@/types/models/permission.type";
|
|
||||||
|
|
||||||
const DELETE_ACCOUNT_PERMISSION: Permission = {
|
|
||||||
name: "hub-admin-backend-service.deleteAccount",
|
|
||||||
description: "Разрешение на удаление чужого аккаунта пользователем",
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
isDeleted: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PERMISSIONS = {
|
|
||||||
deleteAccount: DELETE_ACCOUNT_PERMISSION.name,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const PERMISSION_LIST: Array<Permission> = [DELETE_ACCOUNT_PERMISSION];
|
|
@ -1,234 +0,0 @@
|
|||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
import { AccountModel } from "@/models/account.model";
|
|
||||||
import { RoleModel } from "@/models/role.model";
|
|
||||||
import { PermissionModule } from "@/services/permission/permission.module";
|
|
||||||
|
|
||||||
import { getUser } from "@/clients/auth";
|
|
||||||
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
|
||||||
import { determinePaginationParameters } from "@/utils/determine-pagination-parameters";
|
|
||||||
|
|
||||||
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
||||||
import type { Account } from "@/types/models/account.type";
|
|
||||||
import type { GetAccountRequest, SetAccountRoleRequest, GetAccountsRequest, GetAccountsResponse } from "./types";
|
|
||||||
|
|
||||||
export const getAccounts = async (request: GetAccountsRequest): Promise<GetAccountsResponse> => {
|
|
||||||
const { page, limit } = determinePaginationParameters(request?.query ?? {});
|
|
||||||
|
|
||||||
const accountsCount = await AccountModel.countDocuments();
|
|
||||||
|
|
||||||
const totalPages = Math.ceil(accountsCount / limit);
|
|
||||||
const offset = (page - 1) * limit;
|
|
||||||
|
|
||||||
const accounts = await AccountModel.find({}).sort({ createdAt: "desc" }).skip(offset).limit(limit).lean();
|
|
||||||
|
|
||||||
return { accounts, totalPages };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createAccount = async (request: FastifyRequest, reply: FastifyReply) => {
|
|
||||||
if (!Types.ObjectId.isValid(request.user.id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOne({ userId: request.user.id }).lean();
|
|
||||||
|
|
||||||
if (account) {
|
|
||||||
void reply.status(409);
|
|
||||||
return new Error("account already exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await getUser({ id: request.user.id });
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("user not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const createdAccount = new AccountModel({
|
|
||||||
userId: user._id,
|
|
||||||
});
|
|
||||||
|
|
||||||
return createdAccount.save();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccountByID = async (request: GetAccountRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
const [getAccountRequestParams, error] = validateEmptyFields(request.params ?? {}, ["userId"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(getAccountRequestParams.userId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOne({ userId: getAccountRequestParams.userId }).lean();
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccount = async (request: GetAccountRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
if (!Types.ObjectId.isValid(request.user.id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOne({ userId: request.user.id }).lean();
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setAccountRole = async (request: SetAccountRoleRequest, reply: FastifyReply) => {
|
|
||||||
const [setAccountRoleBody, error] = validateEmptyFields(request.body || {}, ["userId", "role"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = await RoleModel.findOne({ name: setAccountRoleBody.role }).lean();
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOneAndUpdate(
|
|
||||||
{ userId: setAccountRoleBody.userId },
|
|
||||||
{ $set: { role: role.name } }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeAccount = async (request: FastifyRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
if (!Types.ObjectId.isValid(request.user.id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOneAndUpdate(
|
|
||||||
{ userId: request.user.id },
|
|
||||||
{ $set: { isDeleted: true, deletedAt: new Date() } }
|
|
||||||
).lean();
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeAccountById = async (request: GetAccountRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
const [{ userId }, error] = validateEmptyFields(request.params ?? {}, ["userId"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(userId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOne({ userId: request.user.id });
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const isAvailableToDelete = await PermissionModule.deleteAccount(account);
|
|
||||||
|
|
||||||
if (!isAvailableToDelete) {
|
|
||||||
throw new Error("the user doesn't have the permission to delete account");
|
|
||||||
}
|
|
||||||
|
|
||||||
await account.updateOne({ $set: { isDeleted: true, deletedAt: new Date() } });
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteAccount = async (request: FastifyRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
if (!Types.ObjectId.isValid(request.user.id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findByIdAndDelete({ userId: request.user.id }).lean();
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteAccountById = async (request: GetAccountRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
const [{ userId }, error] = validateEmptyFields(request.params ?? {}, ["userId"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(userId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findByIdAndDelete({ userId: request.user.id }).lean();
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const isAvailableToDelete = await PermissionModule.deleteAccount(account);
|
|
||||||
|
|
||||||
if (!isAvailableToDelete) {
|
|
||||||
throw new Error("the user doesn't have the permission to delete account");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restoreAccount = async (request: FastifyRequest, reply: FastifyReply): Promise<Account> => {
|
|
||||||
if (!Types.ObjectId.isValid(request.user.id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid user id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await AccountModel.findOneAndUpdate(
|
|
||||||
{ userId: request.user.id },
|
|
||||||
{ $set: { isDeleted: false } }
|
|
||||||
).lean();
|
|
||||||
|
|
||||||
if (!account) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("account not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return account;
|
|
||||||
};
|
|
@ -1,25 +0,0 @@
|
|||||||
import type { FastifyRequest } from "fastify";
|
|
||||||
import type { Account } from "@/types/models/account.type";
|
|
||||||
import type { PaginationParams } from "@/types/messages/pagination.type";
|
|
||||||
|
|
||||||
export type GetAccountRequest = FastifyRequest<{
|
|
||||||
Params?: {
|
|
||||||
userId?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type SetAccountRoleRequest = FastifyRequest<{
|
|
||||||
Body: {
|
|
||||||
userId?: string;
|
|
||||||
role?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetAccountsRequest = FastifyRequest<{
|
|
||||||
Querystring?: PaginationParams;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetAccountsResponse = {
|
|
||||||
accounts: Account[];
|
|
||||||
totalPages: number;
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
import type { FastifyRequest, FastifyReply } from "fastify";
|
|
||||||
|
|
||||||
export const verifyUser = async (request: FastifyRequest, reply: FastifyReply) => {
|
|
||||||
try {
|
|
||||||
const { id } = await request.jwtVerify<{ id?: string }>();
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
void reply.status(401);
|
|
||||||
return reply.send("user id is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
request.user = { id };
|
|
||||||
} catch (nativeError) {
|
|
||||||
void reply.status(401);
|
|
||||||
return reply.send(nativeError);
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,166 +0,0 @@
|
|||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
import { PermissionModule } from "@/services/permission/permission.module";
|
|
||||||
import { PermissionModel } from "@/models/permission.model";
|
|
||||||
|
|
||||||
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
|
||||||
|
|
||||||
import type { FastifyReply } from "fastify";
|
|
||||||
import type { Permission } from "@/types/models/permission.type";
|
|
||||||
import type { CreatePermissionRequest, GetPermissionByIdRequest, UpdatePermissionRequest } from "./types";
|
|
||||||
|
|
||||||
export const getAllPermissions = async (): Promise<Permission[]> => PermissionModule.getAllPermissions();
|
|
||||||
|
|
||||||
export const getPermissionById = async (
|
|
||||||
request: GetPermissionByIdRequest,
|
|
||||||
reply: FastifyReply
|
|
||||||
): Promise<Permission | undefined> => {
|
|
||||||
const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]);
|
|
||||||
|
|
||||||
if (validateParamsError) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw validateParamsError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(permissionId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid permission id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const permission = await PermissionModel.findOne({
|
|
||||||
_id: new Types.ObjectId(permissionId),
|
|
||||||
isDeleted: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!permission) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("permission not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return permission;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createPermission = async (request: CreatePermissionRequest, reply: FastifyReply): Promise<Permission> => {
|
|
||||||
const [permission, error] = validateEmptyFields(request.body ?? {}, ["name", "description"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newPermission = new PermissionModel(permission);
|
|
||||||
|
|
||||||
return newPermission.save();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePermission = async (
|
|
||||||
request: UpdatePermissionRequest,
|
|
||||||
reply: FastifyReply
|
|
||||||
): Promise<Permission | undefined> => {
|
|
||||||
const [permission, validateBodyError] = validateEmptyFields(request.body ?? {}, ["name", "description"]);
|
|
||||||
const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]);
|
|
||||||
|
|
||||||
if (validateBodyError) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw validateBodyError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validateParamsError) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw validateParamsError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(permissionId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid permission id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const findedPermission = await PermissionModel.findByIdAndUpdate(permissionId, {
|
|
||||||
$set: {
|
|
||||||
...permission,
|
|
||||||
updatedAt: new Date(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!findedPermission) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("permission not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return permission;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removePermission = async (
|
|
||||||
request: GetPermissionByIdRequest,
|
|
||||||
reply: FastifyReply
|
|
||||||
): Promise<Permission | undefined> => {
|
|
||||||
const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]);
|
|
||||||
|
|
||||||
if (validateParamsError) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw validateParamsError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(permissionId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid permission id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const permission = await PermissionModel.findOneAndUpdate(
|
|
||||||
{
|
|
||||||
_id: new Types.ObjectId(permissionId),
|
|
||||||
isDeleted: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
deletedAt: new Date(),
|
|
||||||
isDeleted: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!permission) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("permission not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return permission;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restorePermission = async (
|
|
||||||
request: GetPermissionByIdRequest,
|
|
||||||
reply: FastifyReply
|
|
||||||
): Promise<Permission | undefined> => {
|
|
||||||
const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]);
|
|
||||||
|
|
||||||
if (validateParamsError) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw validateParamsError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(permissionId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid permission id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const permission = await PermissionModel.findOneAndUpdate(
|
|
||||||
{
|
|
||||||
_id: new Types.ObjectId(permissionId),
|
|
||||||
isDeleted: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
deletedAt: undefined,
|
|
||||||
updatedAt: new Date(),
|
|
||||||
isDeleted: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!permission) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("permission not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return permission;
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import type { FastifyRequest } from "fastify";
|
|
||||||
import type { Permission } from "@/types/models/permission.type";
|
|
||||||
import type { ObjectWithPossibleFields } from "@/types/object-with-possible-fields";
|
|
||||||
|
|
||||||
export type CreatePermissionRequest = FastifyRequest<{
|
|
||||||
Body?: ObjectWithPossibleFields<Permission>;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type UpdatePermissionRequest = FastifyRequest<{
|
|
||||||
Body?: ObjectWithPossibleFields<Permission>;
|
|
||||||
Params?: {
|
|
||||||
permissionId?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetPermissionByIdRequest = FastifyRequest<{
|
|
||||||
Params?: {
|
|
||||||
permissionId?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
@ -1,28 +0,0 @@
|
|||||||
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 convertPrivilegesToMap = (privileges: Privilege[]) => {
|
|
||||||
return privileges.reduce<Record<string, Privilege[]>>((accamulator, privilege) => {
|
|
||||||
if (!accamulator[privilege.serviceKey]) {
|
|
||||||
accamulator[privilege.serviceKey] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
accamulator[privilege.serviceKey].push(privilege);
|
|
||||||
|
|
||||||
return accamulator;
|
|
||||||
}, {});
|
|
||||||
};
|
|
@ -1,280 +0,0 @@
|
|||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
import { PrivilegeModel } from "@/models/privilege.model";
|
|
||||||
|
|
||||||
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
|
||||||
import { convertPrivilegesToMap, validatePrivilege } from "./helpers";
|
|
||||||
|
|
||||||
import type { FastifyReply } from "fastify";
|
|
||||||
import type {
|
|
||||||
GetServicePrivilegesRequest,
|
|
||||||
RegisterPrivilegeRequest,
|
|
||||||
GetPrivilegeRequest,
|
|
||||||
RegisterPrivilegesRequest,
|
|
||||||
RemovePrivilegeRequest,
|
|
||||||
} from "./types";
|
|
||||||
|
|
||||||
export const registerPrivileges = async (request: RegisterPrivilegesRequest, reply: FastifyReply) => {
|
|
||||||
const [requestBody, errorEmpty] = validateEmptyFields(request.body ?? {}, ["privileges"]);
|
|
||||||
|
|
||||||
if (errorEmpty) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requestBody.privileges.length) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("empty privilege array");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const rawPrivilege of requestBody.privileges) {
|
|
||||||
const errorInvalid = validatePrivilege(rawPrivilege);
|
|
||||||
|
|
||||||
if (errorInvalid) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorInvalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatePrivilegeRequests = requestBody.privileges.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", "value"],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
if (errorEmpty) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
const errorInvalid = validatePrivilege(requestBody);
|
|
||||||
|
|
||||||
if (errorInvalid) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const privilege = await PrivilegeModel.findOne({ privilegeId: requestBody.privilegeId }).lean();
|
|
||||||
|
|
||||||
if (privilege) {
|
|
||||||
void 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 getAllPrivileges = async () => PrivilegeModel.find({ isDeleted: false }).lean();
|
|
||||||
|
|
||||||
export const getAllPrivilegesMap = async () => {
|
|
||||||
const privileges = await PrivilegeModel.find({ isDeleted: false }).lean();
|
|
||||||
|
|
||||||
if (!privileges.length) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertPrivilegesToMap(privileges);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getServicePrivileges = async (request: GetServicePrivilegesRequest, reply: FastifyReply) => {
|
|
||||||
const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["serviceKey"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void 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) {
|
|
||||||
void reply.status(400);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(requestParams.privilegeId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const privilege = await PrivilegeModel.findOne({ privilegeId: requestParams.privilegeId, isDeleted: false }).lean();
|
|
||||||
|
|
||||||
if (!privilege) {
|
|
||||||
void 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", "value"],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
if (errorEmpty) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
const errorInvalid = validatePrivilege(requestBody);
|
|
||||||
|
|
||||||
if (errorInvalid) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const privilege = await PrivilegeModel.findOne({ privilegeId: requestBody.privilegeId });
|
|
||||||
|
|
||||||
if (!privilege) {
|
|
||||||
void 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 privilege;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removePrivilege = async (request: RemovePrivilegeRequest, reply: FastifyReply) => {
|
|
||||||
const [{ privilegeId }, error] = validateEmptyFields(request.body ?? {}, ["privilegeId"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(privilegeId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const privilege = await PrivilegeModel.findOneAndUpdate(
|
|
||||||
{ privilegeId },
|
|
||||||
{ $set: { isDeleted: true, deletedAt: new Date() } }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!privilege) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("privilege not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return privilege;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const replacePrivileges = async (request: RegisterPrivilegesRequest, reply: FastifyReply) => {
|
|
||||||
const [requestBody, errorEmpty] = validateEmptyFields(request.body ?? {}, ["privileges"]);
|
|
||||||
|
|
||||||
if (errorEmpty) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requestBody.privileges.length) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("empty privilege array");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const rawPrivilege of requestBody.privileges) {
|
|
||||||
const errorInvalid = validatePrivilege(rawPrivilege);
|
|
||||||
|
|
||||||
if (errorInvalid) {
|
|
||||||
void reply.status(400);
|
|
||||||
return errorInvalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const replacePrivilegeRequests = requestBody.privileges.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 restorePrivilege = async (request: RemovePrivilegeRequest, reply: FastifyReply) => {
|
|
||||||
const [{ privilegeId }, error] = validateEmptyFields(request.body ?? {}, ["privilegeId"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(privilegeId)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const privilege = await PrivilegeModel.findOneAndUpdate({ privilegeId }, { $set: { isDeleted: false } });
|
|
||||||
|
|
||||||
if (!privilege) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("privilege not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return privilege;
|
|
||||||
};
|
|
@ -1,33 +0,0 @@
|
|||||||
import type { FastifyRequest } from "fastify";
|
|
||||||
import type { Privilege } from "@/types/models/privilege.type";
|
|
||||||
import type { Eloquent } from "@/types/models/eloquent.type";
|
|
||||||
|
|
||||||
export type RawPrivilege = Partial<Omit<Privilege, keyof Eloquent>>;
|
|
||||||
|
|
||||||
export type RegisterPrivilegeRequest = FastifyRequest<{
|
|
||||||
Body?: RawPrivilege;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type RegisterPrivilegesRequest = FastifyRequest<{
|
|
||||||
Body?: {
|
|
||||||
privileges?: RawPrivilege[];
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetServicePrivilegesRequest = FastifyRequest<{
|
|
||||||
Params?: {
|
|
||||||
serviceKey?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetPrivilegeRequest = FastifyRequest<{
|
|
||||||
Params?: {
|
|
||||||
privilegeId?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type RemovePrivilegeRequest = FastifyRequest<{
|
|
||||||
Body?: {
|
|
||||||
privilegeId?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
@ -1,225 +0,0 @@
|
|||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
import { RoleModel } from "@/models/role.model";
|
|
||||||
|
|
||||||
import { convertArrayToRecord } from "@/utils/convert-array-to-record";
|
|
||||||
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
|
||||||
|
|
||||||
import type { FastifyReply } from "fastify";
|
|
||||||
import type { CreateRoleRequest, GetRoleRequest, RemoveRoleRequest, UpdateRoleRequest } from "./types";
|
|
||||||
|
|
||||||
export const getAllRoles = async () => RoleModel.find({ isDeleted: false }).lean();
|
|
||||||
|
|
||||||
export const createRole = async (request: CreateRoleRequest, reply: FastifyReply) => {
|
|
||||||
const [createRoleRequest, error] = validateEmptyFields(request.body, ["name", "permissions"]);
|
|
||||||
|
|
||||||
if (error || !createRoleRequest) {
|
|
||||||
void reply.status(400);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRoleExist = await RoleModel.exists({ name: createRoleRequest.name }).lean();
|
|
||||||
|
|
||||||
if (isRoleExist) {
|
|
||||||
void reply.status(409);
|
|
||||||
return new Error("role already exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
const permissionsRecord = convertArrayToRecord(createRoleRequest.permissions, true);
|
|
||||||
|
|
||||||
return RoleModel.create({ name: createRoleRequest.name, permissions: permissionsRecord });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteRole = async (request: RemoveRoleRequest, reply: FastifyReply) => {
|
|
||||||
const { id } = request.body || {};
|
|
||||||
|
|
||||||
if (!id || !Types.ObjectId.isValid(id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("wrong id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const deletedRole = await RoleModel.findByIdAndDelete(id);
|
|
||||||
|
|
||||||
if (!deletedRole) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return deletedRole.toJSON();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeRole = async (request: RemoveRoleRequest, reply: FastifyReply) => {
|
|
||||||
const { id } = request.body || {};
|
|
||||||
|
|
||||||
if (!id || !Types.ObjectId.isValid(id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("wrong id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = await RoleModel.findById(id);
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role by id not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role.isDeleted) {
|
|
||||||
void reply.status(409);
|
|
||||||
return new Error("role already deleted");
|
|
||||||
}
|
|
||||||
|
|
||||||
await role.updateOne({ $set: { isDeleted: true, deletedAt: Date.now() } });
|
|
||||||
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => {
|
|
||||||
const { query } = request.params || {};
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("query is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Types.ObjectId.isValid(query)) {
|
|
||||||
const role = await RoleModel.findOne({ _id: new Types.ObjectId(query), isDeleted: false }).lean();
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = await RoleModel.findOne({ name: query, isDeleted: false }).lean();
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyReply) => {
|
|
||||||
const [replaceRoleRequest, error] = validateEmptyFields(request.body ?? {}, ["name", "permissions"]);
|
|
||||||
const { query } = request.params || {};
|
|
||||||
|
|
||||||
if (error || !replaceRoleRequest) {
|
|
||||||
void reply.status(400);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("either name or id must be filled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Types.ObjectId.isValid(query)) {
|
|
||||||
const role = await RoleModel.findById(query);
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role by id not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
await role.replaceOne({
|
|
||||||
name: replaceRoleRequest.name,
|
|
||||||
permissions: convertArrayToRecord(replaceRoleRequest.permissions, true),
|
|
||||||
updatedAt: Date.now(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = await RoleModel.findOne({ name: query });
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
await role.replaceOne({
|
|
||||||
name: replaceRoleRequest.name,
|
|
||||||
permissions: convertArrayToRecord(replaceRoleRequest.permissions, true),
|
|
||||||
updatedAt: Date.now(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateRole = async (request: UpdateRoleRequest, reply: FastifyReply) => {
|
|
||||||
const { query } = request.params;
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("query is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!request.body?.name && !request.body?.permissions) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("either name or permissions must be filled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Types.ObjectId.isValid(query)) {
|
|
||||||
const role = await RoleModel.findById(query);
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role by id not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
await role.updateOne({
|
|
||||||
$set: {
|
|
||||||
name: request.body?.name,
|
|
||||||
permissions: request.body?.permissions && convertArrayToRecord(request.body.permissions, true),
|
|
||||||
updatedAt: Date.now(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = await RoleModel.findOne({ name: query });
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
await role.updateOne({
|
|
||||||
$set: {
|
|
||||||
name: request.body?.name,
|
|
||||||
permissions: request.body?.permissions && convertArrayToRecord(request.body.permissions, true),
|
|
||||||
updatedAt: Date.now(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restoreRole = async (request: RemoveRoleRequest, reply: FastifyReply) => {
|
|
||||||
const { id } = request.body || {};
|
|
||||||
|
|
||||||
if (!id || !Types.ObjectId.isValid(id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
return new Error("wrong id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = await RoleModel.findById(id);
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
void reply.status(404);
|
|
||||||
return new Error("role by id not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!role.isDeleted) {
|
|
||||||
void reply.status(409);
|
|
||||||
return new Error("role not removed");
|
|
||||||
}
|
|
||||||
|
|
||||||
await role.updateOne({ $set: { isDeleted: false } });
|
|
||||||
|
|
||||||
return role;
|
|
||||||
};
|
|
@ -1,22 +0,0 @@
|
|||||||
import type { FastifyRequest } from "fastify";
|
|
||||||
|
|
||||||
type RoleRequest = {
|
|
||||||
name?: string;
|
|
||||||
permissions?: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CreateRoleRequest = FastifyRequest<{ Body: RoleRequest }>;
|
|
||||||
export type RemoveRoleRequest = FastifyRequest<{ Body: { id?: string } }>;
|
|
||||||
|
|
||||||
export type GetRoleRequest = FastifyRequest<{
|
|
||||||
Params: {
|
|
||||||
query?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type UpdateRoleRequest = FastifyRequest<{
|
|
||||||
Body?: RoleRequest;
|
|
||||||
Params: {
|
|
||||||
query?: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
@ -1,18 +0,0 @@
|
|||||||
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", "privileges"], false);
|
|
||||||
|
|
||||||
if (errorEmpty) {
|
|
||||||
return [validatedTariff, errorEmpty];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validatedTariff.price && isNaN(Number(validatedTariff.price))) {
|
|
||||||
return [validatedTariff, new Error("invalid 'price' value")];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [validatedTariff, null];
|
|
||||||
};
|
|
@ -1,210 +0,0 @@
|
|||||||
import { Types } from "mongoose";
|
|
||||||
|
|
||||||
import { TariffModel } from "@/models/tariff.model";
|
|
||||||
import { PrivilegeModel } from "@/models/privilege.model";
|
|
||||||
|
|
||||||
import { validateEmptyFields } from "@/utils/validate-empty-fields";
|
|
||||||
import { determinePaginationParameters } from "@/utils/determine-pagination-parameters";
|
|
||||||
import { validateTariff } from "./helpers";
|
|
||||||
|
|
||||||
import type { FastifyReply } from "fastify";
|
|
||||||
import type { Privilege } from "@/types/models/privilege.type";
|
|
||||||
import type { Tariff } from "@/types/models/tariff.type";
|
|
||||||
import type { Eloquent } from "@/types/models/eloquent.type";
|
|
||||||
import type {
|
|
||||||
CreateTariffRequest,
|
|
||||||
GetTariffRequest,
|
|
||||||
ReplaceTariffRequest,
|
|
||||||
RemoveTariffRequest,
|
|
||||||
GetTariffsResponse,
|
|
||||||
GetTariffsRequest,
|
|
||||||
} from "./types";
|
|
||||||
|
|
||||||
export const getTariffs = async (request: GetTariffsRequest): Promise<GetTariffsResponse> => {
|
|
||||||
const { page, limit } = determinePaginationParameters(request?.query ?? {});
|
|
||||||
|
|
||||||
const tariffsCount = await TariffModel.countDocuments({
|
|
||||||
$or: [{ isCustom: false }, { isCustom: true, userId: request.user.id }],
|
|
||||||
});
|
|
||||||
|
|
||||||
const totalPages = Math.ceil(tariffsCount / limit);
|
|
||||||
const offset = (page - 1) * limit;
|
|
||||||
|
|
||||||
const tariffs = await TariffModel.find({ $or: [{ isCustom: false, isDeleted: false }, { isCustom: true, userId: request.user.id }] })
|
|
||||||
.sort({ order: "asc" })
|
|
||||||
.skip(offset)
|
|
||||||
.limit(limit)
|
|
||||||
.lean();
|
|
||||||
|
|
||||||
return { tariffs, totalPages };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTariff = async (request: GetTariffRequest, reply: FastifyReply): Promise<Tariff> => {
|
|
||||||
const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["id"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(requestParams.id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const tariff = await TariffModel.findOne({
|
|
||||||
$or: [
|
|
||||||
{ _id: new Types.ObjectId(requestParams.id), isCustom: false },
|
|
||||||
{ _id: new Types.ObjectId(requestParams.id), isCustom: true, userId: request.user.id },
|
|
||||||
],
|
|
||||||
}).lean();
|
|
||||||
|
|
||||||
if (!tariff) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("tariff not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return tariff;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createTariff = async (request: CreateTariffRequest, reply: FastifyReply): Promise<Tariff> => {
|
|
||||||
const [requestBody, error] = validateTariff(request.body);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTariff = new TariffModel({
|
|
||||||
name: requestBody.name,
|
|
||||||
description: requestBody.description,
|
|
||||||
order: requestBody.order,
|
|
||||||
price: requestBody.price,
|
|
||||||
userId: request.user.id,
|
|
||||||
isCustom: requestBody.isCustom,
|
|
||||||
privileges: requestBody.privileges,
|
|
||||||
});
|
|
||||||
|
|
||||||
return newTariff.save();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const replaceTariff = async (request: ReplaceTariffRequest, reply: FastifyReply): Promise<Tariff> => {
|
|
||||||
const [requestBody, error] = validateTariff(request.body ?? {});
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(request.params?.id || "")) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const tariff = await TariffModel.findById(request.params?.id);
|
|
||||||
|
|
||||||
if (!tariff) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("tariff not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const privilegesMap = new Map(requestBody.privileges.map((privilege) => [privilege.privilegeId, privilege]));
|
|
||||||
const privilegeIDs = requestBody.privileges.map(({ privilegeId }) => privilegeId);
|
|
||||||
const privileges = await PrivilegeModel.find({ privilegeId: privilegeIDs }).lean();
|
|
||||||
|
|
||||||
const cleanPrivileges = privileges.map<Omit<Privilege, keyof Eloquent>>((privilege) => {
|
|
||||||
const currentPrivilege = privilegesMap.get(privilege._id.toString());
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: privilege.name,
|
|
||||||
privilegeId: privilege.privilegeId,
|
|
||||||
serviceKey: privilege.serviceKey,
|
|
||||||
description: privilege.description,
|
|
||||||
amount: currentPrivilege?.amount ?? 0,
|
|
||||||
type: privilege.type,
|
|
||||||
value: privilege.value,
|
|
||||||
price: privilege.price,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
await tariff.replaceOne({
|
|
||||||
order: requestBody.order,
|
|
||||||
name: requestBody.name,
|
|
||||||
price: requestBody.price,
|
|
||||||
isCustom: requestBody.isCustom,
|
|
||||||
privileges: cleanPrivileges,
|
|
||||||
});
|
|
||||||
|
|
||||||
return tariff;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeTariff = async (request: RemoveTariffRequest, reply: FastifyReply): Promise<Tariff> => {
|
|
||||||
const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const tariff = await TariffModel.findByIdAndUpdate(id, {
|
|
||||||
$set: { isDeleted: true, deletedAt: new Date() },
|
|
||||||
}).lean();
|
|
||||||
|
|
||||||
if (!tariff) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("tariff not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return tariff;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteTariff = async (request: RemoveTariffRequest, reply: FastifyReply): Promise<Tariff> => {
|
|
||||||
const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const tariff = await TariffModel.findByIdAndDelete(id).lean();
|
|
||||||
|
|
||||||
if (!tariff) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("tariff not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return tariff;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restoreTariff = async (request: RemoveTariffRequest, reply: FastifyReply): Promise<Tariff> => {
|
|
||||||
const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Types.ObjectId.isValid(id)) {
|
|
||||||
void reply.status(400);
|
|
||||||
throw new Error("invalid id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const tariff = await TariffModel.findByIdAndUpdate(id, { $set: { isDeleted: false } }).lean();
|
|
||||||
|
|
||||||
if (!tariff) {
|
|
||||||
void reply.status(404);
|
|
||||||
throw new Error("tariff not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return tariff;
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
import type { FastifyRequest } from "fastify";
|
|
||||||
import type { TariffMessage } from "@/types/messages/tariff-message.type";
|
|
||||||
import type { Tariff } from "@/types/models/tariff.type";
|
|
||||||
import type { PaginationParams } from "@/types/messages/pagination.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 };
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetTariffsRequest = FastifyRequest<{
|
|
||||||
Querystring?: PaginationParams;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type GetTariffsResponse = {
|
|
||||||
tariffs: Tariff[];
|
|
||||||
totalPages: number;
|
|
||||||
};
|
|
27
src/index.ts
27
src/index.ts
@ -1,27 +0,0 @@
|
|||||||
import "./configuration/configure-env";
|
|
||||||
|
|
||||||
import { Server } from "./server";
|
|
||||||
|
|
||||||
import { CONFIGURATION } from "@/constants/configuration";
|
|
||||||
|
|
||||||
console.info("server configuration: \n", JSON.stringify(CONFIGURATION, null, 2));
|
|
||||||
console.info("env: \n", JSON.stringify(process.env, null, 2));
|
|
||||||
|
|
||||||
const server = new Server({
|
|
||||||
serverOptions: CONFIGURATION.http,
|
|
||||||
databaseOptions: CONFIGURATION.db,
|
|
||||||
pluginsOptions: {
|
|
||||||
jwt: {
|
|
||||||
secret: {
|
|
||||||
public: CONFIGURATION.service.publicAccessSecretKey,
|
|
||||||
private: "secret",
|
|
||||||
},
|
|
||||||
verify: {
|
|
||||||
allowedIss: "pena-auth-service",
|
|
||||||
allowedAud: "pena",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
server.start();
|
|
@ -1,36 +0,0 @@
|
|||||||
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,
|
|
||||||
index: { unique: 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,25 +0,0 @@
|
|||||||
import { SchemaDefinition } from "mongoose";
|
|
||||||
|
|
||||||
import type { Eloquent } from "@/types/models/eloquent.type";
|
|
||||||
|
|
||||||
export const eloquentSchema: SchemaDefinition<Eloquent> = {
|
|
||||||
createdAt: {
|
|
||||||
type: Date,
|
|
||||||
required: true,
|
|
||||||
default: Date.now,
|
|
||||||
},
|
|
||||||
updatedAt: {
|
|
||||||
type: Date,
|
|
||||||
required: true,
|
|
||||||
default: Date.now,
|
|
||||||
},
|
|
||||||
deletedAt: {
|
|
||||||
type: Date,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
isDeleted: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,28 +0,0 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
|
||||||
|
|
||||||
import { eloquentSchema } from "./eloquent.schema";
|
|
||||||
|
|
||||||
import type { Permission } from "@/types/models/permission.type";
|
|
||||||
|
|
||||||
const schema: SchemaDefinition<Permission> = {
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
index: { unique: true },
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
default: "Разрешение на создание ролей",
|
|
||||||
},
|
|
||||||
...eloquentSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaSettings = {
|
|
||||||
versionKey: false,
|
|
||||||
collection: "permissions",
|
|
||||||
};
|
|
||||||
|
|
||||||
const PermissionSchema = new Schema<Permission>(schema, schemaSettings);
|
|
||||||
|
|
||||||
export const PermissionModel = model("Permission", PermissionSchema);
|
|
@ -1,55 +0,0 @@
|
|||||||
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,
|
|
||||||
},
|
|
||||||
amount: {
|
|
||||||
type: Number,
|
|
||||||
require: false,
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
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: false,
|
|
||||||
},
|
|
||||||
...eloquentSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaSettings = {
|
|
||||||
versionKey: false,
|
|
||||||
collection: "privileges",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PrivilegeSchema = new Schema<Privilege>(schema, schemaSettings);
|
|
||||||
|
|
||||||
export const PrivilegeModel = model("Privilege", PrivilegeSchema);
|
|
@ -1,27 +0,0 @@
|
|||||||
import { Schema, model, SchemaDefinition } from "mongoose";
|
|
||||||
|
|
||||||
import { eloquentSchema } from "./eloquent.schema";
|
|
||||||
|
|
||||||
import type { Role } from "@/types/models/role.type";
|
|
||||||
|
|
||||||
const schema: SchemaDefinition<Role> = {
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
permissions: {
|
|
||||||
type: Map,
|
|
||||||
of: Boolean,
|
|
||||||
default: {},
|
|
||||||
},
|
|
||||||
...eloquentSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaSettings = {
|
|
||||||
versionKey: false,
|
|
||||||
collection: "roles",
|
|
||||||
};
|
|
||||||
|
|
||||||
const RoleSchema = new Schema<Role>(schema, schemaSettings);
|
|
||||||
|
|
||||||
export const RoleModel = model("Role", RoleSchema);
|
|
@ -1,47 +0,0 @@
|
|||||||
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,
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
price: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
order: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
userId: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
isCustom: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
privileges: {
|
|
||||||
type: [PrivilegeSchema],
|
|
||||||
default: [],
|
|
||||||
},
|
|
||||||
...eloquentSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
const schemaSettings = {
|
|
||||||
versionKey: false,
|
|
||||||
collection: "tariffs",
|
|
||||||
};
|
|
||||||
|
|
||||||
const TariffSchema = new Schema<Tariff>(schema, schemaSettings);
|
|
||||||
|
|
||||||
export const TariffModel = model("Tariff", TariffSchema);
|
|
@ -1,44 +0,0 @@
|
|||||||
import fastifyPlugin from "fastify-plugin";
|
|
||||||
|
|
||||||
import type { FastifyError, FastifyInstance, FastifyPluginOptions, RouteOptions } from "fastify";
|
|
||||||
|
|
||||||
type PrintRoutesRouteOptions = {
|
|
||||||
hide?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const METHODS_ORDER = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS"];
|
|
||||||
|
|
||||||
const printRoutes = (routes: Array<RouteOptions & PrintRoutesRouteOptions> = [], isSwagger = false) => {
|
|
||||||
if (routes.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredRoutes = routes.filter((route) => route.hide !== true);
|
|
||||||
const sortedRoutes = [...filteredRoutes].sort((routeA, routeB) => routeA.url.localeCompare(routeB.url));
|
|
||||||
const output = sortedRoutes.reduce<string>((accamulator, route) => {
|
|
||||||
const methods = Array.isArray(route.method) ? route.method : [route.method];
|
|
||||||
const methodsValue = [...methods].sort((a, b) => METHODS_ORDER.indexOf(a) - METHODS_ORDER.indexOf(b)).join(" | ");
|
|
||||||
|
|
||||||
return accamulator + `${methodsValue}\t${route.url}\n`;
|
|
||||||
}, "");
|
|
||||||
const swaggerOutput = isSwagger ? "GET\t/swagger\n" : "";
|
|
||||||
|
|
||||||
console.info(`\n\nAvailable routes:\n${output + swaggerOutput}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default fastifyPlugin(
|
|
||||||
(instance: FastifyInstance, _: FastifyPluginOptions, done: (error?: FastifyError) => void) => {
|
|
||||||
const routes: Array<RouteOptions> = [];
|
|
||||||
|
|
||||||
instance.addHook("onRoute", (route) => {
|
|
||||||
routes.push(route);
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.addHook("onReady", (next) => {
|
|
||||||
printRoutes(routes, !!instance.swagger);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,50 +0,0 @@
|
|||||||
import { Router } from "@/server/router";
|
|
||||||
|
|
||||||
import {
|
|
||||||
createAccount,
|
|
||||||
getAccountByID,
|
|
||||||
getAccount,
|
|
||||||
setAccountRole,
|
|
||||||
getAccounts,
|
|
||||||
deleteAccount,
|
|
||||||
deleteAccountById,
|
|
||||||
removeAccount,
|
|
||||||
removeAccountById,
|
|
||||||
restoreAccount,
|
|
||||||
} from "@/handlers/account";
|
|
||||||
import { verifyUser } from "@/handlers/auth/middleware";
|
|
||||||
|
|
||||||
import {
|
|
||||||
createAccountSchema,
|
|
||||||
getAccountByIdSchema,
|
|
||||||
getAccountSchema,
|
|
||||||
setAccountRoleSchema,
|
|
||||||
getAccountsSchema,
|
|
||||||
removeAccountSchema,
|
|
||||||
removeAccountByIdSchema,
|
|
||||||
restoreAccountSchema,
|
|
||||||
deleteAccountSchema,
|
|
||||||
deleteAccountByIdSchema,
|
|
||||||
} from "@/swagger/account";
|
|
||||||
|
|
||||||
export const setAccountRoutes = (router: Router): void => {
|
|
||||||
router.get("/pagination", getAccounts, { schema: getAccountsSchema });
|
|
||||||
router.get("/:userId", getAccountByID, { schema: getAccountByIdSchema });
|
|
||||||
router.get("/", getAccount, { preHandler: [verifyUser], 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("/:userId", removeAccountById, {
|
|
||||||
preHandler: [verifyUser],
|
|
||||||
schema: removeAccountByIdSchema,
|
|
||||||
});
|
|
||||||
router.delete("/delete", deleteAccount, { preHandler: [verifyUser], schema: deleteAccountSchema });
|
|
||||||
router.delete("/delete/:userId", deleteAccountById, {
|
|
||||||
preHandler: [verifyUser],
|
|
||||||
schema: deleteAccountByIdSchema,
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,31 +0,0 @@
|
|||||||
import { Router } from "@/server/router";
|
|
||||||
|
|
||||||
import {
|
|
||||||
getAllPermissions,
|
|
||||||
getPermissionById,
|
|
||||||
createPermission,
|
|
||||||
updatePermission,
|
|
||||||
removePermission,
|
|
||||||
restorePermission,
|
|
||||||
} from "@/handlers/permission";
|
|
||||||
|
|
||||||
import {
|
|
||||||
getAllPermissionsSchema,
|
|
||||||
getPermissionByIdSchema,
|
|
||||||
createPermissionSchema,
|
|
||||||
removePermissionSchema,
|
|
||||||
restorePermissionSchema,
|
|
||||||
updatePermissionSchema,
|
|
||||||
} from "@/swagger/permission";
|
|
||||||
|
|
||||||
export const setPermissionRoutes = (router: Router): void => {
|
|
||||||
router.get("/all", getAllPermissions, { schema: getAllPermissionsSchema });
|
|
||||||
router.get("/:permissionId", getPermissionById, { schema: getPermissionByIdSchema });
|
|
||||||
|
|
||||||
router.post("/", createPermission, { schema: createPermissionSchema });
|
|
||||||
router.post("/restore/:permissionId", restorePermission, { schema: restorePermissionSchema });
|
|
||||||
|
|
||||||
router.patch("/:permissionId", updatePermission, { schema: updatePermissionSchema });
|
|
||||||
|
|
||||||
router.delete("/:permissionId", removePermission, { schema: removePermissionSchema });
|
|
||||||
};
|
|
@ -1,40 +0,0 @@
|
|||||||
import { Router } from "@/server/router";
|
|
||||||
|
|
||||||
import {
|
|
||||||
registerPrivilege,
|
|
||||||
getAllPrivileges,
|
|
||||||
getAllPrivilegesMap,
|
|
||||||
getPrivilege,
|
|
||||||
getServicePrivileges,
|
|
||||||
replacePrivilege,
|
|
||||||
registerPrivileges,
|
|
||||||
removePrivilege,
|
|
||||||
replacePrivileges,
|
|
||||||
restorePrivilege,
|
|
||||||
} from "@/handlers/privilege";
|
|
||||||
|
|
||||||
import {
|
|
||||||
getPrivilegesSchema,
|
|
||||||
getPrivilegesMapSchema,
|
|
||||||
getPrivilegeSchema,
|
|
||||||
getServicePrivilegesSchema,
|
|
||||||
registerPrivilegeSchema,
|
|
||||||
registerPrivilegesSchema,
|
|
||||||
replacePrivilegeSchema,
|
|
||||||
replacePrivilegesSchema,
|
|
||||||
removePrivilegeSchema,
|
|
||||||
restorePrivilegeSchema,
|
|
||||||
} from "@/swagger/privilege";
|
|
||||||
|
|
||||||
export const setPrivilegeRoutes = (router: Router): void => {
|
|
||||||
router.get("/", getAllPrivileges, { schema: getPrivilegesSchema });
|
|
||||||
router.get("/service", getAllPrivilegesMap, { schema: getPrivilegesMapSchema });
|
|
||||||
router.get("/:privilegeId", getPrivilege, { schema: getPrivilegeSchema });
|
|
||||||
router.get("/service/:serviceKey", getServicePrivileges, { schema: getServicePrivilegesSchema });
|
|
||||||
router.post("/", registerPrivilege, { schema: registerPrivilegeSchema });
|
|
||||||
router.post("/many", registerPrivileges, { schema: registerPrivilegesSchema });
|
|
||||||
router.post("/restore/", restorePrivilege, { schema: restorePrivilegeSchema });
|
|
||||||
router.put("/", replacePrivilege, { schema: replacePrivilegeSchema });
|
|
||||||
router.put("/many", replacePrivileges, { schema: replacePrivilegesSchema });
|
|
||||||
router.delete("/", removePrivilege, { schema: removePrivilegeSchema });
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
import { Router } from "@/server/router";
|
|
||||||
|
|
||||||
import {
|
|
||||||
getRole,
|
|
||||||
getAllRoles,
|
|
||||||
createRole,
|
|
||||||
deleteRole,
|
|
||||||
updateRole,
|
|
||||||
replaceRole,
|
|
||||||
removeRole,
|
|
||||||
restoreRole,
|
|
||||||
} from "@/handlers/roles";
|
|
||||||
|
|
||||||
import {
|
|
||||||
getRolesSchema,
|
|
||||||
getRoleSchema,
|
|
||||||
createRoleSchema,
|
|
||||||
restoreRoleSchema,
|
|
||||||
updateRoleSchema,
|
|
||||||
replaceRoleSchema,
|
|
||||||
removeRoleSchema,
|
|
||||||
deleteRoleSchema,
|
|
||||||
} from "@/swagger/role";
|
|
||||||
|
|
||||||
export const setRoleRoutes = (router: Router): void => {
|
|
||||||
router.get("/", getAllRoles, { schema: getRolesSchema });
|
|
||||||
router.get("/:query", getRole, { schema: getRoleSchema });
|
|
||||||
router.post("/", createRole, { schema: createRoleSchema });
|
|
||||||
router.post("/restore", restoreRole, { schema: restoreRoleSchema });
|
|
||||||
router.patch("/:query", updateRole, { schema: updateRoleSchema });
|
|
||||||
router.put("/:query", replaceRole, { schema: replaceRoleSchema });
|
|
||||||
router.delete("/", removeRole, { schema: removeRoleSchema });
|
|
||||||
router.delete("/delete", deleteRole, { schema: deleteRoleSchema });
|
|
||||||
};
|
|
@ -1,32 +0,0 @@
|
|||||||
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, { preHandler: [verifyUser], schema: getTariffsSchema });
|
|
||||||
router.get("/:id", getTariff, { preHandler: [verifyUser], 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,61 +0,0 @@
|
|||||||
import fastify, { FastifyInstance } from "fastify";
|
|
||||||
import { connect as mongoConnect } from "mongoose";
|
|
||||||
|
|
||||||
import { Router } from "./router";
|
|
||||||
|
|
||||||
import { registerFastifyPlugins } from "@/configuration/register-fastify-plugins";
|
|
||||||
import { combineRoutes } from "@/configuration/combine-routes";
|
|
||||||
import { constituteMongoURI } from "@/configuration/constitute-mongo-uri";
|
|
||||||
|
|
||||||
import { DEFAULT } from "@/constants/default";
|
|
||||||
|
|
||||||
import type { PluginsOptions } from "@/types/configuration/plugins-options";
|
|
||||||
import type { DatabaseOptions } from "@/types/configuration/database-options";
|
|
||||||
|
|
||||||
type ServerOptions = {
|
|
||||||
port?: number;
|
|
||||||
host?: string;
|
|
||||||
backlog?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ServerArgs = {
|
|
||||||
serverOptions?: ServerOptions;
|
|
||||||
pluginsOptions?: PluginsOptions;
|
|
||||||
databaseOptions?: DatabaseOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Server {
|
|
||||||
private fastify: FastifyInstance;
|
|
||||||
private serverOptions?: ServerOptions;
|
|
||||||
private databaseOptions?: DatabaseOptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Настройка сервера
|
|
||||||
* @param {ServerOptions} serverOptions объект настроек сервера.
|
|
||||||
* @param {DatabaseOptions} databaseOptions объект настроек подключения к базе данных.
|
|
||||||
* @param {PluginsOptions} pluginsOptions объект настроек плагинов fastify.
|
|
||||||
*/
|
|
||||||
constructor({ serverOptions, databaseOptions, pluginsOptions }: ServerArgs) {
|
|
||||||
this.serverOptions = serverOptions;
|
|
||||||
this.databaseOptions = databaseOptions;
|
|
||||||
this.fastify = fastify(DEFAULT.fastifyOptions);
|
|
||||||
|
|
||||||
if (pluginsOptions) {
|
|
||||||
registerFastifyPlugins(this.fastify, pluginsOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
combineRoutes(new Router(this.fastify));
|
|
||||||
}
|
|
||||||
|
|
||||||
public start = async () => {
|
|
||||||
const fasticyConnection = this.fastify.listen(this.serverOptions);
|
|
||||||
const databaseConnection = this.databaseOptions ? mongoConnect(constituteMongoURI(this.databaseOptions)) : null;
|
|
||||||
|
|
||||||
await Promise.all([databaseConnection, fasticyConnection])
|
|
||||||
.then(() => {
|
|
||||||
this.fastify.swagger();
|
|
||||||
console.info(`server started on ${this.serverOptions?.host}:${this.serverOptions?.port}`);
|
|
||||||
})
|
|
||||||
.catch((reason) => console.error(reason));
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
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);
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { RoleModel } from "@/models/role.model";
|
|
||||||
|
|
||||||
import type { Role } from "@/types/models/role.type";
|
|
||||||
import type { Account } from "@/types/models/account.type";
|
|
||||||
|
|
||||||
export class AccountService {
|
|
||||||
public static async determineAccountRole(account: Account): Promise<Role> {
|
|
||||||
const role = await RoleModel.findOne({ name: account.role }).lean();
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
throw new Error("role not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import type { Account } from "@/types/models/account.type";
|
|
||||||
import type { Role } from "@/types/models/role.type";
|
|
||||||
|
|
||||||
export interface AccountService {
|
|
||||||
determineAccountRole(account: Account): Promise<Role>;
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import { AccountService } from "@/services/account/account.service";
|
|
||||||
import { PermissionService } from "./permission.service";
|
|
||||||
|
|
||||||
export const PermissionModule = new PermissionService({
|
|
||||||
accountService: AccountService,
|
|
||||||
});
|
|
@ -1,78 +0,0 @@
|
|||||||
import { mock, mockReset } from "jest-mock-extended";
|
|
||||||
|
|
||||||
import { PermissionService } from "./permission.service";
|
|
||||||
|
|
||||||
import { PERMISSIONS } from "@/constants/permissions";
|
|
||||||
|
|
||||||
import type { AccountService } from "./permission.interface";
|
|
||||||
import type { Account } from "@/types/models/account.type";
|
|
||||||
|
|
||||||
const DEFAULT_ACCOUNT: Account = {
|
|
||||||
userId: "userId",
|
|
||||||
nickname: "nickname",
|
|
||||||
avatar: "/img/avatar.png",
|
|
||||||
role: "admin",
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
isDeleted: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("PermissionService", () => {
|
|
||||||
const accountService = mock<AccountService>();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockReset(accountService);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("deleteAccount", () => {
|
|
||||||
test("Успешное определение доступа на удаление аккаунта", async () => {
|
|
||||||
const permissionService = new PermissionService({ accountService });
|
|
||||||
|
|
||||||
accountService.determineAccountRole.mockResolvedValueOnce({
|
|
||||||
name: "admin",
|
|
||||||
permissions: {
|
|
||||||
[PERMISSIONS.deleteAccount]: true,
|
|
||||||
},
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
isDeleted: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const isAvailableToDeleteAccount = await permissionService.deleteAccount(DEFAULT_ACCOUNT);
|
|
||||||
|
|
||||||
expect(accountService.determineAccountRole).toHaveBeenCalledWith(DEFAULT_ACCOUNT);
|
|
||||||
expect(accountService.determineAccountRole).toHaveBeenCalledTimes(1);
|
|
||||||
expect(isAvailableToDeleteAccount).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("У пользователя нет прав на удаление", async () => {
|
|
||||||
const permissionService = new PermissionService({ accountService });
|
|
||||||
|
|
||||||
accountService.determineAccountRole.mockResolvedValueOnce({
|
|
||||||
name: "admin",
|
|
||||||
permissions: {
|
|
||||||
read: true,
|
|
||||||
},
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
isDeleted: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const isAvailableToDeleteAccount = await permissionService.deleteAccount(DEFAULT_ACCOUNT);
|
|
||||||
|
|
||||||
expect(accountService.determineAccountRole).toHaveBeenCalledWith(DEFAULT_ACCOUNT);
|
|
||||||
expect(accountService.determineAccountRole).toHaveBeenCalledTimes(1);
|
|
||||||
expect(isAvailableToDeleteAccount).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Ошибка должна успешно пробрасываться", async () => {
|
|
||||||
const permissionService = new PermissionService({ accountService });
|
|
||||||
|
|
||||||
accountService.determineAccountRole.mockRejectedValueOnce(new Error("role not found"));
|
|
||||||
|
|
||||||
expect(permissionService.deleteAccount(DEFAULT_ACCOUNT)).resolves.toBe(false);
|
|
||||||
expect(accountService.determineAccountRole).toHaveBeenCalledWith(DEFAULT_ACCOUNT);
|
|
||||||
expect(accountService.determineAccountRole).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,39 +0,0 @@
|
|||||||
import { PermissionModel } from "@/models/permission.model";
|
|
||||||
|
|
||||||
import { PERMISSIONS, PERMISSION_LIST } from "@/constants/permissions";
|
|
||||||
|
|
||||||
import type { Account } from "@/types/models/account.type";
|
|
||||||
import type { AccountService } from "./permission.interface";
|
|
||||||
import type { Permission } from "@/types/models/permission.type";
|
|
||||||
|
|
||||||
type PermissionServiceDeps = {
|
|
||||||
readonly accountService: AccountService;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class PermissionService {
|
|
||||||
private accountService: AccountService;
|
|
||||||
|
|
||||||
constructor(deps: PermissionServiceDeps) {
|
|
||||||
this.accountService = deps.accountService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async deleteAccount(account: Account): Promise<boolean> {
|
|
||||||
try {
|
|
||||||
const role = await this.accountService.determineAccountRole(account);
|
|
||||||
|
|
||||||
if (!role.permissions[PERMISSIONS.deleteAccount]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getAllPermissions(): Promise<Permission[]> {
|
|
||||||
const permissions = await PermissionModel.find({}).lean();
|
|
||||||
|
|
||||||
return [...permissions, ...PERMISSION_LIST];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
import { getAccountParams, setAccountRoleBody, getAccountsQuerystring } from "./inputs";
|
|
||||||
import {
|
|
||||||
getAccountResponse,
|
|
||||||
createAccountResponse,
|
|
||||||
setAccountRoleResponse,
|
|
||||||
getAccountsResponse,
|
|
||||||
removeAccountResponse,
|
|
||||||
} from "./responses";
|
|
||||||
|
|
||||||
import type { SwaggerSchema } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getAccountsSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение информации об аккаунтах",
|
|
||||||
description: "Получение список аккаунтов с пагинацией из БД",
|
|
||||||
tags: ["account"],
|
|
||||||
querystring: getAccountsQuerystring,
|
|
||||||
response: getAccountsResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccountByIdSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение информации об аккаунте",
|
|
||||||
description: "Получение аккаунта по ID",
|
|
||||||
tags: ["account"],
|
|
||||||
params: getAccountParams,
|
|
||||||
response: getAccountResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccountSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение информации об аккаунте",
|
|
||||||
description: "Получение информации об аккаунте через токен доступа",
|
|
||||||
tags: ["account"],
|
|
||||||
security: [{ bearer: [] }],
|
|
||||||
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: removeAccountResponse,
|
|
||||||
security: [{ bearer: [] }],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeAccountByIdSchema: SwaggerSchema = {
|
|
||||||
summary: "Удаление аккаунта по ID",
|
|
||||||
description: "Помечает аккаунт удалённым, но не удаляет его из БД",
|
|
||||||
tags: ["account"],
|
|
||||||
params: getAccountParams,
|
|
||||||
response: removeAccountResponse,
|
|
||||||
security: [{ bearer: [] }],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteAccountSchema: SwaggerSchema = {
|
|
||||||
summary: "Удаление аккаунта",
|
|
||||||
description: "Удаляет аккаунт из БД окончательно",
|
|
||||||
tags: ["account"],
|
|
||||||
response: removeAccountResponse,
|
|
||||||
security: [{ bearer: [] }],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteAccountByIdSchema: SwaggerSchema = {
|
|
||||||
summary: "Удаление аккаунта по ID",
|
|
||||||
description: "Удаляет аккаунт из БД окончательно",
|
|
||||||
tags: ["account"],
|
|
||||||
params: getAccountParams,
|
|
||||||
response: removeAccountResponse,
|
|
||||||
security: [{ bearer: [] }],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restoreAccountSchema: SwaggerSchema = {
|
|
||||||
summary: "Восстановление аккаунта",
|
|
||||||
description: "Восстанавливает аккаунт, который не был удалён окончательно",
|
|
||||||
tags: ["account"],
|
|
||||||
response: removeAccountResponse,
|
|
||||||
security: [{ bearer: [] }],
|
|
||||||
};
|
|
@ -1,41 +0,0 @@
|
|||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getAccountParams: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["userId"],
|
|
||||||
properties: {
|
|
||||||
userId: {
|
|
||||||
type: "string",
|
|
||||||
description: "ID пользователя",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccountsQuerystring: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
page: {
|
|
||||||
type: "number",
|
|
||||||
description: "номер страницы",
|
|
||||||
},
|
|
||||||
limit: {
|
|
||||||
type: "number",
|
|
||||||
description: "Лимит количества аккаунтов (больше 100 не обрабатывается)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setAccountRoleBody: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["userId", "role"],
|
|
||||||
properties: {
|
|
||||||
userId: {
|
|
||||||
type: "string",
|
|
||||||
description: "ID пользователя",
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
type: "string",
|
|
||||||
description: "название роли",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,90 +0,0 @@
|
|||||||
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",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const accounts: SwaggerMessage = {
|
|
||||||
description: "Список аккаунтов",
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
accounts: {
|
|
||||||
type: "array",
|
|
||||||
description: "Массив аккаунтов",
|
|
||||||
items: account,
|
|
||||||
},
|
|
||||||
totalPages: { type: "number" },
|
|
||||||
},
|
|
||||||
examples: [
|
|
||||||
{
|
|
||||||
totalPages: 10,
|
|
||||||
accounts: [
|
|
||||||
{
|
|
||||||
_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",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@ -1,36 +0,0 @@
|
|||||||
import { swaggerError } from "@/utils/swagger-error";
|
|
||||||
|
|
||||||
import { account, accounts } from "./models";
|
|
||||||
|
|
||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getAccountsResponse: Record<string, SwaggerMessage> = {
|
|
||||||
200: accounts,
|
|
||||||
};
|
|
||||||
|
|
||||||
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 removeAccountResponse: Record<string, SwaggerMessage> = {
|
|
||||||
200: account,
|
|
||||||
400: swaggerError(400, "invalid user id"),
|
|
||||||
401: swaggerError(401, "invalid token"),
|
|
||||||
404: swaggerError(404, "user not found"),
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
import { getPermissionParams, createPermissionBody } from "./inputs";
|
|
||||||
import { getPermissionResponse, getAllPermissionsResponse, createPermissionResponse } from "./responses";
|
|
||||||
|
|
||||||
import type { SwaggerSchema } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getAllPermissionsSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение информации об разрешениях",
|
|
||||||
description: "Получение списка всех разрешений из БД",
|
|
||||||
tags: ["permission"],
|
|
||||||
response: getAllPermissionsResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPermissionByIdSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение информации об аккаунте",
|
|
||||||
description: "Получение аккаунта по ID",
|
|
||||||
tags: ["permission"],
|
|
||||||
params: getPermissionParams,
|
|
||||||
response: getPermissionResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createPermissionSchema: SwaggerSchema = {
|
|
||||||
summary: "Создание разрешения",
|
|
||||||
tags: ["permission"],
|
|
||||||
body: createPermissionBody,
|
|
||||||
response: createPermissionResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removePermissionSchema: SwaggerSchema = {
|
|
||||||
summary: "Удаление разрешения",
|
|
||||||
description: "Помечает разрешение удалённым, но не удаляет его из БД",
|
|
||||||
tags: ["permission"],
|
|
||||||
params: getPermissionParams,
|
|
||||||
response: getPermissionResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restorePermissionSchema: SwaggerSchema = {
|
|
||||||
summary: "Восстановление разрешения",
|
|
||||||
description: "Восстанавливает разрешение, которое не было удалёно окончательно",
|
|
||||||
tags: ["permission"],
|
|
||||||
params: getPermissionParams,
|
|
||||||
response: getPermissionResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePermissionSchema: SwaggerSchema = {
|
|
||||||
summary: "Обновление разрешения",
|
|
||||||
description: "Обновляет данные о разрешении",
|
|
||||||
tags: ["permission"],
|
|
||||||
params: getPermissionParams,
|
|
||||||
body: createPermissionBody,
|
|
||||||
response: getPermissionResponse,
|
|
||||||
};
|
|
@ -1,41 +0,0 @@
|
|||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getPermissionParams: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["permissionId"],
|
|
||||||
properties: {
|
|
||||||
permissionId: {
|
|
||||||
type: "string",
|
|
||||||
description: "ID разрешения",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccountsQuerystring: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
page: {
|
|
||||||
type: "number",
|
|
||||||
description: "номер страницы",
|
|
||||||
},
|
|
||||||
limit: {
|
|
||||||
type: "number",
|
|
||||||
description: "Лимит количества аккаунтов (больше 100 не обрабатывается)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createPermissionBody: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["name", "description"],
|
|
||||||
properties: {
|
|
||||||
name: {
|
|
||||||
type: "string",
|
|
||||||
description: "имя разрешения",
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: "string",
|
|
||||||
description: "описание разрешения",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,42 +0,0 @@
|
|||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const permission: SwaggerMessage = {
|
|
||||||
description: "Разрешение",
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
_id: { type: "string" },
|
|
||||||
name: { type: "string" },
|
|
||||||
description: { 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",
|
|
||||||
name: "hub-admin-backend-service.deleteAccount",
|
|
||||||
nickname: "Разрешение на удаление аккаунта",
|
|
||||||
avatar: "/media/avatar/default-avatar.jpg",
|
|
||||||
role: "user",
|
|
||||||
isDeleted: false,
|
|
||||||
createdAt: "2017-07-21T17:32:28Z",
|
|
||||||
updatedAt: "2017-07-21T17:32:28Z",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const permissions: SwaggerMessage = {
|
|
||||||
description: "Список разрешений",
|
|
||||||
type: "array",
|
|
||||||
items: permission,
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import { swaggerError } from "@/utils/swagger-error";
|
|
||||||
|
|
||||||
import { permission, permissions } from "./models";
|
|
||||||
|
|
||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getAllPermissionsResponse: Record<string, SwaggerMessage> = {
|
|
||||||
200: permissions,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPermissionResponse: Record<string, SwaggerMessage> = {
|
|
||||||
200: permission,
|
|
||||||
400: swaggerError(400, "invalid permission id"),
|
|
||||||
404: swaggerError(400, "permission not found"),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createPermissionResponse: Record<string, SwaggerMessage> = {
|
|
||||||
200: permission,
|
|
||||||
409: swaggerError(409, "permission already exist"),
|
|
||||||
};
|
|
@ -1,84 +0,0 @@
|
|||||||
import { privilegeBody, registerPrivilegesBody, getPrivilegeParams, getServicePrivilegesParams } from "./inputs";
|
|
||||||
import {
|
|
||||||
getPrivilegeReponse,
|
|
||||||
getPrivilegesReponse,
|
|
||||||
getAllPrivilegesMapReponse,
|
|
||||||
getAllPrivilegesReponse,
|
|
||||||
registerPrivilegeResponse,
|
|
||||||
replacePrivilegeResponse,
|
|
||||||
registerPrivilegesResponse,
|
|
||||||
replacePrivilegesResponse,
|
|
||||||
removePrivilegeResponse,
|
|
||||||
} from "./responses";
|
|
||||||
|
|
||||||
import type { SwaggerSchema } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getPrivilegesSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение всех привелегий",
|
|
||||||
description: "Получение всех привелегий в виде массива",
|
|
||||||
tags: ["privilege"],
|
|
||||||
response: getAllPrivilegesReponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPrivilegesMapSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение всех привелегий",
|
|
||||||
description: "Получение всех привелегий в виде объекта ключ-значение, где ключём является serviceKey",
|
|
||||||
tags: ["privilege"],
|
|
||||||
response: getAllPrivilegesMapReponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPrivilegeSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение привилегии по ID",
|
|
||||||
tags: ["privilege"],
|
|
||||||
params: getPrivilegeParams,
|
|
||||||
response: getPrivilegeReponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getServicePrivilegesSchema: SwaggerSchema = {
|
|
||||||
summary: "Получение привилегий сервиса",
|
|
||||||
tags: ["privilege"],
|
|
||||||
params: getServicePrivilegesParams,
|
|
||||||
response: getPrivilegesReponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerPrivilegeSchema: SwaggerSchema = {
|
|
||||||
summary: "Регистрация привелегии сервиса",
|
|
||||||
tags: ["privilege"],
|
|
||||||
body: privilegeBody,
|
|
||||||
response: registerPrivilegeResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerPrivilegesSchema: SwaggerSchema = {
|
|
||||||
summary: "Регистрация привелегий сервиса",
|
|
||||||
tags: ["privilege"],
|
|
||||||
body: registerPrivilegesBody,
|
|
||||||
response: registerPrivilegesResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const replacePrivilegeSchema: SwaggerSchema = {
|
|
||||||
summary: "Замена привилегии сервиса",
|
|
||||||
tags: ["privilege"],
|
|
||||||
body: privilegeBody,
|
|
||||||
response: replacePrivilegeResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const replacePrivilegesSchema: SwaggerSchema = {
|
|
||||||
summary: "Замена привилегий сервиса",
|
|
||||||
tags: ["privilege"],
|
|
||||||
body: registerPrivilegesBody,
|
|
||||||
response: replacePrivilegesResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removePrivilegeSchema: SwaggerSchema = {
|
|
||||||
summary: "Удаление привелегии",
|
|
||||||
tags: ["privilege"],
|
|
||||||
body: getPrivilegeParams,
|
|
||||||
response: removePrivilegeResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const restorePrivilegeSchema: SwaggerSchema = {
|
|
||||||
summary: "Восстановление привилегии",
|
|
||||||
tags: ["privilege"],
|
|
||||||
body: getPrivilegeParams,
|
|
||||||
response: removePrivilegeResponse,
|
|
||||||
};
|
|
@ -1,64 +0,0 @@
|
|||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const privilegeBody: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["name", "privilegeId", "serviceKey", "description", "type", "value", "amount"],
|
|
||||||
properties: {
|
|
||||||
name: { type: "string" },
|
|
||||||
privilegeId: { type: "string" },
|
|
||||||
serviceKey: { type: "string" },
|
|
||||||
description: { type: "string" },
|
|
||||||
type: { type: "string" },
|
|
||||||
value: { type: "string" },
|
|
||||||
price: { type: "number" },
|
|
||||||
amount: { type: "number" },
|
|
||||||
},
|
|
||||||
examples: [
|
|
||||||
{
|
|
||||||
name: "Количество попыток использования",
|
|
||||||
privilegeId: "507f1f77bcf86cd799439011",
|
|
||||||
serviceKey: "docx-templater-service",
|
|
||||||
description: "Количество попыток использования",
|
|
||||||
type: "count",
|
|
||||||
value: "200",
|
|
||||||
price: 12300,
|
|
||||||
amount: 300,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const privilegesBody: SwaggerMessage = {
|
|
||||||
type: "array",
|
|
||||||
items: privilegeBody,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerPrivilegesBody: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
privileges: privilegesBody,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPrivilegeParams: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["privilegeId"],
|
|
||||||
properties: {
|
|
||||||
privilegeId: {
|
|
||||||
type: "string",
|
|
||||||
description: "ID привилегии (privilegeId)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
examples: [{ privilegeId: "507f1f77bcf86cd799439011" }],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getServicePrivilegesParams: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["serviceKey"],
|
|
||||||
properties: {
|
|
||||||
serviceKey: {
|
|
||||||
type: "string",
|
|
||||||
description: "Ключ сервиса",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
examples: [{ serviceKey: "docx-templater-service" }],
|
|
||||||
};
|
|
@ -1,47 +0,0 @@
|
|||||||
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" },
|
|
||||||
amount: { 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,
|
|
||||||
};
|
|
@ -1,95 +0,0 @@
|
|||||||
import { swaggerError } from "@/utils/swagger-error";
|
|
||||||
|
|
||||||
import { privilege } from "./models";
|
|
||||||
|
|
||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const getAllPrivilegesReponse: Record<string, SwaggerMessage> = {
|
|
||||||
200: {
|
|
||||||
type: "array",
|
|
||||||
description: "Привилегии",
|
|
||||||
items: privilege,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAllPrivilegesMapReponse: 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 getPrivilegesReponse: 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 registerPrivilegesResponse: 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 replacePrivilegesResponse: 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"),
|
|
||||||
};
|
|
@ -1,71 +0,0 @@
|
|||||||
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,
|
|
||||||
};
|
|
@ -1,58 +0,0 @@
|
|||||||
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" }],
|
|
||||||
};
|
|
@ -1,32 +0,0 @@
|
|||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
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"),
|
|
||||||
};
|
|
@ -1,67 +0,0 @@
|
|||||||
import { getTariffParams, tariffBody, replaceTariffParams, getTariffsQuerystring } 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"],
|
|
||||||
querystring: getTariffsQuerystring,
|
|
||||||
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,
|
|
||||||
};
|
|
@ -1,86 +0,0 @@
|
|||||||
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 getTariffsQuerystring: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
page: {
|
|
||||||
type: "number",
|
|
||||||
description: "номер страницы",
|
|
||||||
},
|
|
||||||
limit: {
|
|
||||||
type: "number",
|
|
||||||
description: "Лимит количества аккаунтов (больше 100 не обрабатывается)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tariffBody: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
description: "Тариф",
|
|
||||||
required: ["name", "isCustom", "privileges"],
|
|
||||||
properties: {
|
|
||||||
name: { type: "string" },
|
|
||||||
price: { type: "number" },
|
|
||||||
isCustom: { type: "boolean" },
|
|
||||||
privileges: {
|
|
||||||
type: "array",
|
|
||||||
items: {
|
|
||||||
type: "object",
|
|
||||||
description: "Привилегия",
|
|
||||||
properties: {
|
|
||||||
name: { type: "string" },
|
|
||||||
privilegeId: { type: "string" },
|
|
||||||
serviceKey: { type: "string" },
|
|
||||||
description: { type: "string" },
|
|
||||||
amount: { type: "number" },
|
|
||||||
type: { type: "string" },
|
|
||||||
value: { type: "string" },
|
|
||||||
price: { type: "number" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
examples: [
|
|
||||||
{
|
|
||||||
name: "Использование сервисов",
|
|
||||||
price: 14000,
|
|
||||||
isCustom: false,
|
|
||||||
privileges: [
|
|
||||||
{
|
|
||||||
name: "Количество попыток использования",
|
|
||||||
privilegeId: "507f1f77bcf86cd799439011",
|
|
||||||
serviceKey: "docx-templater-service",
|
|
||||||
description: "Количество попыток использования",
|
|
||||||
type: "count",
|
|
||||||
value: "200",
|
|
||||||
price: 12300,
|
|
||||||
amount: 300,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const replaceTariffParams: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
required: ["id"],
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: "string",
|
|
||||||
description: "ID тарифа",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
examples: [{ id: "63a7d47ba24613f98562bafa" }],
|
|
||||||
};
|
|
@ -1,148 +0,0 @@
|
|||||||
import type { SwaggerMessage } from "@/types/swagger.type";
|
|
||||||
|
|
||||||
export const tariff: SwaggerMessage = {
|
|
||||||
type: "object",
|
|
||||||
description: "Тариф",
|
|
||||||
properties: {
|
|
||||||
_id: { type: "string" },
|
|
||||||
name: { type: "string" },
|
|
||||||
description: { type: "string" },
|
|
||||||
price: { type: "number" },
|
|
||||||
order: { type: "number" },
|
|
||||||
isCustom: { type: "boolean" },
|
|
||||||
privileges: {
|
|
||||||
type: "array",
|
|
||||||
items: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
name: { type: "string" },
|
|
||||||
privilegeId: { type: "string" },
|
|
||||||
serviceKey: { type: "string" },
|
|
||||||
description: { type: "string" },
|
|
||||||
type: { type: "string" },
|
|
||||||
value: { type: "string" },
|
|
||||||
price: { type: "number" },
|
|
||||||
amount: { type: "number" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
privileges: [
|
|
||||||
{
|
|
||||||
name: "name",
|
|
||||||
privilegeId: "507f1f77bcf86cd799439011",
|
|
||||||
serviceKey: "docx-templater-service",
|
|
||||||
description: "Количество попыток использования",
|
|
||||||
type: "count",
|
|
||||||
value: "200",
|
|
||||||
price: 12300,
|
|
||||||
amount: 300,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
isDeleted: false,
|
|
||||||
createdAt: "2017-07-21T17:32:28Z",
|
|
||||||
updatedAt: "2017-07-21T17:32:28Z",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "user",
|
|
||||||
price: 14000,
|
|
||||||
isCustom: false,
|
|
||||||
privileges: [
|
|
||||||
{
|
|
||||||
name: "507f1f77bcf86cd799439011",
|
|
||||||
privilegeId: "507f1f77bcf86cd799439011",
|
|
||||||
serviceKey: "docx-templater-service",
|
|
||||||
description: "Количество попыток использования",
|
|
||||||
type: "count",
|
|
||||||
value: "200",
|
|
||||||
price: 12300,
|
|
||||||
amount: 100,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
isDeleted: true,
|
|
||||||
createdAt: "2017-07-21T17:32:28Z",
|
|
||||||
updatedAt: "2019-04-14T15:32:15Z",
|
|
||||||
deletedAt: "2021-08-17T13:23:44Z",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tariffs: SwaggerMessage = {
|
|
||||||
description: "Список тарифов",
|
|
||||||
type: "object",
|
|
||||||
required: ["tariffs", "totalPages"],
|
|
||||||
properties: {
|
|
||||||
tariffs: {
|
|
||||||
type: "array",
|
|
||||||
description: "Массив тарифов",
|
|
||||||
items: tariff,
|
|
||||||
},
|
|
||||||
totalPages: { type: "number" },
|
|
||||||
},
|
|
||||||
examples: [
|
|
||||||
{
|
|
||||||
totalPages: 10,
|
|
||||||
tariffs: [
|
|
||||||
{
|
|
||||||
name: "Использование сервисов",
|
|
||||||
price: 14000,
|
|
||||||
isCustom: false,
|
|
||||||
privileges: [
|
|
||||||
{
|
|
||||||
name: "name",
|
|
||||||
privilegeId: "507f1f77bcf86cd799439011",
|
|
||||||
serviceKey: "docx-templater-service",
|
|
||||||
description: "Количество попыток использования",
|
|
||||||
type: "count",
|
|
||||||
value: "200",
|
|
||||||
price: 12300,
|
|
||||||
amount: 300,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
isDeleted: false,
|
|
||||||
createdAt: "2017-07-21T17:32:28Z",
|
|
||||||
updatedAt: "2017-07-21T17:32:28Z",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "user",
|
|
||||||
price: 14000,
|
|
||||||
isCustom: false,
|
|
||||||
privileges: [
|
|
||||||
{
|
|
||||||
name: "507f1f77bcf86cd799439011",
|
|
||||||
privilegeId: "507f1f77bcf86cd799439011",
|
|
||||||
serviceKey: "docx-templater-service",
|
|
||||||
description: "Количество попыток использования",
|
|
||||||
type: "count",
|
|
||||||
value: "200",
|
|
||||||
price: 12300,
|
|
||||||
amount: 100,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
isDeleted: true,
|
|
||||||
createdAt: "2017-07-21T17:32:28Z",
|
|
||||||
updatedAt: "2019-04-14T15:32:15Z",
|
|
||||||
deletedAt: "2021-08-17T13:23:44Z",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@ -1,36 +0,0 @@
|
|||||||
import { swaggerError } from "@/utils/swagger-error";
|
|
||||||
|
|
||||||
import { tariff, tariffs } 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: tariffs,
|
|
||||||
};
|
|
||||||
|
|
||||||
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"),
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
export type DatabaseOptions = {
|
|
||||||
host: string;
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
port: number;
|
|
||||||
database?: string;
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
import type { FastifyCookieOptions } from "@fastify/cookie";
|
|
||||||
import type { FastifyJWTOptions } from "@fastify/jwt";
|
|
||||||
|
|
||||||
export type PluginsOptions = {
|
|
||||||
cookie?: FastifyCookieOptions;
|
|
||||||
jwt?: FastifyJWTOptions;
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export type Environment = "development" | "staging" | "production";
|
|
8
src/types/fastify-jwt.d.ts
vendored
8
src/types/fastify-jwt.d.ts
vendored
@ -1,8 +0,0 @@
|
|||||||
import "@fastify/jwt";
|
|
||||||
|
|
||||||
declare module "@fastify/jwt" {
|
|
||||||
interface FastifyJWT {
|
|
||||||
payload: { id: string };
|
|
||||||
user: { id: string };
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
export type PaginationParams = {
|
|
||||||
page?: number;
|
|
||||||
limit?: number;
|
|
||||||
};
|
|
@ -1,4 +0,0 @@
|
|||||||
import type { Eloquent } from "../models/eloquent.type";
|
|
||||||
import type { Tariff } from "../models/tariff.type";
|
|
||||||
|
|
||||||
export type TariffMessage = Partial<Omit<Tariff, keyof Eloquent | "userId">>;
|
|
@ -1,8 +0,0 @@
|
|||||||
import type { Eloquent } from "./eloquent.type";
|
|
||||||
|
|
||||||
export type Account = Eloquent & {
|
|
||||||
userId: string;
|
|
||||||
nickname: string;
|
|
||||||
avatar: string;
|
|
||||||
role: string;
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
export type Eloquent = {
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
deletedAt?: Date;
|
|
||||||
isDeleted: boolean;
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
import type { Eloquent } from "./eloquent.type";
|
|
||||||
|
|
||||||
export type Permission = Eloquent & {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
import type { Eloquent } from "./eloquent.type";
|
|
||||||
|
|
||||||
export type Privilege = Eloquent & {
|
|
||||||
name: string;
|
|
||||||
privilegeId: string;
|
|
||||||
serviceKey: string;
|
|
||||||
description: string;
|
|
||||||
amount: number;
|
|
||||||
type: "count" | "day" | "full";
|
|
||||||
value: string;
|
|
||||||
price: number;
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
import type { Eloquent } from "./eloquent.type";
|
|
||||||
|
|
||||||
export type Role = Eloquent & {
|
|
||||||
name: string;
|
|
||||||
permissions: Record<string, boolean>;
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
import type { Privilege } from "./privilege.type";
|
|
||||||
import type { Eloquent } from "./eloquent.type";
|
|
||||||
|
|
||||||
export type Tariff = Eloquent & {
|
|
||||||
name: string;
|
|
||||||
userId: string;
|
|
||||||
description: string;
|
|
||||||
price?: number;
|
|
||||||
order?: number;
|
|
||||||
isCustom: boolean;
|
|
||||||
privileges: Array<Omit<Privilege, keyof Eloquent>>;
|
|
||||||
};
|
|
@ -1,8 +0,0 @@
|
|||||||
import type { Eloquent } from "./eloquent.type";
|
|
||||||
|
|
||||||
export type User = Eloquent & {
|
|
||||||
_id: string;
|
|
||||||
login: string;
|
|
||||||
email: string;
|
|
||||||
phoneNumber: string;
|
|
||||||
};
|
|
@ -1,3 +0,0 @@
|
|||||||
export type ObjectWithPossibleFields<KeyValue extends Record<string, unknown>> = {
|
|
||||||
[Key in keyof KeyValue]?: KeyValue[Key];
|
|
||||||
};
|
|
@ -1,3 +0,0 @@
|
|||||||
export type ObjectWithRequiredFields<KeyValue extends Record<string, unknown>> = {
|
|
||||||
[Key in keyof KeyValue]-?: KeyValue[Key];
|
|
||||||
};
|
|
@ -1,50 +0,0 @@
|
|||||||
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>;
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
export const convertArrayToRecord = <Array extends string[], Value>(
|
|
||||||
array: Array,
|
|
||||||
defaultValue: Value
|
|
||||||
): Record<string, Value> =>
|
|
||||||
array.reduce<Record<string, Value>>((accamulator, value) => ({ ...accamulator, [value]: defaultValue }), {});
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user