diff --git a/.github/workflows/cd-vesst-discord-bot-backend-aws-ecs.yaml b/.github/workflows/cd-vesst-discord-bot-backend-aws-ecs.yaml
new file mode 100644
index 0000000..675ccc6
--- /dev/null
+++ b/.github/workflows/cd-vesst-discord-bot-backend-aws-ecs.yaml
@@ -0,0 +1,69 @@
+# Introduction:
+#
+# This workflow is responsible for both creating and pushing the container image of the generated service to
+# Amazon Elastic Container Registry (ECR), aswell as rendering and deploying an task definition to an Amazon
+# Elastic Container Service (ECS) cluster. Lastly the execution of a task definition requires as IAM role which
+# can be consumed.
+
+name: vesst-discord-bot-backend-deploy-to-aws-ecs
+concurrency: ${{ github.ref }}
+
+on:
+ workflow_dispatch: {}
+ pull_request:
+ types: [closed]
+
+env:
+ AWS_REGION: eu-west-1
+ ECR_REPOSITORY: repository-name
+ ECS_SERVICE: vesst-discord-bot-backend
+ ECS_CLUSTER: development-cluster
+ ECS_TASK_DEFINITION: .github/workflows/configuration/cd-vesst-discord-bot-backend-aws-ecs.json
+ CONTAINER_NAME: vesst-discord-bot-backend
+
+jobs:
+ package:
+ name: deploy
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+
+ - name: configure aws credentials
+ uses: aws-actions/configure-aws-credentials@v4
+ with:
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ aws-region: ${{ env.AWS_REGION }}
+
+ - name: login to amazon ecr
+ id: registry
+ uses: aws-actions/amazon-ecr-login@v2
+
+ - name: build, tag and push image
+ id: image
+ env:
+ ECR_REGISTRY: ${{ steps.registry.outputs.registry }}
+ IMAGE_TAG: ${{github.sha}}
+ run: |
+ docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG apps/vesst-discord-bot-backend-server
+ docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
+ echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
+
+ # https://github.com/aws-actions/amazon-ecs-render-task-definition
+ - name: render amazon ecs task definition
+ id: task-definition
+ uses: aws-actions/amazon-ecs-render-task-definition@v1
+ with:
+ task-definition: ${{ env.ECS_TASK_DEFINITION }}
+ container-name: ${{ env.CONTAINER_NAME }}
+ image: ${{ steps.image.outputs.image }}
+
+ # https://github.com/aws-actions/amazon-ecs-deploy-task-definition
+ - name: deploy amazon ecs task definition
+ uses: aws-actions/amazon-ecs-deploy-task-definition@v1
+ with:
+ task-definition: ${{ steps.task-definition.outputs.task-definition }}
+ service: ${{ env.ECS_SERVICE }}
+ cluster: ${{ env.ECS_CLUSTER }}
+ wait-for-service-stability: false
diff --git a/.github/workflows/ci-vesst-discord-bot-backend.yaml b/.github/workflows/ci-vesst-discord-bot-backend.yaml
new file mode 100644
index 0000000..94f4504
--- /dev/null
+++ b/.github/workflows/ci-vesst-discord-bot-backend.yaml
@@ -0,0 +1,36 @@
+name: continuous integration - vesst-discord-bot-backend
+
+concurrency:
+ group: vesst-discord-bot-backend
+ cancel-in-progress: true
+
+on:
+ workflow_dispatch:
+ push:
+ branches: ["*"]
+ paths: ["apps/vesst-discord-bot-backend-server"]
+
+jobs:
+ continuous-integration:
+ name: continuous integration
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v3
+
+ - name: setup node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18.x
+
+ - name: install dependencies
+ run: npm install
+ working-directory: apps/vesst-discord-bot-backend-server
+
+ - name: build
+ run: npm run build
+ working-directory: apps/vesst-discord-bot-backend-server
+
+ - name: test
+ run: npm test
+ working-directory: apps/vesst-discord-bot-backend-server
diff --git a/.github/workflows/configuration/cd-vesst-discord-bot-backend-aws-ecs.json b/.github/workflows/configuration/cd-vesst-discord-bot-backend-aws-ecs.json
new file mode 100644
index 0000000..b61fb18
--- /dev/null
+++ b/.github/workflows/configuration/cd-vesst-discord-bot-backend-aws-ecs.json
@@ -0,0 +1,58 @@
+{
+ "family": "vesst-discord-bot-backend",
+ "containerDefinitions": [
+ {
+ "name": "vesst-discord-bot-backend",
+ "image": "012345678901.dkr.ecr.eu-west-1.amazonaws.com/repository-name:latest",
+ "essential": true,
+ "portMappings": [
+ {
+ "name": "vesst-discord-bot-backend-3000-tcp",
+ "containerPort": 3000,
+ "hostPort": 3000,
+ "protocol": "tcp"
+ }
+ ],
+ "secrets": [
+ {
+ "name": "BCRYPT_SALT",
+ "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:BCRYPT_SALT::"
+ },
+ {
+ "name": "JWT_EXPIRATION",
+ "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:JWT_EXPIRATION::"
+ },
+ {
+ "name": "JWT_SECRET_KEY",
+ "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:JWT_SECRET_KEY::"
+ },
+ {
+ "name": "DB_URL",
+ "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:DB_URL::"
+ }
+ ],
+ "logConfiguration": {
+ "logDriver": "awslogs",
+ "options": {
+ "awslogs-create-group": "true",
+ "awslogs-group": "/ecs/vesst-discord-bot-backend",
+ "awslogs-region": "eu-west-1",
+ "awslogs-stream-prefix": "ecs"
+ }
+ },
+ "mountPoints": [],
+ "volumesFrom": []
+ }
+ ],
+ "executionRoleArn": "arn:aws:iam::012345678901:role/task-execution-role-name",
+ "networkMode": "awsvpc",
+ "requiresCompatibilities": [
+ "FARGATE"
+ ],
+ "cpu": "1024",
+ "memory": "2048",
+ "runtimePlatform": {
+ "cpuArchitecture": "X86_64",
+ "operatingSystemFamily": "LINUX"
+ }
+}
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-admin/.dockerignore b/apps/vesst-discord-bot-backend-admin/.dockerignore
new file mode 100644
index 0000000..1194b4f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/.dockerignore
@@ -0,0 +1,7 @@
+.dockerignore
+docker-compose.yml
+Dockerfile
+build/
+node_modules
+.env
+.gitignore
diff --git a/apps/vesst-discord-bot-backend-admin/.env b/apps/vesst-discord-bot-backend-admin/.env
new file mode 100644
index 0000000..4eef91c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/.env
@@ -0,0 +1,2 @@
+PORT=3001
+REACT_APP_SERVER_URL=http://localhost:3000
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-admin/.gitignore b/apps/vesst-discord-bot-backend-admin/.gitignore
new file mode 100644
index 0000000..590b2e0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/.gitignore
@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/apps/vesst-discord-bot-backend-admin/Dockerfile b/apps/vesst-discord-bot-backend-admin/Dockerfile
new file mode 100644
index 0000000..0911e21
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/Dockerfile
@@ -0,0 +1,51 @@
+# multi-stage: base (build)
+FROM node:18.13.0-slim AS base
+
+# instantiate environment variable
+ARG REACT_APP_SERVER_URL=http://localhost:3000
+
+# set the environment variable that points to the server
+ENV REACT_APP_SERVER_URL=$REACT_APP_SERVER_URL
+
+# create directory where the application will be built
+WORKDIR /app
+
+# copy over the dependency manifests, both the package.json
+# and the package-lock.json are copied over
+COPY package*.json ./
+
+# installs packages and their dependencies
+RUN npm install
+
+# copy over the code base
+COPY . .
+
+# create the bundle of the application
+RUN npm run build
+
+# multi-stage: production (runtime)
+FROM nginx:1.22-alpine AS production
+
+# copy over the bundled code from the build stage
+COPY --from=base /app/build /usr/share/nginx/html
+COPY --from=base /app/configuration/nginx.conf /etc/nginx/conf.d/default.conf
+
+# create a new process indication file
+RUN touch /var/run/nginx.pid
+
+# change ownership of nginx related directories and files
+RUN chown -R nginx:nginx /var/run/nginx.pid \
+ /usr/share/nginx/html \
+ /var/cache/nginx \
+ /var/log/nginx \
+ /etc/nginx/conf.d
+
+# set user to the created non-privileged user
+USER nginx
+
+# expose a specific port on the docker container
+ENV PORT=3001
+EXPOSE ${PORT}
+
+# start the server using the previously build application
+ENTRYPOINT [ "nginx", "-g", "daemon off;" ]
diff --git a/apps/vesst-discord-bot-backend-admin/README.md b/apps/vesst-discord-bot-backend-admin/README.md
new file mode 100644
index 0000000..cc7c387
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/README.md
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+# Introduction
+
+This service was generated with Amplication. It serves as the client-side for the generated server component. The client-side consist of a React application with ready-made forms for creating and editing the different data models of the application. It is pre-conffigured to work with the server and comes with the boilerplate and foundation for the client - i.e., routing, navigation, authentication, permissions, menu, breadcrumbs, error handling and much more. Additional information about the admin component and the architecture around it, can be found on the [documentation](https://docs.amplication.com/guides/getting-started) site. This side of the generated project was bootstrapped with [create-react-app](https://github.com/facebook/create-react-app) and built with [react-admin](https://marmelab.com/react-admin/).
+
+
+
+
+
+
+# Getting started
+
+## Step 1: Configuration
+
+Configuration for the client component can be provided through the use of environment variables. These can be passed to the application via the use of the `.env` file in the base directory of the generated service. Below a table can be found which show the different variables that can be passed. These values are provided default values after generation, change them to the desired values.
+
+| Variable | Description | Value |
+| -------------------- | ------------------------------------------------ | ------------------------------ |
+| PORT | the port on which to run the client | 3001 |
+| REACT_APP_SERVER_URL | the url on which the server component is running | http://localhost:[server-port] |
+
+> **Note**
+> Amplication generates default values and stores them under the .env file. It is advised to use some form of secrets manager/vault solution when using in production.
+
+
+## Step 2: Scripts
+
+After configuration of the client the next step would be to run the application. Before running the client side of the component, make sure that the different pre-requisites are met - i.e., npm, docker. Make sure that the server-side of the application is running.
+
+```sh
+# installation of the dependencies
+$ npm install
+
+# starts the application in development mode - available by default under http://localhost:3001 with a pre-configured user with the username "admin" and password "admin"
+$ npm run start
+
+# builds the application in production mode - available under 'build'
+$ npm run build
+
+# removes the single build dependency from the project
+$ npm run eject
+```
diff --git a/apps/vesst-discord-bot-backend-admin/configuration/nginx.conf b/apps/vesst-discord-bot-backend-admin/configuration/nginx.conf
new file mode 100644
index 0000000..c907b5c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/configuration/nginx.conf
@@ -0,0 +1,11 @@
+server_tokens off;
+
+server {
+ listen 3001;
+ server_name localhost;
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ try_files $uri /index.html;
+ }
+}
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-admin/package.json b/apps/vesst-discord-bot-backend-admin/package.json
new file mode 100644
index 0000000..463bf2d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/package.json
@@ -0,0 +1,60 @@
+{
+ "name": "@vesst-discord-bot-backend/admin",
+ "private": true,
+ "dependencies": {
+ "@apollo/client": "3.6.9",
+ "@material-ui/core": "4.12.4",
+ "graphql": "15.6.1",
+ "lodash": "4.17.21",
+ "pluralize": "8.0.0",
+ "ra-data-graphql-amplication": "0.0.14",
+ "react": "16.14.0",
+ "react-admin": "3.19.12",
+ "react-dom": "16.14.0",
+ "react-scripts": "5.0.0",
+ "sass": "^1.39.0",
+ "web-vitals": "1.1.2"
+ },
+ "overrides": {
+ "react-scripts": {
+ "@svgr/webpack": "6.5.1"
+ }
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject",
+ "package:container": "docker build ."
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@testing-library/jest-dom": "5.14.1",
+ "@testing-library/react": "11.2.7",
+ "@testing-library/user-event": "13.2.0",
+ "@types/jest": "26.0.16",
+ "@types/lodash": "4.14.178",
+ "@types/node": "12.20.16",
+ "@types/react": "16.14.11",
+ "@types/react-dom": "17.0.0",
+ "type-fest": "0.13.1",
+ "typescript": "4.3.5"
+ }
+}
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-admin/public/favicon.ico b/apps/vesst-discord-bot-backend-admin/public/favicon.ico
new file mode 100644
index 0000000..fcbdcf2
Binary files /dev/null and b/apps/vesst-discord-bot-backend-admin/public/favicon.ico differ
diff --git a/apps/vesst-discord-bot-backend-admin/public/index.html b/apps/vesst-discord-bot-backend-admin/public/index.html
new file mode 100644
index 0000000..72ad502
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/public/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ VESSTDiscordBotBackend
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
diff --git a/apps/vesst-discord-bot-backend-admin/public/logo192.png b/apps/vesst-discord-bot-backend-admin/public/logo192.png
new file mode 100644
index 0000000..1918ff2
Binary files /dev/null and b/apps/vesst-discord-bot-backend-admin/public/logo192.png differ
diff --git a/apps/vesst-discord-bot-backend-admin/public/logo512.png b/apps/vesst-discord-bot-backend-admin/public/logo512.png
new file mode 100644
index 0000000..7e7dc74
Binary files /dev/null and b/apps/vesst-discord-bot-backend-admin/public/logo512.png differ
diff --git a/apps/vesst-discord-bot-backend-admin/public/manifest.json b/apps/vesst-discord-bot-backend-admin/public/manifest.json
new file mode 100644
index 0000000..b65b890
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "VESSTDiscordBotBackend",
+ "name": "VESSTDiscordBotBackend",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-admin/public/robots.txt b/apps/vesst-discord-bot-backend-admin/public/robots.txt
new file mode 100644
index 0000000..e9e57dc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/apps/vesst-discord-bot-backend-admin/src/App.scss b/apps/vesst-discord-bot-backend-admin/src/App.scss
new file mode 100644
index 0000000..4c1cbb0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/App.scss
@@ -0,0 +1,59 @@
+// .App {
+// .MuiAppBar-colorSecondary {
+// background-color: black;
+
+// .RaAppBar-menuButton-13 {
+// background-color: yellow;
+// }
+// }
+
+// .MuiDrawer-paper {
+// background-color: red;
+
+// .MuiListItemIcon-root {
+// color: white;
+// }
+// }
+
+// .MuiButton-textPrimary {
+// background-color: purple;
+// margin: 0 0.5rem;
+// color: white;
+// padding: 0.5rem 1rem;
+
+// &:hover {
+// background-color: blue;
+// }
+// }
+
+// .MuiTableRow-head {
+// .MuiTableCell-head {
+// background-color: black;
+// color: white;
+// }
+
+// .MuiTableSortLabel-root {
+// &:hover {
+// color: red;
+
+// .MuiTableSortLabel-icon {
+// color: red !important;
+// }
+// }
+// .MuiTableSortLabel-icon {
+// color: white !important;
+// }
+// }
+// .MuiTableSortLabel-active {
+// color: green;
+
+// .MuiTableSortLabel-icon {
+// color: green !important;
+// }
+// }
+// }
+
+// .MuiFormLabel-root {
+// color: magenta;
+// }
+// }
diff --git a/apps/vesst-discord-bot-backend-admin/src/App.tsx b/apps/vesst-discord-bot-backend-admin/src/App.tsx
new file mode 100644
index 0000000..e3bd2f2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/App.tsx
@@ -0,0 +1,116 @@
+import React, { useEffect, useState } from "react";
+import { Admin, DataProvider, Resource } from "react-admin";
+import buildGraphQLProvider from "./data-provider/graphqlDataProvider";
+import { theme } from "./theme/theme";
+import Login from "./Login";
+import "./App.scss";
+import Dashboard from "./pages/Dashboard";
+import { SlotList } from "./slot/SlotList";
+import { SlotCreate } from "./slot/SlotCreate";
+import { SlotEdit } from "./slot/SlotEdit";
+import { SlotShow } from "./slot/SlotShow";
+import { VouchList } from "./vouch/VouchList";
+import { VouchCreate } from "./vouch/VouchCreate";
+import { VouchEdit } from "./vouch/VouchEdit";
+import { VouchShow } from "./vouch/VouchShow";
+import { EmbedList } from "./embed/EmbedList";
+import { EmbedCreate } from "./embed/EmbedCreate";
+import { EmbedEdit } from "./embed/EmbedEdit";
+import { EmbedShow } from "./embed/EmbedShow";
+import { TicketList } from "./ticket/TicketList";
+import { TicketCreate } from "./ticket/TicketCreate";
+import { TicketEdit } from "./ticket/TicketEdit";
+import { TicketShow } from "./ticket/TicketShow";
+import { SecurityList } from "./security/SecurityList";
+import { SecurityCreate } from "./security/SecurityCreate";
+import { SecurityEdit } from "./security/SecurityEdit";
+import { SecurityShow } from "./security/SecurityShow";
+import { EntertainmentList } from "./entertainment/EntertainmentList";
+import { EntertainmentCreate } from "./entertainment/EntertainmentCreate";
+import { EntertainmentEdit } from "./entertainment/EntertainmentEdit";
+import { EntertainmentShow } from "./entertainment/EntertainmentShow";
+import { UserList } from "./user/UserList";
+import { UserCreate } from "./user/UserCreate";
+import { UserEdit } from "./user/UserEdit";
+import { UserShow } from "./user/UserShow";
+import { jwtAuthProvider } from "./auth-provider/ra-auth-jwt";
+
+const App = (): React.ReactElement => {
+ const [dataProvider, setDataProvider] = useState(null);
+ useEffect(() => {
+ buildGraphQLProvider
+ .then((provider: any) => {
+ setDataProvider(() => provider);
+ })
+ .catch((error: any) => {
+ console.log(error);
+ });
+ }, []);
+ if (!dataProvider) {
+ return Loading
;
+ }
+ return (
+
+ );
+};
+
+export default App;
diff --git a/apps/vesst-discord-bot-backend-admin/src/Components/Pagination.tsx b/apps/vesst-discord-bot-backend-admin/src/Components/Pagination.tsx
new file mode 100644
index 0000000..2de2ebf
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/Components/Pagination.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import { Pagination as RAPagination, PaginationProps } from "react-admin";
+
+const PAGINATION_OPTIONS = [10, 25, 50, 100, 200];
+
+const Pagination = (props: PaginationProps) => (
+
+);
+
+export default Pagination;
diff --git a/apps/vesst-discord-bot-backend-admin/src/Login.tsx b/apps/vesst-discord-bot-backend-admin/src/Login.tsx
new file mode 100644
index 0000000..f7ec8ed
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/Login.tsx
@@ -0,0 +1,117 @@
+import * as React from "react";
+import { useState } from "react";
+import { useLogin, useNotify, Notification, defaultTheme } from "react-admin";
+import { ThemeProvider } from "@material-ui/styles";
+import { createTheme } from "@material-ui/core/styles";
+import { Button } from "@material-ui/core";
+import "./login.scss";
+
+const CLASS_NAME = "login-page";
+
+const Login = ({ theme }: any) => {
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState("");
+ const login = useLogin();
+ const notify = useNotify();
+ const BASE_URI = process.env.REACT_APP_SERVER_URL;
+ const submit = (e: any) => {
+ e.preventDefault();
+ login({ username, password }).catch(() =>
+ notify("Invalid username or password")
+ );
+ };
+
+ return (
+
+
+
+
+
+
Connect via GraphQL
+
+ Connect to the server using GraphQL API with a complete and
+ understandable description of the data in your API
+
+
+ Continue
+
+
+
+
+
Admin UI
+
+ Sign in to a React-Admin client with ready-made forms for creating
+ and editing all the data models of your application
+
+
+
+
+
+
Connect via REST API
+
+ Connect to the server using REST API with a built-in Swagger
+ documentation
+
+
+ Continue
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Login;
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/CreateEmbedArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/CreateEmbedArgs.ts
new file mode 100644
index 0000000..1907ecb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/CreateEmbedArgs.ts
@@ -0,0 +1,5 @@
+import { EmbedCreateInput } from "./EmbedCreateInput";
+
+export type CreateEmbedArgs = {
+ data: EmbedCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/DeleteEmbedArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/DeleteEmbedArgs.ts
new file mode 100644
index 0000000..e9d3f20
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/DeleteEmbedArgs.ts
@@ -0,0 +1,5 @@
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+
+export type DeleteEmbedArgs = {
+ where: EmbedWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/Embed.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/Embed.ts
new file mode 100644
index 0000000..0199884
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/Embed.ts
@@ -0,0 +1,10 @@
+export type Embed = {
+ color: string | null;
+ createdAt: Date;
+ dateCreated: Date | null;
+ description: string | null;
+ footer: string | null;
+ id: string;
+ title: string | null;
+ updatedAt: Date;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedCountArgs.ts
new file mode 100644
index 0000000..394609c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedCountArgs.ts
@@ -0,0 +1,5 @@
+import { EmbedWhereInput } from "./EmbedWhereInput";
+
+export type EmbedCountArgs = {
+ where?: EmbedWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedCreateInput.ts
new file mode 100644
index 0000000..817db45
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedCreateInput.ts
@@ -0,0 +1,7 @@
+export type EmbedCreateInput = {
+ color?: string | null;
+ dateCreated?: Date | null;
+ description?: string | null;
+ footer?: string | null;
+ title?: string | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedFindManyArgs.ts
new file mode 100644
index 0000000..fe28032
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { EmbedWhereInput } from "./EmbedWhereInput";
+import { EmbedOrderByInput } from "./EmbedOrderByInput";
+
+export type EmbedFindManyArgs = {
+ where?: EmbedWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedFindUniqueArgs.ts
new file mode 100644
index 0000000..1af047b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+
+export type EmbedFindUniqueArgs = {
+ where: EmbedWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedListRelationFilter.ts
new file mode 100644
index 0000000..0f88698
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { EmbedWhereInput } from "./EmbedWhereInput";
+
+export type EmbedListRelationFilter = {
+ every?: EmbedWhereInput;
+ some?: EmbedWhereInput;
+ none?: EmbedWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedOrderByInput.ts
new file mode 100644
index 0000000..9504097
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedOrderByInput.ts
@@ -0,0 +1,12 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type EmbedOrderByInput = {
+ color?: SortOrder;
+ createdAt?: SortOrder;
+ dateCreated?: SortOrder;
+ description?: SortOrder;
+ footer?: SortOrder;
+ id?: SortOrder;
+ title?: SortOrder;
+ updatedAt?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedUpdateInput.ts
new file mode 100644
index 0000000..e46d1c1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedUpdateInput.ts
@@ -0,0 +1,7 @@
+export type EmbedUpdateInput = {
+ color?: string | null;
+ dateCreated?: Date | null;
+ description?: string | null;
+ footer?: string | null;
+ title?: string | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedWhereInput.ts
new file mode 100644
index 0000000..753781e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedWhereInput.ts
@@ -0,0 +1,12 @@
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+
+export type EmbedWhereInput = {
+ color?: StringNullableFilter;
+ dateCreated?: DateTimeNullableFilter;
+ description?: StringNullableFilter;
+ footer?: StringNullableFilter;
+ id?: StringFilter;
+ title?: StringNullableFilter;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedWhereUniqueInput.ts
new file mode 100644
index 0000000..1995e5b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/EmbedWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type EmbedWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/embed/UpdateEmbedArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/embed/UpdateEmbedArgs.ts
new file mode 100644
index 0000000..1e9119c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/embed/UpdateEmbedArgs.ts
@@ -0,0 +1,7 @@
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+import { EmbedUpdateInput } from "./EmbedUpdateInput";
+
+export type UpdateEmbedArgs = {
+ where: EmbedWhereUniqueInput;
+ data: EmbedUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/CreateEntertainmentArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/CreateEntertainmentArgs.ts
new file mode 100644
index 0000000..009ad43
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/CreateEntertainmentArgs.ts
@@ -0,0 +1,5 @@
+import { EntertainmentCreateInput } from "./EntertainmentCreateInput";
+
+export type CreateEntertainmentArgs = {
+ data: EntertainmentCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/DeleteEntertainmentArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/DeleteEntertainmentArgs.ts
new file mode 100644
index 0000000..cbb9315
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/DeleteEntertainmentArgs.ts
@@ -0,0 +1,5 @@
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+
+export type DeleteEntertainmentArgs = {
+ where: EntertainmentWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/Entertainment.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/Entertainment.ts
new file mode 100644
index 0000000..c40f7a6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/Entertainment.ts
@@ -0,0 +1,10 @@
+import { JsonValue } from "type-fest";
+
+export type Entertainment = {
+ createdAt: Date;
+ details: JsonValue;
+ id: string;
+ name: string | null;
+ typeField?: "Option1" | null;
+ updatedAt: Date;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentCountArgs.ts
new file mode 100644
index 0000000..7243a7f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentCountArgs.ts
@@ -0,0 +1,5 @@
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+
+export type EntertainmentCountArgs = {
+ where?: EntertainmentWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentCreateInput.ts
new file mode 100644
index 0000000..512a686
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentCreateInput.ts
@@ -0,0 +1,7 @@
+import { InputJsonValue } from "../../types";
+
+export type EntertainmentCreateInput = {
+ details?: InputJsonValue;
+ name?: string | null;
+ typeField?: "Option1" | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentFindManyArgs.ts
new file mode 100644
index 0000000..c45f4df
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+import { EntertainmentOrderByInput } from "./EntertainmentOrderByInput";
+
+export type EntertainmentFindManyArgs = {
+ where?: EntertainmentWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentFindUniqueArgs.ts
new file mode 100644
index 0000000..360ff78
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+
+export type EntertainmentFindUniqueArgs = {
+ where: EntertainmentWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentListRelationFilter.ts
new file mode 100644
index 0000000..0810e26
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+
+export type EntertainmentListRelationFilter = {
+ every?: EntertainmentWhereInput;
+ some?: EntertainmentWhereInput;
+ none?: EntertainmentWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentOrderByInput.ts
new file mode 100644
index 0000000..d9dd815
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentOrderByInput.ts
@@ -0,0 +1,10 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type EntertainmentOrderByInput = {
+ createdAt?: SortOrder;
+ details?: SortOrder;
+ id?: SortOrder;
+ name?: SortOrder;
+ typeField?: SortOrder;
+ updatedAt?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentUpdateInput.ts
new file mode 100644
index 0000000..813e723
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentUpdateInput.ts
@@ -0,0 +1,7 @@
+import { InputJsonValue } from "../../types";
+
+export type EntertainmentUpdateInput = {
+ details?: InputJsonValue;
+ name?: string | null;
+ typeField?: "Option1" | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentWhereInput.ts
new file mode 100644
index 0000000..72e5112
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentWhereInput.ts
@@ -0,0 +1,10 @@
+import { JsonFilter } from "../../util/JsonFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+
+export type EntertainmentWhereInput = {
+ details?: JsonFilter;
+ id?: StringFilter;
+ name?: StringNullableFilter;
+ typeField?: "Option1";
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentWhereUniqueInput.ts
new file mode 100644
index 0000000..ed2adcb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EntertainmentWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type EntertainmentWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EnumEntertainmentTypeField.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EnumEntertainmentTypeField.ts
new file mode 100644
index 0000000..07771ad
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/EnumEntertainmentTypeField.ts
@@ -0,0 +1,3 @@
+export enum EnumEntertainmentTypeField {
+ Option_1 = "Option1",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/entertainment/UpdateEntertainmentArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/UpdateEntertainmentArgs.ts
new file mode 100644
index 0000000..70660bc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/entertainment/UpdateEntertainmentArgs.ts
@@ -0,0 +1,7 @@
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+import { EntertainmentUpdateInput } from "./EntertainmentUpdateInput";
+
+export type UpdateEntertainmentArgs = {
+ where: EntertainmentWhereUniqueInput;
+ data: EntertainmentUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/CreateSecurityArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/CreateSecurityArgs.ts
new file mode 100644
index 0000000..b0456a3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/CreateSecurityArgs.ts
@@ -0,0 +1,5 @@
+import { SecurityCreateInput } from "./SecurityCreateInput";
+
+export type CreateSecurityArgs = {
+ data: SecurityCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/DeleteSecurityArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/DeleteSecurityArgs.ts
new file mode 100644
index 0000000..5590f0f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/DeleteSecurityArgs.ts
@@ -0,0 +1,5 @@
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+
+export type DeleteSecurityArgs = {
+ where: SecurityWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/EnumSecurityStatus.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/EnumSecurityStatus.ts
new file mode 100644
index 0000000..ae70b11
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/EnumSecurityStatus.ts
@@ -0,0 +1,3 @@
+export enum EnumSecurityStatus {
+ Option_1 = "Option1",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/Security.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/Security.ts
new file mode 100644
index 0000000..f21800e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/Security.ts
@@ -0,0 +1,11 @@
+import { User } from "../user/User";
+
+export type Security = {
+ action: string | null;
+ createdAt: Date;
+ date: Date | null;
+ id: string;
+ status?: "Option1" | null;
+ updatedAt: Date;
+ user?: User | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityCountArgs.ts
new file mode 100644
index 0000000..403230e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityCountArgs.ts
@@ -0,0 +1,5 @@
+import { SecurityWhereInput } from "./SecurityWhereInput";
+
+export type SecurityCountArgs = {
+ where?: SecurityWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityCreateInput.ts
new file mode 100644
index 0000000..1c10a8e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityCreateInput.ts
@@ -0,0 +1,8 @@
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type SecurityCreateInput = {
+ action?: string | null;
+ date?: Date | null;
+ status?: "Option1" | null;
+ user?: UserWhereUniqueInput | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityFindManyArgs.ts
new file mode 100644
index 0000000..571b2e1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { SecurityWhereInput } from "./SecurityWhereInput";
+import { SecurityOrderByInput } from "./SecurityOrderByInput";
+
+export type SecurityFindManyArgs = {
+ where?: SecurityWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityFindUniqueArgs.ts
new file mode 100644
index 0000000..5ea2a04
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+
+export type SecurityFindUniqueArgs = {
+ where: SecurityWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityListRelationFilter.ts
new file mode 100644
index 0000000..e9b0260
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { SecurityWhereInput } from "./SecurityWhereInput";
+
+export type SecurityListRelationFilter = {
+ every?: SecurityWhereInput;
+ some?: SecurityWhereInput;
+ none?: SecurityWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityOrderByInput.ts
new file mode 100644
index 0000000..4bbf73b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityOrderByInput.ts
@@ -0,0 +1,11 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type SecurityOrderByInput = {
+ action?: SortOrder;
+ createdAt?: SortOrder;
+ date?: SortOrder;
+ id?: SortOrder;
+ status?: SortOrder;
+ updatedAt?: SortOrder;
+ userId?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityUpdateInput.ts
new file mode 100644
index 0000000..ddb0cd3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityUpdateInput.ts
@@ -0,0 +1,8 @@
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type SecurityUpdateInput = {
+ action?: string | null;
+ date?: Date | null;
+ status?: "Option1" | null;
+ user?: UserWhereUniqueInput | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityWhereInput.ts
new file mode 100644
index 0000000..04022d3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityWhereInput.ts
@@ -0,0 +1,12 @@
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type SecurityWhereInput = {
+ action?: StringNullableFilter;
+ date?: DateTimeNullableFilter;
+ id?: StringFilter;
+ status?: "Option1";
+ user?: UserWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityWhereUniqueInput.ts
new file mode 100644
index 0000000..0dca2bc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/SecurityWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type SecurityWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/security/UpdateSecurityArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/security/UpdateSecurityArgs.ts
new file mode 100644
index 0000000..582f0d3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/security/UpdateSecurityArgs.ts
@@ -0,0 +1,7 @@
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+import { SecurityUpdateInput } from "./SecurityUpdateInput";
+
+export type UpdateSecurityArgs = {
+ where: SecurityWhereUniqueInput;
+ data: SecurityUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/CreateSlotArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/CreateSlotArgs.ts
new file mode 100644
index 0000000..26a1949
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/CreateSlotArgs.ts
@@ -0,0 +1,5 @@
+import { SlotCreateInput } from "./SlotCreateInput";
+
+export type CreateSlotArgs = {
+ data: SlotCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/DeleteSlotArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/DeleteSlotArgs.ts
new file mode 100644
index 0000000..021dece
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/DeleteSlotArgs.ts
@@ -0,0 +1,5 @@
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+
+export type DeleteSlotArgs = {
+ where: SlotWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/Slot.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/Slot.ts
new file mode 100644
index 0000000..abe22f0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/Slot.ts
@@ -0,0 +1,13 @@
+import { JsonValue } from "type-fest";
+import { User } from "../user/User";
+
+export type Slot = {
+ bid: number | null;
+ createdAt: Date;
+ description: string | null;
+ id: string;
+ metrics: JsonValue;
+ name: string | null;
+ updatedAt: Date;
+ user?: User | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotCountArgs.ts
new file mode 100644
index 0000000..38d1e6c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotCountArgs.ts
@@ -0,0 +1,5 @@
+import { SlotWhereInput } from "./SlotWhereInput";
+
+export type SlotCountArgs = {
+ where?: SlotWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotCreateInput.ts
new file mode 100644
index 0000000..cc5402e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotCreateInput.ts
@@ -0,0 +1,10 @@
+import { InputJsonValue } from "../../types";
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type SlotCreateInput = {
+ bid?: number | null;
+ description?: string | null;
+ metrics?: InputJsonValue;
+ name?: string | null;
+ user?: UserWhereUniqueInput | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotFindManyArgs.ts
new file mode 100644
index 0000000..f4cd5f5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { SlotWhereInput } from "./SlotWhereInput";
+import { SlotOrderByInput } from "./SlotOrderByInput";
+
+export type SlotFindManyArgs = {
+ where?: SlotWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotFindUniqueArgs.ts
new file mode 100644
index 0000000..43982e3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+
+export type SlotFindUniqueArgs = {
+ where: SlotWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotListRelationFilter.ts
new file mode 100644
index 0000000..f3b2f8c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { SlotWhereInput } from "./SlotWhereInput";
+
+export type SlotListRelationFilter = {
+ every?: SlotWhereInput;
+ some?: SlotWhereInput;
+ none?: SlotWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotOrderByInput.ts
new file mode 100644
index 0000000..b048d65
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotOrderByInput.ts
@@ -0,0 +1,12 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type SlotOrderByInput = {
+ bid?: SortOrder;
+ createdAt?: SortOrder;
+ description?: SortOrder;
+ id?: SortOrder;
+ metrics?: SortOrder;
+ name?: SortOrder;
+ updatedAt?: SortOrder;
+ userId?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotUpdateInput.ts
new file mode 100644
index 0000000..9de9c68
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotUpdateInput.ts
@@ -0,0 +1,10 @@
+import { InputJsonValue } from "../../types";
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type SlotUpdateInput = {
+ bid?: number | null;
+ description?: string | null;
+ metrics?: InputJsonValue;
+ name?: string | null;
+ user?: UserWhereUniqueInput | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotWhereInput.ts
new file mode 100644
index 0000000..2ce125a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotWhereInput.ts
@@ -0,0 +1,14 @@
+import { FloatNullableFilter } from "../../util/FloatNullableFilter";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { JsonFilter } from "../../util/JsonFilter";
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type SlotWhereInput = {
+ bid?: FloatNullableFilter;
+ description?: StringNullableFilter;
+ id?: StringFilter;
+ metrics?: JsonFilter;
+ name?: StringNullableFilter;
+ user?: UserWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotWhereUniqueInput.ts
new file mode 100644
index 0000000..5e93e41
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/SlotWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type SlotWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/slot/UpdateSlotArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/slot/UpdateSlotArgs.ts
new file mode 100644
index 0000000..c2e0c1a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/slot/UpdateSlotArgs.ts
@@ -0,0 +1,7 @@
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+import { SlotUpdateInput } from "./SlotUpdateInput";
+
+export type UpdateSlotArgs = {
+ where: SlotWhereUniqueInput;
+ data: SlotUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/CreateTicketArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/CreateTicketArgs.ts
new file mode 100644
index 0000000..1848f91
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/CreateTicketArgs.ts
@@ -0,0 +1,5 @@
+import { TicketCreateInput } from "./TicketCreateInput";
+
+export type CreateTicketArgs = {
+ data: TicketCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/DeleteTicketArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/DeleteTicketArgs.ts
new file mode 100644
index 0000000..8d55a09
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/DeleteTicketArgs.ts
@@ -0,0 +1,5 @@
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+
+export type DeleteTicketArgs = {
+ where: TicketWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/EnumTicketPriority.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/EnumTicketPriority.ts
new file mode 100644
index 0000000..c2841f5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/EnumTicketPriority.ts
@@ -0,0 +1,3 @@
+export enum EnumTicketPriority {
+ Option_1 = "Option1",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/EnumTicketStatus.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/EnumTicketStatus.ts
new file mode 100644
index 0000000..77c9b6f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/EnumTicketStatus.ts
@@ -0,0 +1,3 @@
+export enum EnumTicketStatus {
+ Option_1 = "Option1",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/Ticket.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/Ticket.ts
new file mode 100644
index 0000000..62342be
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/Ticket.ts
@@ -0,0 +1,13 @@
+import { User } from "../user/User";
+
+export type Ticket = {
+ createdAt: Date;
+ dateClosed: Date | null;
+ dateCreated: Date | null;
+ id: string;
+ issue: string | null;
+ priority?: "Option1" | null;
+ status?: "Option1" | null;
+ updatedAt: Date;
+ user?: User | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketCountArgs.ts
new file mode 100644
index 0000000..18f86da
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketCountArgs.ts
@@ -0,0 +1,5 @@
+import { TicketWhereInput } from "./TicketWhereInput";
+
+export type TicketCountArgs = {
+ where?: TicketWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketCreateInput.ts
new file mode 100644
index 0000000..75b31cd
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketCreateInput.ts
@@ -0,0 +1,10 @@
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type TicketCreateInput = {
+ dateClosed?: Date | null;
+ dateCreated?: Date | null;
+ issue?: string | null;
+ priority?: "Option1" | null;
+ status?: "Option1" | null;
+ user?: UserWhereUniqueInput | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketFindManyArgs.ts
new file mode 100644
index 0000000..2137bab
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { TicketWhereInput } from "./TicketWhereInput";
+import { TicketOrderByInput } from "./TicketOrderByInput";
+
+export type TicketFindManyArgs = {
+ where?: TicketWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketFindUniqueArgs.ts
new file mode 100644
index 0000000..7a639aa
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+
+export type TicketFindUniqueArgs = {
+ where: TicketWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketListRelationFilter.ts
new file mode 100644
index 0000000..e243cc0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { TicketWhereInput } from "./TicketWhereInput";
+
+export type TicketListRelationFilter = {
+ every?: TicketWhereInput;
+ some?: TicketWhereInput;
+ none?: TicketWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketOrderByInput.ts
new file mode 100644
index 0000000..0753d6c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketOrderByInput.ts
@@ -0,0 +1,13 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type TicketOrderByInput = {
+ createdAt?: SortOrder;
+ dateClosed?: SortOrder;
+ dateCreated?: SortOrder;
+ id?: SortOrder;
+ issue?: SortOrder;
+ priority?: SortOrder;
+ status?: SortOrder;
+ updatedAt?: SortOrder;
+ userId?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketUpdateInput.ts
new file mode 100644
index 0000000..dc394ec
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketUpdateInput.ts
@@ -0,0 +1,10 @@
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type TicketUpdateInput = {
+ dateClosed?: Date | null;
+ dateCreated?: Date | null;
+ issue?: string | null;
+ priority?: "Option1" | null;
+ status?: "Option1" | null;
+ user?: UserWhereUniqueInput | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketWhereInput.ts
new file mode 100644
index 0000000..1cf03cc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketWhereInput.ts
@@ -0,0 +1,14 @@
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type TicketWhereInput = {
+ dateClosed?: DateTimeNullableFilter;
+ dateCreated?: DateTimeNullableFilter;
+ id?: StringFilter;
+ issue?: StringNullableFilter;
+ priority?: "Option1";
+ status?: "Option1";
+ user?: UserWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketWhereUniqueInput.ts
new file mode 100644
index 0000000..ad68683
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/TicketWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type TicketWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/ticket/UpdateTicketArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/ticket/UpdateTicketArgs.ts
new file mode 100644
index 0000000..80a7766
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/ticket/UpdateTicketArgs.ts
@@ -0,0 +1,7 @@
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+import { TicketUpdateInput } from "./TicketUpdateInput";
+
+export type UpdateTicketArgs = {
+ where: TicketWhereUniqueInput;
+ data: TicketUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/CreateUserArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/CreateUserArgs.ts
new file mode 100644
index 0000000..2a56f0c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/CreateUserArgs.ts
@@ -0,0 +1,5 @@
+import { UserCreateInput } from "./UserCreateInput";
+
+export type CreateUserArgs = {
+ data: UserCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/DeleteUserArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/DeleteUserArgs.ts
new file mode 100644
index 0000000..5f655b8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/DeleteUserArgs.ts
@@ -0,0 +1,5 @@
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+
+export type DeleteUserArgs = {
+ where: UserWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/SecurityCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/SecurityCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..2737a0b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/SecurityCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,5 @@
+import { SecurityWhereUniqueInput } from "../security/SecurityWhereUniqueInput";
+
+export type SecurityCreateNestedManyWithoutUsersInput = {
+ connect?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/SecurityUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/SecurityUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..c69c596
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/SecurityUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,7 @@
+import { SecurityWhereUniqueInput } from "../security/SecurityWhereUniqueInput";
+
+export type SecurityUpdateManyWithoutUsersInput = {
+ connect?: Array;
+ disconnect?: Array;
+ set?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/SlotCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/SlotCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..cffeea4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/SlotCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,5 @@
+import { SlotWhereUniqueInput } from "../slot/SlotWhereUniqueInput";
+
+export type SlotCreateNestedManyWithoutUsersInput = {
+ connect?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/SlotUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/SlotUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..9275c1b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/SlotUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,7 @@
+import { SlotWhereUniqueInput } from "../slot/SlotWhereUniqueInput";
+
+export type SlotUpdateManyWithoutUsersInput = {
+ connect?: Array;
+ disconnect?: Array;
+ set?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/TicketCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/TicketCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..df6e4da
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/TicketCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,5 @@
+import { TicketWhereUniqueInput } from "../ticket/TicketWhereUniqueInput";
+
+export type TicketCreateNestedManyWithoutUsersInput = {
+ connect?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/TicketUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/TicketUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..57a5fef
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/TicketUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,7 @@
+import { TicketWhereUniqueInput } from "../ticket/TicketWhereUniqueInput";
+
+export type TicketUpdateManyWithoutUsersInput = {
+ connect?: Array;
+ disconnect?: Array;
+ set?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UpdateUserArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UpdateUserArgs.ts
new file mode 100644
index 0000000..30e635e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UpdateUserArgs.ts
@@ -0,0 +1,7 @@
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+import { UserUpdateInput } from "./UserUpdateInput";
+
+export type UpdateUserArgs = {
+ where: UserWhereUniqueInput;
+ data: UserUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/User.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/User.ts
new file mode 100644
index 0000000..1df9767
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/User.ts
@@ -0,0 +1,22 @@
+import { JsonValue } from "type-fest";
+import { Security } from "../security/Security";
+import { Slot } from "../slot/Slot";
+import { Ticket } from "../ticket/Ticket";
+import { Vouch } from "../vouch/Vouch";
+
+export type User = {
+ createdAt: Date;
+ discordId: string | null;
+ email: string | null;
+ firstName: string | null;
+ id: string;
+ lastName: string | null;
+ reputation: number | null;
+ roles: JsonValue;
+ securities?: Array;
+ slots?: Array;
+ tickets?: Array;
+ updatedAt: Date;
+ username: string;
+ vouches?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserCountArgs.ts
new file mode 100644
index 0000000..b300ec3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserCountArgs.ts
@@ -0,0 +1,5 @@
+import { UserWhereInput } from "./UserWhereInput";
+
+export type UserCountArgs = {
+ where?: UserWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserCreateInput.ts
new file mode 100644
index 0000000..3d49dfc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserCreateInput.ts
@@ -0,0 +1,20 @@
+import { InputJsonValue } from "../../types";
+import { SecurityCreateNestedManyWithoutUsersInput } from "./SecurityCreateNestedManyWithoutUsersInput";
+import { SlotCreateNestedManyWithoutUsersInput } from "./SlotCreateNestedManyWithoutUsersInput";
+import { TicketCreateNestedManyWithoutUsersInput } from "./TicketCreateNestedManyWithoutUsersInput";
+import { VouchCreateNestedManyWithoutUsersInput } from "./VouchCreateNestedManyWithoutUsersInput";
+
+export type UserCreateInput = {
+ discordId?: string | null;
+ email?: string | null;
+ firstName?: string | null;
+ lastName?: string | null;
+ password: string;
+ reputation?: number | null;
+ roles: InputJsonValue;
+ securities?: SecurityCreateNestedManyWithoutUsersInput;
+ slots?: SlotCreateNestedManyWithoutUsersInput;
+ tickets?: TicketCreateNestedManyWithoutUsersInput;
+ username: string;
+ vouches?: VouchCreateNestedManyWithoutUsersInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserFindManyArgs.ts
new file mode 100644
index 0000000..b453f3e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { UserWhereInput } from "./UserWhereInput";
+import { UserOrderByInput } from "./UserOrderByInput";
+
+export type UserFindManyArgs = {
+ where?: UserWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserFindUniqueArgs.ts
new file mode 100644
index 0000000..97d18e8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+
+export type UserFindUniqueArgs = {
+ where: UserWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserListRelationFilter.ts
new file mode 100644
index 0000000..4c4d06e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { UserWhereInput } from "./UserWhereInput";
+
+export type UserListRelationFilter = {
+ every?: UserWhereInput;
+ some?: UserWhereInput;
+ none?: UserWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserOrderByInput.ts
new file mode 100644
index 0000000..a5f7a42
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserOrderByInput.ts
@@ -0,0 +1,15 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type UserOrderByInput = {
+ createdAt?: SortOrder;
+ discordId?: SortOrder;
+ email?: SortOrder;
+ firstName?: SortOrder;
+ id?: SortOrder;
+ lastName?: SortOrder;
+ password?: SortOrder;
+ reputation?: SortOrder;
+ roles?: SortOrder;
+ updatedAt?: SortOrder;
+ username?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserUpdateInput.ts
new file mode 100644
index 0000000..4febcc9
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserUpdateInput.ts
@@ -0,0 +1,20 @@
+import { InputJsonValue } from "../../types";
+import { SecurityUpdateManyWithoutUsersInput } from "./SecurityUpdateManyWithoutUsersInput";
+import { SlotUpdateManyWithoutUsersInput } from "./SlotUpdateManyWithoutUsersInput";
+import { TicketUpdateManyWithoutUsersInput } from "./TicketUpdateManyWithoutUsersInput";
+import { VouchUpdateManyWithoutUsersInput } from "./VouchUpdateManyWithoutUsersInput";
+
+export type UserUpdateInput = {
+ discordId?: string | null;
+ email?: string | null;
+ firstName?: string | null;
+ lastName?: string | null;
+ password?: string;
+ reputation?: number | null;
+ roles?: InputJsonValue;
+ securities?: SecurityUpdateManyWithoutUsersInput;
+ slots?: SlotUpdateManyWithoutUsersInput;
+ tickets?: TicketUpdateManyWithoutUsersInput;
+ username?: string;
+ vouches?: VouchUpdateManyWithoutUsersInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserWhereInput.ts
new file mode 100644
index 0000000..85889fa
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserWhereInput.ts
@@ -0,0 +1,21 @@
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { IntNullableFilter } from "../../util/IntNullableFilter";
+import { SecurityListRelationFilter } from "../security/SecurityListRelationFilter";
+import { SlotListRelationFilter } from "../slot/SlotListRelationFilter";
+import { TicketListRelationFilter } from "../ticket/TicketListRelationFilter";
+import { VouchListRelationFilter } from "../vouch/VouchListRelationFilter";
+
+export type UserWhereInput = {
+ discordId?: StringNullableFilter;
+ email?: StringNullableFilter;
+ firstName?: StringNullableFilter;
+ id?: StringFilter;
+ lastName?: StringNullableFilter;
+ reputation?: IntNullableFilter;
+ securities?: SecurityListRelationFilter;
+ slots?: SlotListRelationFilter;
+ tickets?: TicketListRelationFilter;
+ username?: StringFilter;
+ vouches?: VouchListRelationFilter;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/UserWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/UserWhereUniqueInput.ts
new file mode 100644
index 0000000..309d343
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/UserWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type UserWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/VouchCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/VouchCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..ba56dd2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/VouchCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,5 @@
+import { VouchWhereUniqueInput } from "../vouch/VouchWhereUniqueInput";
+
+export type VouchCreateNestedManyWithoutUsersInput = {
+ connect?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/user/VouchUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/user/VouchUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..1a6daf8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/user/VouchUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,7 @@
+import { VouchWhereUniqueInput } from "../vouch/VouchWhereUniqueInput";
+
+export type VouchUpdateManyWithoutUsersInput = {
+ connect?: Array;
+ disconnect?: Array;
+ set?: Array;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/CreateVouchArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/CreateVouchArgs.ts
new file mode 100644
index 0000000..7df022a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/CreateVouchArgs.ts
@@ -0,0 +1,5 @@
+import { VouchCreateInput } from "./VouchCreateInput";
+
+export type CreateVouchArgs = {
+ data: VouchCreateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/DeleteVouchArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/DeleteVouchArgs.ts
new file mode 100644
index 0000000..5622e01
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/DeleteVouchArgs.ts
@@ -0,0 +1,5 @@
+import { VouchWhereUniqueInput } from "./VouchWhereUniqueInput";
+
+export type DeleteVouchArgs = {
+ where: VouchWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/UpdateVouchArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/UpdateVouchArgs.ts
new file mode 100644
index 0000000..4feca2f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/UpdateVouchArgs.ts
@@ -0,0 +1,7 @@
+import { VouchWhereUniqueInput } from "./VouchWhereUniqueInput";
+import { VouchUpdateInput } from "./VouchUpdateInput";
+
+export type UpdateVouchArgs = {
+ where: VouchWhereUniqueInput;
+ data: VouchUpdateInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/Vouch.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/Vouch.ts
new file mode 100644
index 0000000..68ddd46
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/Vouch.ts
@@ -0,0 +1,13 @@
+import { User } from "../user/User";
+
+export type Vouch = {
+ badge: string | null;
+ category: string | null;
+ challenge: string | null;
+ createdAt: Date;
+ date: Date | null;
+ id: string;
+ updatedAt: Date;
+ user?: User | null;
+ vouchText: string | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchCountArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchCountArgs.ts
new file mode 100644
index 0000000..1d040cb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchCountArgs.ts
@@ -0,0 +1,5 @@
+import { VouchWhereInput } from "./VouchWhereInput";
+
+export type VouchCountArgs = {
+ where?: VouchWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchCreateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchCreateInput.ts
new file mode 100644
index 0000000..06c7589
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchCreateInput.ts
@@ -0,0 +1,10 @@
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type VouchCreateInput = {
+ badge?: string | null;
+ category?: string | null;
+ challenge?: string | null;
+ date?: Date | null;
+ user?: UserWhereUniqueInput | null;
+ vouchText?: string | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchFindManyArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchFindManyArgs.ts
new file mode 100644
index 0000000..255ab7a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchFindManyArgs.ts
@@ -0,0 +1,9 @@
+import { VouchWhereInput } from "./VouchWhereInput";
+import { VouchOrderByInput } from "./VouchOrderByInput";
+
+export type VouchFindManyArgs = {
+ where?: VouchWhereInput;
+ orderBy?: Array;
+ skip?: number;
+ take?: number;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchFindUniqueArgs.ts
new file mode 100644
index 0000000..8852518
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchFindUniqueArgs.ts
@@ -0,0 +1,5 @@
+import { VouchWhereUniqueInput } from "./VouchWhereUniqueInput";
+
+export type VouchFindUniqueArgs = {
+ where: VouchWhereUniqueInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchListRelationFilter.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchListRelationFilter.ts
new file mode 100644
index 0000000..07950b3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchListRelationFilter.ts
@@ -0,0 +1,7 @@
+import { VouchWhereInput } from "./VouchWhereInput";
+
+export type VouchListRelationFilter = {
+ every?: VouchWhereInput;
+ some?: VouchWhereInput;
+ none?: VouchWhereInput;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchOrderByInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchOrderByInput.ts
new file mode 100644
index 0000000..fc7e001
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchOrderByInput.ts
@@ -0,0 +1,13 @@
+import { SortOrder } from "../../util/SortOrder";
+
+export type VouchOrderByInput = {
+ badge?: SortOrder;
+ category?: SortOrder;
+ challenge?: SortOrder;
+ createdAt?: SortOrder;
+ date?: SortOrder;
+ id?: SortOrder;
+ updatedAt?: SortOrder;
+ userId?: SortOrder;
+ vouchText?: SortOrder;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchUpdateInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchUpdateInput.ts
new file mode 100644
index 0000000..b575eff
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchUpdateInput.ts
@@ -0,0 +1,10 @@
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type VouchUpdateInput = {
+ badge?: string | null;
+ category?: string | null;
+ challenge?: string | null;
+ date?: Date | null;
+ user?: UserWhereUniqueInput | null;
+ vouchText?: string | null;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchWhereInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchWhereInput.ts
new file mode 100644
index 0000000..cb0c86d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchWhereInput.ts
@@ -0,0 +1,14 @@
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { UserWhereUniqueInput } from "../user/UserWhereUniqueInput";
+
+export type VouchWhereInput = {
+ badge?: StringNullableFilter;
+ category?: StringNullableFilter;
+ challenge?: StringNullableFilter;
+ date?: DateTimeNullableFilter;
+ id?: StringFilter;
+ user?: UserWhereUniqueInput;
+ vouchText?: StringNullableFilter;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchWhereUniqueInput.ts
new file mode 100644
index 0000000..e7cb7eb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/api/vouch/VouchWhereUniqueInput.ts
@@ -0,0 +1,3 @@
+export type VouchWhereUniqueInput = {
+ id: string;
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/auth-provider/ra-auth-http.ts b/apps/vesst-discord-bot-backend-admin/src/auth-provider/ra-auth-http.ts
new file mode 100644
index 0000000..c6eeba8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/auth-provider/ra-auth-http.ts
@@ -0,0 +1,78 @@
+import { gql } from "@apollo/client/core";
+import { AuthProvider } from "react-admin";
+import {
+ CREDENTIALS_LOCAL_STORAGE_ITEM,
+ USER_DATA_LOCAL_STORAGE_ITEM,
+} from "../constants";
+import { Credentials, LoginMutateResult } from "../types";
+import { apolloClient } from "../data-provider/graphqlDataProvider";
+
+const LOGIN = gql`
+ mutation login($username: String!, $password: String!) {
+ login(credentials: { username: $username, password: $password }) {
+ username
+ roles
+ }
+ }
+`;
+
+export const httpAuthProvider: AuthProvider = {
+ login: async (credentials: Credentials) => {
+ const userData = await apolloClient.mutate({
+ mutation: LOGIN,
+ variables: {
+ ...credentials,
+ },
+ });
+
+ if (userData && userData.data?.login.username) {
+ localStorage.setItem(
+ CREDENTIALS_LOCAL_STORAGE_ITEM,
+ createBasicAuthorizationHeader(
+ credentials.username,
+ credentials.password
+ )
+ );
+ localStorage.setItem(
+ USER_DATA_LOCAL_STORAGE_ITEM,
+ JSON.stringify(userData.data)
+ );
+ return Promise.resolve();
+ }
+ return Promise.reject();
+ },
+ logout: () => {
+ localStorage.removeItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+ return Promise.resolve();
+ },
+ checkError: ({ status }: any) => {
+ if (status === 401 || status === 403) {
+ localStorage.removeItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+ return Promise.reject();
+ }
+ return Promise.resolve();
+ },
+ checkAuth: () => {
+ return localStorage.getItem(CREDENTIALS_LOCAL_STORAGE_ITEM)
+ ? Promise.resolve()
+ : Promise.reject();
+ },
+ getPermissions: () => Promise.reject("Unknown method"),
+ getIdentity: () => {
+ const str = localStorage.getItem(USER_DATA_LOCAL_STORAGE_ITEM);
+ const userData: LoginMutateResult = JSON.parse(str || "");
+
+ return Promise.resolve({
+ id: userData.login.username,
+ fullName: userData.login.username,
+ avatar: undefined,
+ });
+ },
+};
+
+function createBasicAuthorizationHeader(
+ username: string,
+ password: string
+): string {
+ return `Basic ${btoa(`${username}:${password}`)}`;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/auth-provider/ra-auth-jwt.ts b/apps/vesst-discord-bot-backend-admin/src/auth-provider/ra-auth-jwt.ts
new file mode 100644
index 0000000..c8bcafc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/auth-provider/ra-auth-jwt.ts
@@ -0,0 +1,72 @@
+import { gql } from "@apollo/client/core";
+import { AuthProvider } from "react-admin";
+import {
+ CREDENTIALS_LOCAL_STORAGE_ITEM,
+ USER_DATA_LOCAL_STORAGE_ITEM,
+} from "../constants";
+import { Credentials, LoginMutateResult } from "../types";
+import { apolloClient } from "../data-provider/graphqlDataProvider";
+
+const LOGIN = gql`
+ mutation login($username: String!, $password: String!) {
+ login(credentials: { username: $username, password: $password }) {
+ username
+ accessToken
+ }
+ }
+`;
+
+export const jwtAuthProvider: AuthProvider = {
+ login: async (credentials: Credentials) => {
+ const userData = await apolloClient.mutate({
+ mutation: LOGIN,
+ variables: {
+ ...credentials,
+ },
+ });
+
+ if (userData && userData.data?.login.username) {
+ localStorage.setItem(
+ CREDENTIALS_LOCAL_STORAGE_ITEM,
+ createBearerAuthorizationHeader(userData.data.login?.accessToken)
+ );
+ localStorage.setItem(
+ USER_DATA_LOCAL_STORAGE_ITEM,
+ JSON.stringify(userData.data)
+ );
+ return Promise.resolve();
+ }
+ return Promise.reject();
+ },
+ logout: () => {
+ localStorage.removeItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+ return Promise.resolve();
+ },
+ checkError: ({ status }: any) => {
+ if (status === 401 || status === 403) {
+ localStorage.removeItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+ return Promise.reject();
+ }
+ return Promise.resolve();
+ },
+ checkAuth: () => {
+ return localStorage.getItem(CREDENTIALS_LOCAL_STORAGE_ITEM)
+ ? Promise.resolve()
+ : Promise.reject();
+ },
+ getPermissions: () => Promise.reject("Unknown method"),
+ getIdentity: () => {
+ const str = localStorage.getItem(USER_DATA_LOCAL_STORAGE_ITEM);
+ const userData: LoginMutateResult = JSON.parse(str || "");
+
+ return Promise.resolve({
+ id: userData.login.username,
+ fullName: userData.login.username,
+ avatar: undefined,
+ });
+ },
+};
+
+export function createBearerAuthorizationHeader(accessToken: string) {
+ return `Bearer ${accessToken}`;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/auth.ts b/apps/vesst-discord-bot-backend-admin/src/auth.ts
new file mode 100644
index 0000000..498b026
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/auth.ts
@@ -0,0 +1,34 @@
+import { EventEmitter } from "events";
+import { CREDENTIALS_LOCAL_STORAGE_ITEM } from "./constants";
+import { Credentials } from "./types";
+
+const eventEmitter = new EventEmitter();
+
+export function isAuthenticated(): boolean {
+ return Boolean(getCredentials());
+}
+
+export function listen(listener: (authenticated: boolean) => void): void {
+ eventEmitter.on("change", () => {
+ listener(isAuthenticated());
+ });
+}
+
+export function setCredentials(credentials: Credentials) {
+ localStorage.setItem(
+ CREDENTIALS_LOCAL_STORAGE_ITEM,
+ JSON.stringify(credentials)
+ );
+}
+
+export function getCredentials(): Credentials | null {
+ const raw = localStorage.getItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+ if (raw === null) {
+ return null;
+ }
+ return JSON.parse(raw);
+}
+
+export function removeCredentials(): void {
+ localStorage.removeItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/constants.ts b/apps/vesst-discord-bot-backend-admin/src/constants.ts
new file mode 100644
index 0000000..4b3ca4b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/constants.ts
@@ -0,0 +1,2 @@
+export const CREDENTIALS_LOCAL_STORAGE_ITEM = "credentials";
+export const USER_DATA_LOCAL_STORAGE_ITEM = "userData";
diff --git a/apps/vesst-discord-bot-backend-admin/src/data-provider/graphqlDataProvider.ts b/apps/vesst-discord-bot-backend-admin/src/data-provider/graphqlDataProvider.ts
new file mode 100644
index 0000000..3ec4466
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/data-provider/graphqlDataProvider.ts
@@ -0,0 +1,28 @@
+import buildGraphQLProvider from "ra-data-graphql-amplication";
+import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
+import { setContext } from "@apollo/client/link/context";
+import { CREDENTIALS_LOCAL_STORAGE_ITEM } from "../constants";
+
+const httpLink = createHttpLink({
+ uri: `${process.env.REACT_APP_SERVER_URL}/graphql`,
+});
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+const authLink = setContext((_, { headers }) => {
+ const token = localStorage.getItem(CREDENTIALS_LOCAL_STORAGE_ITEM);
+ return {
+ headers: {
+ ...headers,
+ authorization: token ? token : "",
+ },
+ };
+});
+
+export const apolloClient = new ApolloClient({
+ cache: new InMemoryCache(),
+ link: authLink.concat(httpLink),
+});
+
+export default buildGraphQLProvider({
+ client: apolloClient,
+});
diff --git a/apps/vesst-discord-bot-backend-admin/src/embed/EmbedCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedCreate.tsx
new file mode 100644
index 0000000..5cd6f18
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedCreate.tsx
@@ -0,0 +1,22 @@
+import * as React from "react";
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ TextInput,
+ DateTimeInput,
+} from "react-admin";
+
+export const EmbedCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/embed/EmbedEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedEdit.tsx
new file mode 100644
index 0000000..ec7d2a7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedEdit.tsx
@@ -0,0 +1,22 @@
+import * as React from "react";
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ TextInput,
+ DateTimeInput,
+} from "react-admin";
+
+export const EmbedEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/embed/EmbedList.tsx b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedList.tsx
new file mode 100644
index 0000000..6d8bbda
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedList.tsx
@@ -0,0 +1,26 @@
+import * as React from "react";
+import { List, Datagrid, ListProps, TextField, DateField } from "react-admin";
+import Pagination from "../Components/Pagination";
+
+export const EmbedList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/embed/EmbedShow.tsx b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedShow.tsx
new file mode 100644
index 0000000..724a11a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedShow.tsx
@@ -0,0 +1,25 @@
+import * as React from "react";
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ TextField,
+ DateField,
+} from "react-admin";
+
+export const EmbedShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/embed/EmbedTitle.ts b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedTitle.ts
new file mode 100644
index 0000000..42dacb6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/embed/EmbedTitle.ts
@@ -0,0 +1,7 @@
+import { Embed as TEmbed } from "../api/embed/Embed";
+
+export const EMBED_TITLE_FIELD = "title";
+
+export const EmbedTitle = (record: TEmbed): string => {
+ return record.title?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentCreate.tsx
new file mode 100644
index 0000000..c46c873
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentCreate.tsx
@@ -0,0 +1,27 @@
+import * as React from "react";
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ TextInput,
+ SelectInput,
+} from "react-admin";
+
+export const EntertainmentCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentEdit.tsx
new file mode 100644
index 0000000..829ce58
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentEdit.tsx
@@ -0,0 +1,27 @@
+import * as React from "react";
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ TextInput,
+ SelectInput,
+} from "react-admin";
+
+export const EntertainmentEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentList.tsx b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentList.tsx
new file mode 100644
index 0000000..258dc3b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentList.tsx
@@ -0,0 +1,24 @@
+import * as React from "react";
+import { List, Datagrid, ListProps, DateField, TextField } from "react-admin";
+import Pagination from "../Components/Pagination";
+
+export const EntertainmentList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentShow.tsx b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentShow.tsx
new file mode 100644
index 0000000..d6a2d38
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentShow.tsx
@@ -0,0 +1,23 @@
+import * as React from "react";
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ DateField,
+ TextField,
+} from "react-admin";
+
+export const EntertainmentShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentTitle.ts b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentTitle.ts
new file mode 100644
index 0000000..091e2a6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/entertainment/EntertainmentTitle.ts
@@ -0,0 +1,7 @@
+import { Entertainment as TEntertainment } from "../api/entertainment/Entertainment";
+
+export const ENTERTAINMENT_TITLE_FIELD = "name";
+
+export const EntertainmentTitle = (record: TEntertainment): string => {
+ return record.name?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/index.css b/apps/vesst-discord-bot-backend-admin/src/index.css
new file mode 100644
index 0000000..8686848
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/index.css
@@ -0,0 +1,26 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+#root {
+ height: 100vh;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
+ monospace;
+}
+
+.amp-breadcrumbs {
+ padding: var(--default-spacing);
+}
+
+.entity-id {
+ color: var(--primary);
+ text-decoration: underline;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/index.tsx b/apps/vesst-discord-bot-backend-admin/src/index.tsx
new file mode 100644
index 0000000..2da129c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/index.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import ReactDOM from "react-dom";
+import "./index.css";
+
+import App from "./App";
+import reportWebVitals from "./reportWebVitals";
+
+ReactDOM.render(
+
+
+ ,
+ document.getElementById("root")
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+reportWebVitals();
diff --git a/apps/vesst-discord-bot-backend-admin/src/login.scss b/apps/vesst-discord-bot-backend-admin/src/login.scss
new file mode 100644
index 0000000..667d8d2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/login.scss
@@ -0,0 +1,119 @@
+:root {
+ --surface: #15192c; /*dark: black100 */
+ --white: #15192c; /*dark: black100 */
+
+ --black100: #ffffff; /*dark: white */
+ --black90: #b7bac7; /*dark: black10 */
+ --black80: #a3a8b8; /*dark: black20 */
+ --black60: #80869d; /*dark: black30 */
+ --black40: #686f8c; /*dark: black40 */
+ --black30: #515873; /*dark: black50 */
+ --black20: #444b66; /*dark: black60 */
+ --black10: #373d57; /*dark: black70 */
+ --black5: #2c3249; /*dark: black80 */
+ --black2: #22273c; /*dark: black90 */
+
+ --primary: #7950ed;
+}
+
+.login-page {
+ height: 100vh;
+ width: 100%;
+ background-color: var(--surface);
+ color: var(--black100);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+
+ &__wrapper {
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ flex-direction: row;
+ }
+
+ &__box {
+ text-align: center;
+ width: 340px;
+ background-color: var(--black2);
+ border-radius: var(--small-border-radius);
+ margin: 1rem;
+ padding: 1rem;
+ border: 1px solid var(--black10);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: stretch;
+
+ h2 {
+ font-size: 18px;
+ }
+ img {
+ width: 48px;
+ }
+
+ &__message {
+ color: var(--black80);
+ font-size: 14px;
+ line-height: 22px;
+ }
+
+ button,
+ .MuiButton-contained {
+ box-sizing: border-box;
+ background-color: var(--primary);
+ width: 300px;
+ margin-top: 0.5rem;
+ margin-bottom: 1rem;
+ margin-top: auto;
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: var(--primary);
+ }
+ }
+ }
+
+ form {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 2rem;
+
+ label {
+ span {
+ display: block;
+ text-align: left;
+ font-size: 12px;
+ color: var(--black60);
+ }
+ }
+
+ input {
+ box-sizing: border-box;
+ background-color: var(--white);
+ border: 1px solid var(--black10);
+ padding: 0.5rem;
+ margin-bottom: 1rem;
+ outline: none;
+ border-radius: var(--small-border-radius);
+ width: 300px;
+ color: var(--black100);
+ &:hover,
+ &:active,
+ &:focus {
+ border: 1px solid var(--black100);
+ }
+ }
+ }
+
+ &__read-more {
+ color: var(--black80);
+ a {
+ color: var(--black100);
+ text-decoration: none;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/pages/Dashboard.tsx b/apps/vesst-discord-bot-backend-admin/src/pages/Dashboard.tsx
new file mode 100644
index 0000000..39c4d18
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/pages/Dashboard.tsx
@@ -0,0 +1,12 @@
+import * as React from "react";
+import Card from "@material-ui/core/Card";
+import CardContent from "@material-ui/core/CardContent";
+import { Title } from "react-admin";
+const Dashboard = () => (
+
+
+ Welcome
+
+);
+
+export default Dashboard;
diff --git a/apps/vesst-discord-bot-backend-admin/src/reportWebVitals.ts b/apps/vesst-discord-bot-backend-admin/src/reportWebVitals.ts
new file mode 100644
index 0000000..821a6cd
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/reportWebVitals.ts
@@ -0,0 +1,17 @@
+import { ReportHandler } from "web-vitals";
+
+const reportWebVitals = (onPerfEntry?: ReportHandler): void => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ void import("web-vitals").then(
+ ({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ }
+ );
+ }
+};
+
+export default reportWebVitals;
diff --git a/apps/vesst-discord-bot-backend-admin/src/security/SecurityCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/security/SecurityCreate.tsx
new file mode 100644
index 0000000..86b5d68
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/security/SecurityCreate.tsx
@@ -0,0 +1,35 @@
+import * as React from "react";
+
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ TextInput,
+ DateTimeInput,
+ SelectInput,
+ ReferenceInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const SecurityCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/security/SecurityEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/security/SecurityEdit.tsx
new file mode 100644
index 0000000..a4c4387
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/security/SecurityEdit.tsx
@@ -0,0 +1,35 @@
+import * as React from "react";
+
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ TextInput,
+ DateTimeInput,
+ SelectInput,
+ ReferenceInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const SecurityEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/security/SecurityList.tsx b/apps/vesst-discord-bot-backend-admin/src/security/SecurityList.tsx
new file mode 100644
index 0000000..206e821
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/security/SecurityList.tsx
@@ -0,0 +1,35 @@
+import * as React from "react";
+import {
+ List,
+ Datagrid,
+ ListProps,
+ TextField,
+ DateField,
+ ReferenceField,
+} from "react-admin";
+import Pagination from "../Components/Pagination";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const SecurityList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/security/SecurityShow.tsx b/apps/vesst-discord-bot-backend-admin/src/security/SecurityShow.tsx
new file mode 100644
index 0000000..6e45a97
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/security/SecurityShow.tsx
@@ -0,0 +1,28 @@
+import * as React from "react";
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ TextField,
+ DateField,
+ ReferenceField,
+} from "react-admin";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const SecurityShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/security/SecurityTitle.ts b/apps/vesst-discord-bot-backend-admin/src/security/SecurityTitle.ts
new file mode 100644
index 0000000..7b91fa9
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/security/SecurityTitle.ts
@@ -0,0 +1,7 @@
+import { Security as TSecurity } from "../api/security/Security";
+
+export const SECURITY_TITLE_FIELD = "action";
+
+export const SecurityTitle = (record: TSecurity): string => {
+ return record.action?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/setupTests.ts b/apps/vesst-discord-bot-backend-admin/src/setupTests.ts
new file mode 100644
index 0000000..1dd407a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/setupTests.ts
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import "@testing-library/jest-dom";
diff --git a/apps/vesst-discord-bot-backend-admin/src/slot/SlotCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/slot/SlotCreate.tsx
new file mode 100644
index 0000000..f113118
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/slot/SlotCreate.tsx
@@ -0,0 +1,29 @@
+import * as React from "react";
+
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ NumberInput,
+ TextInput,
+ ReferenceInput,
+ SelectInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const SlotCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/slot/SlotEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/slot/SlotEdit.tsx
new file mode 100644
index 0000000..8324e92
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/slot/SlotEdit.tsx
@@ -0,0 +1,29 @@
+import * as React from "react";
+
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ NumberInput,
+ TextInput,
+ ReferenceInput,
+ SelectInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const SlotEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/slot/SlotList.tsx b/apps/vesst-discord-bot-backend-admin/src/slot/SlotList.tsx
new file mode 100644
index 0000000..ddadcfb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/slot/SlotList.tsx
@@ -0,0 +1,36 @@
+import * as React from "react";
+import {
+ List,
+ Datagrid,
+ ListProps,
+ TextField,
+ DateField,
+ ReferenceField,
+} from "react-admin";
+import Pagination from "../Components/Pagination";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const SlotList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/slot/SlotShow.tsx b/apps/vesst-discord-bot-backend-admin/src/slot/SlotShow.tsx
new file mode 100644
index 0000000..81a2125
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/slot/SlotShow.tsx
@@ -0,0 +1,29 @@
+import * as React from "react";
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ TextField,
+ DateField,
+ ReferenceField,
+} from "react-admin";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const SlotShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/slot/SlotTitle.ts b/apps/vesst-discord-bot-backend-admin/src/slot/SlotTitle.ts
new file mode 100644
index 0000000..3ff48af
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/slot/SlotTitle.ts
@@ -0,0 +1,7 @@
+import { Slot as TSlot } from "../api/slot/Slot";
+
+export const SLOT_TITLE_FIELD = "name";
+
+export const SlotTitle = (record: TSlot): string => {
+ return record.name?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/theme/theme.ts b/apps/vesst-discord-bot-backend-admin/src/theme/theme.ts
new file mode 100644
index 0000000..56a1153
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/theme/theme.ts
@@ -0,0 +1,33 @@
+import { defaultTheme } from "react-admin";
+import { createTheme, ThemeOptions } from "@material-ui/core/styles";
+import { merge } from "lodash";
+import createPalette from "@material-ui/core/styles/createPalette";
+
+const palette = createPalette(
+ merge({}, defaultTheme.palette, {
+ primary: {
+ main: "#20a4f3",
+ },
+ secondary: {
+ main: "#7950ed",
+ },
+ error: {
+ main: "#e93c51",
+ },
+ warning: {
+ main: "#f6aa50",
+ },
+ info: {
+ main: "#144bc1",
+ },
+ success: {
+ main: "#31c587",
+ },
+ })
+);
+
+const themeOptions: ThemeOptions = {
+ palette,
+};
+
+export const theme = createTheme(merge({}, defaultTheme, themeOptions));
diff --git a/apps/vesst-discord-bot-backend-admin/src/ticket/TicketCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketCreate.tsx
new file mode 100644
index 0000000..368f695
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketCreate.tsx
@@ -0,0 +1,44 @@
+import * as React from "react";
+
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ DateTimeInput,
+ TextInput,
+ SelectInput,
+ ReferenceInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const TicketCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/ticket/TicketEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketEdit.tsx
new file mode 100644
index 0000000..61aace0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketEdit.tsx
@@ -0,0 +1,44 @@
+import * as React from "react";
+
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ DateTimeInput,
+ TextInput,
+ SelectInput,
+ ReferenceInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const TicketEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/ticket/TicketList.tsx b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketList.tsx
new file mode 100644
index 0000000..a7c14e2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketList.tsx
@@ -0,0 +1,37 @@
+import * as React from "react";
+import {
+ List,
+ Datagrid,
+ ListProps,
+ DateField,
+ TextField,
+ ReferenceField,
+} from "react-admin";
+import Pagination from "../Components/Pagination";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const TicketList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/ticket/TicketShow.tsx b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketShow.tsx
new file mode 100644
index 0000000..8893b43
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketShow.tsx
@@ -0,0 +1,30 @@
+import * as React from "react";
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ DateField,
+ TextField,
+ ReferenceField,
+} from "react-admin";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const TicketShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/ticket/TicketTitle.ts b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketTitle.ts
new file mode 100644
index 0000000..9a42f71
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/ticket/TicketTitle.ts
@@ -0,0 +1,7 @@
+import { Ticket as TTicket } from "../api/ticket/Ticket";
+
+export const TICKET_TITLE_FIELD = "id";
+
+export const TicketTitle = (record: TTicket): string => {
+ return record.id?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/types.ts b/apps/vesst-discord-bot-backend-admin/src/types.ts
new file mode 100644
index 0000000..45a457d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/types.ts
@@ -0,0 +1,13 @@
+import { JsonValue } from "type-fest";
+
+export type Credentials = {
+ username: string;
+ password: string;
+};
+export type LoginMutateResult = {
+ login: {
+ username: string;
+ accessToken: string;
+ };
+};
+export type InputJsonValue = Omit;
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/EnumRoles.ts b/apps/vesst-discord-bot-backend-admin/src/user/EnumRoles.ts
new file mode 100644
index 0000000..3df7048
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/EnumRoles.ts
@@ -0,0 +1,3 @@
+export enum EnumRoles {
+ User = "user",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/RolesOptions.ts b/apps/vesst-discord-bot-backend-admin/src/user/RolesOptions.ts
new file mode 100644
index 0000000..5e30fe9
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/RolesOptions.ts
@@ -0,0 +1,11 @@
+import { ROLES } from "./roles";
+
+declare interface Role {
+ name: string;
+ displayName: string;
+}
+
+export const ROLES_OPTIONS = ROLES.map((role: Role) => ({
+ value: role.name,
+ label: role.displayName,
+}));
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/UserCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/user/UserCreate.tsx
new file mode 100644
index 0000000..9e7fc7a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/UserCreate.tsx
@@ -0,0 +1,72 @@
+import * as React from "react";
+
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ TextInput,
+ PasswordInput,
+ NumberInput,
+ SelectArrayInput,
+ ReferenceArrayInput,
+} from "react-admin";
+
+import { SecurityTitle } from "../security/SecurityTitle";
+import { SlotTitle } from "../slot/SlotTitle";
+import { TicketTitle } from "../ticket/TicketTitle";
+import { VouchTitle } from "../vouch/VouchTitle";
+import { ROLES_OPTIONS } from "../user/RolesOptions";
+
+export const UserCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/UserEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/user/UserEdit.tsx
new file mode 100644
index 0000000..d1ef5ae
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/UserEdit.tsx
@@ -0,0 +1,72 @@
+import * as React from "react";
+
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ TextInput,
+ PasswordInput,
+ NumberInput,
+ SelectArrayInput,
+ ReferenceArrayInput,
+} from "react-admin";
+
+import { SecurityTitle } from "../security/SecurityTitle";
+import { SlotTitle } from "../slot/SlotTitle";
+import { TicketTitle } from "../ticket/TicketTitle";
+import { VouchTitle } from "../vouch/VouchTitle";
+import { ROLES_OPTIONS } from "../user/RolesOptions";
+
+export const UserEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+
+ value && value.map((v: any) => ({ id: v }))}
+ format={(value: any) => value && value.map((v: any) => v.id)}
+ >
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/UserList.tsx b/apps/vesst-discord-bot-backend-admin/src/user/UserList.tsx
new file mode 100644
index 0000000..b4ed3da
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/UserList.tsx
@@ -0,0 +1,28 @@
+import * as React from "react";
+import { List, Datagrid, ListProps, DateField, TextField } from "react-admin";
+import Pagination from "../Components/Pagination";
+
+export const UserList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/UserShow.tsx b/apps/vesst-discord-bot-backend-admin/src/user/UserShow.tsx
new file mode 100644
index 0000000..0fe7ba5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/UserShow.tsx
@@ -0,0 +1,94 @@
+import * as React from "react";
+
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ DateField,
+ TextField,
+ ReferenceManyField,
+ Datagrid,
+ ReferenceField,
+} from "react-admin";
+
+import { USER_TITLE_FIELD } from "./UserTitle";
+
+export const UserShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/UserTitle.ts b/apps/vesst-discord-bot-backend-admin/src/user/UserTitle.ts
new file mode 100644
index 0000000..336f609
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/UserTitle.ts
@@ -0,0 +1,7 @@
+import { User as TUser } from "../api/user/User";
+
+export const USER_TITLE_FIELD = "firstName";
+
+export const UserTitle = (record: TUser): string => {
+ return record.firstName?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/user/roles.ts b/apps/vesst-discord-bot-backend-admin/src/user/roles.ts
new file mode 100644
index 0000000..732870a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/user/roles.ts
@@ -0,0 +1,6 @@
+export const ROLES = [
+ {
+ name: "user",
+ displayName: "User",
+ },
+];
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/BooleanFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/BooleanFilter.ts
new file mode 100644
index 0000000..a142d58
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/BooleanFilter.ts
@@ -0,0 +1,4 @@
+export class BooleanFilter {
+ equals?: boolean;
+ not?: boolean;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/BooleanNullableFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/BooleanNullableFilter.ts
new file mode 100644
index 0000000..b94aefc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/BooleanNullableFilter.ts
@@ -0,0 +1,4 @@
+export class BooleanNullableFilter {
+ equals?: boolean | null;
+ not?: boolean | null;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/DateTimeFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/DateTimeFilter.ts
new file mode 100644
index 0000000..cd8d213
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/DateTimeFilter.ts
@@ -0,0 +1,10 @@
+export class DateTimeFilter {
+ equals?: Date;
+ not?: Date;
+ in?: Date[];
+ notIn?: Date[];
+ lt?: Date;
+ lte?: Date;
+ gt?: Date;
+ gte?: Date;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/DateTimeNullableFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/DateTimeNullableFilter.ts
new file mode 100644
index 0000000..2f9c7b3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/DateTimeNullableFilter.ts
@@ -0,0 +1,10 @@
+export class DateTimeNullableFilter {
+ equals?: Date | null;
+ in?: Date[] | null;
+ notIn?: Date[] | null;
+ lt?: Date;
+ lte?: Date;
+ gt?: Date;
+ gte?: Date;
+ not?: Date;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/FloatFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/FloatFilter.ts
new file mode 100644
index 0000000..62aeb14
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/FloatFilter.ts
@@ -0,0 +1,10 @@
+export class FloatFilter {
+ equals?: number;
+ in?: number[];
+ notIn?: number[];
+ lt?: number;
+ lte?: number;
+ gt?: number;
+ gte?: number;
+ not?: number;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/FloatNullableFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/FloatNullableFilter.ts
new file mode 100644
index 0000000..d7bb163
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/FloatNullableFilter.ts
@@ -0,0 +1,10 @@
+export class FloatNullableFilter {
+ equals?: number | null;
+ in?: number[] | null;
+ notIn?: number[] | null;
+ lt?: number;
+ lte?: number;
+ gt?: number;
+ gte?: number;
+ not?: number;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/IntFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/IntFilter.ts
new file mode 100644
index 0000000..3dc0221
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/IntFilter.ts
@@ -0,0 +1,10 @@
+export class IntFilter {
+ equals?: number;
+ in?: number[];
+ notIn?: number[];
+ lt?: number;
+ lte?: number;
+ gt?: number;
+ gte?: number;
+ not?: number;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/IntNullableFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/IntNullableFilter.ts
new file mode 100644
index 0000000..2107cae
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/IntNullableFilter.ts
@@ -0,0 +1,10 @@
+export class IntNullableFilter {
+ equals?: number | null;
+ in?: number[] | null;
+ notIn?: number[] | null;
+ lt?: number;
+ lte?: number;
+ gt?: number;
+ gte?: number;
+ not?: number;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/JsonFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/JsonFilter.ts
new file mode 100644
index 0000000..cc44763
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/JsonFilter.ts
@@ -0,0 +1,5 @@
+import { InputJsonValue } from "../types";
+export class JsonFilter {
+ equals?: InputJsonValue;
+ not?: InputJsonValue;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/JsonNullableFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/JsonNullableFilter.ts
new file mode 100644
index 0000000..e6d1506
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/JsonNullableFilter.ts
@@ -0,0 +1,5 @@
+import { JsonValue } from "type-fest";
+export class JsonNullableFilter {
+ equals?: JsonValue | null;
+ not?: JsonValue | null;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/MetaQueryPayload.ts b/apps/vesst-discord-bot-backend-admin/src/util/MetaQueryPayload.ts
new file mode 100644
index 0000000..bc3175b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/MetaQueryPayload.ts
@@ -0,0 +1,3 @@
+export class MetaQueryPayload {
+ count!: number;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/QueryMode.ts b/apps/vesst-discord-bot-backend-admin/src/util/QueryMode.ts
new file mode 100644
index 0000000..8a2164e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/QueryMode.ts
@@ -0,0 +1,4 @@
+export enum QueryMode {
+ Default = "default",
+ Insensitive = "insensitive",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/SortOrder.ts b/apps/vesst-discord-bot-backend-admin/src/util/SortOrder.ts
new file mode 100644
index 0000000..a5bcdb6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/SortOrder.ts
@@ -0,0 +1,4 @@
+export enum SortOrder {
+ Asc = "asc",
+ Desc = "desc",
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/StringFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/StringFilter.ts
new file mode 100644
index 0000000..c2e26c5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/StringFilter.ts
@@ -0,0 +1,16 @@
+import { QueryMode } from "./QueryMode";
+
+export class StringFilter {
+ equals?: string;
+ in?: string[];
+ notIn?: string[];
+ lt?: string;
+ lte?: string;
+ gt?: string;
+ gte?: string;
+ contains?: string;
+ startsWith?: string;
+ endsWith?: string;
+ mode?: QueryMode;
+ not?: string;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/util/StringNullableFilter.ts b/apps/vesst-discord-bot-backend-admin/src/util/StringNullableFilter.ts
new file mode 100644
index 0000000..e1e37ec
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/util/StringNullableFilter.ts
@@ -0,0 +1,15 @@
+import { QueryMode } from "./QueryMode";
+export class StringNullableFilter {
+ equals?: string | null;
+ in?: string[] | null;
+ notIn?: string[] | null;
+ lt?: string;
+ lte?: string;
+ gt?: string;
+ gte?: string;
+ contains?: string;
+ startsWith?: string;
+ endsWith?: string;
+ mode?: QueryMode;
+ not?: string;
+}
diff --git a/apps/vesst-discord-bot-backend-admin/src/vouch/VouchCreate.tsx b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchCreate.tsx
new file mode 100644
index 0000000..7f99ce9
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchCreate.tsx
@@ -0,0 +1,30 @@
+import * as React from "react";
+
+import {
+ Create,
+ SimpleForm,
+ CreateProps,
+ TextInput,
+ DateTimeInput,
+ ReferenceInput,
+ SelectInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const VouchCreate = (props: CreateProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/vouch/VouchEdit.tsx b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchEdit.tsx
new file mode 100644
index 0000000..520fb33
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchEdit.tsx
@@ -0,0 +1,30 @@
+import * as React from "react";
+
+import {
+ Edit,
+ SimpleForm,
+ EditProps,
+ TextInput,
+ DateTimeInput,
+ ReferenceInput,
+ SelectInput,
+} from "react-admin";
+
+import { UserTitle } from "../user/UserTitle";
+
+export const VouchEdit = (props: EditProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/vouch/VouchList.tsx b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchList.tsx
new file mode 100644
index 0000000..9249053
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchList.tsx
@@ -0,0 +1,37 @@
+import * as React from "react";
+import {
+ List,
+ Datagrid,
+ ListProps,
+ TextField,
+ DateField,
+ ReferenceField,
+} from "react-admin";
+import Pagination from "../Components/Pagination";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const VouchList = (props: ListProps): React.ReactElement => {
+ return (
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/vouch/VouchShow.tsx b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchShow.tsx
new file mode 100644
index 0000000..db6a368
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchShow.tsx
@@ -0,0 +1,30 @@
+import * as React from "react";
+import {
+ Show,
+ SimpleShowLayout,
+ ShowProps,
+ TextField,
+ DateField,
+ ReferenceField,
+} from "react-admin";
+import { USER_TITLE_FIELD } from "../user/UserTitle";
+
+export const VouchShow = (props: ShowProps): React.ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/vesst-discord-bot-backend-admin/src/vouch/VouchTitle.ts b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchTitle.ts
new file mode 100644
index 0000000..cfaf0d1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/src/vouch/VouchTitle.ts
@@ -0,0 +1,7 @@
+import { Vouch as TVouch } from "../api/vouch/Vouch";
+
+export const VOUCH_TITLE_FIELD = "badge";
+
+export const VouchTitle = (record: TVouch): string => {
+ return record.badge?.toString() || String(record.id);
+};
diff --git a/apps/vesst-discord-bot-backend-admin/tsconfig.json b/apps/vesst-discord-bot-backend-admin/tsconfig.json
new file mode 100644
index 0000000..31cc780
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-admin/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": true
+ },
+ "include": ["src"],
+ "exclude": ["./node_modules"]
+}
diff --git a/apps/vesst-discord-bot-backend-server/.dockerignore b/apps/vesst-discord-bot-backend-server/.dockerignore
new file mode 100644
index 0000000..cb5c30b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/.dockerignore
@@ -0,0 +1,8 @@
+.dockerignore
+docker-compose.yml
+Dockerfile
+dist/
+node_modules
+.env
+.gitignore
+.prettierignore
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/.env b/apps/vesst-discord-bot-backend-server/.env
new file mode 100644
index 0000000..6973cd8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/.env
@@ -0,0 +1,41 @@
+APP_MODE=both
+BCRYPT_SALT=10
+CA_CERT_PATH=./.certs/ca.crt
+COMPOSE_PROJECT_NAME=amp_cm0ih22ay4z5613ggzef5r9lm
+DB_NAME=my-db
+DB_PASSWORD=admin
+DB_PORT=27017
+DB_URL=mongodb://admin:admin@localhost:27017/my-db?authSource=admin
+DB_USER=admin
+GRPC_CLIENT_URL_PATH=localhost:9090
+HTTPS_PORT=443
+JAEGER_AGENT_HOST=jaeger
+JAEGER_AGENT_PORT=16686
+JWT_EXPIRATION=2d
+JWT_SECRET_KEY=Change_ME!!!
+KAFKA_BROKERS=localhost:9092
+KAFKA_CLIENT_ID=vesst-discord-bot-backend
+KAFKA_ENABLE_SSL=false
+KAFKA_GROUP_ID=vesst-discord-bot-backend
+LOG_LEVEL=info
+LOG_REQUEST=false
+OPENAI_API_KEY=[open-ai-key]
+OTEL_COLLECTOR_HOST=localhost
+OTEL_COLLECTOR_PORT_GRPC=4317
+OTEL_COLLECTOR_PORT_HTTP=4318
+OTEL_EXPORTER_OTLP_ENDPOINT=http://${OTEL_COLLECTOR_HOST}:${OTEL_COLLECTOR_PORT_GRPC}
+PINO_PRETTY=false
+PORT=3000
+REDIS_BROKER_ENABLE_TLS=false
+REDIS_BROKER_HOST=localhost
+REDIS_BROKER_PORT=6379
+REDIS_BROKER_RETRY_ATTEMPTS=3
+REDIS_BROKER_RETRY_DELAY=3
+REDIS_HOST=localhost
+REDIS_PASSWORD=
+REDIS_PORT=6379
+REDIS_TTL=5000
+REDIS_USERNAME=
+SERVICE_NAME=VESSTDiscordBotBackend
+SSL_CERT_PATH=./.certs/server.crt
+SSL_KEY_PATH=./.certs/server.key
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/.gitignore b/apps/vesst-discord-bot-backend-server/.gitignore
new file mode 100644
index 0000000..08c9980
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/.gitignore
@@ -0,0 +1,5 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+/node_modules
+/dist
+.DS_Store
diff --git a/apps/vesst-discord-bot-backend-server/.prettierignore b/apps/vesst-discord-bot-backend-server/.prettierignore
new file mode 100644
index 0000000..e48f355
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/.prettierignore
@@ -0,0 +1,5 @@
+node_modules/
+dist/
+prisma/migrations/
+package-lock.json
+coverage/
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/Dockerfile b/apps/vesst-discord-bot-backend-server/Dockerfile
new file mode 100644
index 0000000..80dd8d3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/Dockerfile
@@ -0,0 +1,68 @@
+# multi-stage: base (build)
+FROM node:18.13.0 AS base
+
+# create directory where the application will be built
+WORKDIR /app
+
+# copy over the dependency manifests, both the package.json
+# and the package-lock.json are copied over
+COPY package*.json ./
+
+# installs packages and their dependencies
+RUN npm install
+
+# copy over the prisma schema
+COPY prisma/schema.prisma ./prisma/
+
+# generate the prisma client based on the schema
+RUN npm run prisma:generate
+
+# copy over the code base
+COPY . .
+
+# create the bundle of the application
+RUN npm run build
+
+# multi-stage: production (runtime)
+FROM node:18.13.0-slim AS production
+
+# create arguments of builds time variables
+ARG user=amplication
+ARG group=${user}
+ARG uid=1001
+ARG gid=$uid
+
+# [temporary] work around to be able to run prisma
+RUN apt-get update -y && apt-get install -y openssl
+
+# create directory where the application will be executed from
+WORKDIR /app
+
+# add the user and group
+RUN groupadd --gid ${gid} ${user}
+RUN useradd --uid ${uid} --gid ${gid} -m ${user}
+
+# copy over the bundled code from the build stage
+COPY --from=base /app/node_modules/ ./node_modules
+COPY --from=base /app/package.json ./package.json
+COPY --from=base /app/dist ./dist
+COPY --from=base /app/prisma ./prisma
+COPY --from=base /app/scripts ./scripts
+COPY --from=base /app/src ./src
+COPY --from=base /app/tsconfig* ./
+
+# change ownership of the workspace directory
+RUN chown -R ${uid}:${gid} /app/
+
+# get rid of the development dependencies
+RUN npm install --production
+
+# set user to the created non-privileged user
+USER ${user}
+
+# expose a specific port on the docker container
+ENV PORT=3000
+EXPOSE ${PORT}
+
+# start the server using the previously build application
+CMD [ "node", "./dist/main.js" ]
diff --git a/apps/vesst-discord-bot-backend-server/README.md b/apps/vesst-discord-bot-backend-server/README.md
new file mode 100644
index 0000000..bca0445
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/README.md
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+# Introduction
+
+This service was generated with Amplication. The server-side of the generated project. This component provides the different backend services - i.e., REST API, GraphQL API, authentication, authorization, logging, data validation and the connection to the database. Additional information about the server component and the architecture around it, can be found on the [documentation](https://docs.amplication.com/guides/getting-started) site.
+
+# Getting started
+
+## Step 1: Configuration
+
+Configuration for the server component can be provided through the use of environment variables. These can be passed to the application via the use of the `.env` file in the base directory of the generated service. Below a table can be found which show the different variables that can be passed - these are the variables which exist by default, through the use of plugins additional integrations could require additional values. These values are provided default values after generation, change them to the desired values.
+
+| Variable | Description | Value |
+| -------------------- | -------------------------------------------- | ------------------------------------------------------------------- |
+| BCRYPT_SALT | the string used for hashing | [random-string] |
+| COMPOSE_PROJECT_NAME | the identifier of the service plus prefix | amp_[service-identifier] |
+| PORT | the port on which to run the server | 3000 |
+| DB_URL | the connection url for the database | [db-provider]://[username]:[password]@localhost:[db-port]/[db-name] |
+| DB_PORT | the port used by the database instance | [db-provider-port] |
+| DB_USER | the username used to connect to the database | [username] |
+| DB_PASSWORD | the password used to connect to the database | [password] |
+| DB_NAME | the name of the database | [service-name] / [project-name] |
+| JWT_SECRET_KEY | the secret used to sign the json-web token | [secret] |
+| JWT_EXPIRATION | the expiration time for the json-web token | 2d |
+
+> **Note**
+> Amplication generates default values and stores them under the .env file. It is advised to use some form of secrets manager/vault solution when using in production.
+
+## Step 2.1: Scripts - pre-requisites
+
+After configuration of the server the next step would be to run the application. Before running the server side of the component, make sure that the different pre-requisites are met - i.e., node.js [^16.x], npm, docker. After the setup of the pre-requisites the server component can be started.
+
+```sh
+# installation of the dependencies
+$ npm install
+
+# generate the prisma client
+$ npm run prisma:generate
+```
+
+## Step 2.2: Scripts - local development
+
+```sh
+# start the database where the server component will connect to
+$ npm run docker:dev
+
+# initialize the database
+$ npm run db:init
+
+# start the server component
+$ npm run start
+```
+By default, your app comes with one user with the username "admin" and password "admin".
+
+## Step 2.2: Scripts - container based development
+
+```shell
+# start the server component as a docker container
+$ npm run compose:up
+```
diff --git a/apps/vesst-discord-bot-backend-server/docker-compose.dev.yml b/apps/vesst-discord-bot-backend-server/docker-compose.dev.yml
new file mode 100644
index 0000000..b507d94
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/docker-compose.dev.yml
@@ -0,0 +1,107 @@
+version: "3"
+services:
+ db:
+ image: mongo
+ ports:
+ - ${DB_PORT}:27017
+ environment:
+ POSTGRES_USER: ${DB_USER}
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ MONGO_INITDB_ROOT_USERNAME: ${DB_USER}
+ MONGO_INITDB_ROOT_PASSWORD: ${DB_PASSWORD}
+ MONGO_INITDB_DATABASE: ${DB_NAME}
+ MONGO_REPLICA_SET_NAME: rs0
+ volumes:
+ - mongo:/var/lib/mongosql/data
+ restart: always
+ entrypoint:
+ - /bin/bash
+ - -c
+ - openssl rand -base64 741 > /data/cert.crt; chmod 400 /data/cert.crt &&
+ chown 999 /data/cert.crt; /usr/local/bin/docker-entrypoint.sh mongod
+ --bind_ip_all --keyFile /data/cert.crt --replSet rs0
+ healthcheck:
+ test: "test $$(mongosh --quiet -u $${MONGO_INITDB_ROOT_USERNAME} -p
+ $${MONGO_INITDB_ROOT_PASSWORD} --eval \"try { rs.initiate({ _id:
+ '\"rs0\"',members: [{ _id: 0, host: '\"localhost\"' }] }).ok } catch (_)
+ { rs.status().ok}\") -eq 1"
+ start_period: 5s
+ interval: 10s
+ timeout: 10s
+ zookeeper:
+ image: confluentinc/cp-zookeeper:5.2.4
+ environment:
+ ZOOKEEPER_CLIENT_PORT: 2181
+ ZOOKEEPER_TICK_TIME: 2000
+ ports:
+ - 2181:2181
+ kafka:
+ image: confluentinc/cp-kafka:7.3.1
+ depends_on:
+ - zookeeper
+ ports:
+ - 9092:9092
+ - 9997:9997
+ environment:
+ KAFKA_BROKER_ID: 1
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
+ KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
+ KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+ KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
+ KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
+ kafka-ui:
+ container_name: kafka-ui
+ image: provectuslabs/kafka-ui:latest
+ ports:
+ - 8080:8080
+ depends_on:
+ - zookeeper
+ - kafka
+ environment:
+ KAFKA_CLUSTERS_0_NAME: local
+ KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
+ KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181
+ KAFKA_CLUSTERS_0_JMXPORT: 9997
+ jaeger:
+ image: jaegertracing/all-in-one:latest
+ ports:
+ - ${JAEGER_AGENT_PORT}:${JAEGER_AGENT_PORT}
+ - 14268:14268
+ - 14250:4317
+ opentelemetry:
+ image: otel/opentelemetry-collector:latest
+ ports:
+ - ${OTEL_COLLECTOR_PORT_GRPC}:${OTEL_COLLECTOR_PORT_GRPC}
+ - ${OTEL_COLLECTOR_PORT_HTTP}:${OTEL_COLLECTOR_PORT_HTTP}
+ - 1888:1888
+ - 13133:13133
+ - 55670:55679
+ volumes:
+ - ./otel-config.yml:/etc/otel-config.yml
+ command:
+ - --config=/etc/otel-config.yml
+ depends_on:
+ - jaeger
+ redis:
+ container_name: ${REDIS_HOST}
+ image: redis:7
+ ports:
+ - ${REDIS_PORT}:6379
+ volumes:
+ - redis:/data
+ redis_broker:
+ container_name: ${REDIS_BROKER_HOST}
+ image: redis:7
+ ports:
+ - ${REDIS_BROKER_PORT}:6379
+ volumes:
+ - redis_broker:/redis-broker-data
+volumes:
+ postgres: ~
+ mongo: ~
+ redis:
+ driver: local
+ redis_broker:
+ driver: local
diff --git a/apps/vesst-discord-bot-backend-server/docker-compose.yml b/apps/vesst-discord-bot-backend-server/docker-compose.yml
new file mode 100644
index 0000000..8bf0814
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/docker-compose.yml
@@ -0,0 +1,149 @@
+version: "3"
+services:
+ server:
+ build:
+ context: .
+ args:
+ NPM_LOG_LEVEL: notice
+ ports:
+ - ${PORT}:3000
+ environment:
+ BCRYPT_SALT: ${BCRYPT_SALT}
+ DB_URL: mongodb://${DB_USER}:${DB_PASSWORD}@db:27017/${DB_NAME}?authSource=admin
+ LOG_LEVEL: ${LOG_LEVEL}
+ SERVICE_NAME: ${SERVICE_NAME}
+ JWT_SECRET_KEY: ${JWT_SECRET_KEY}
+ JWT_EXPIRATION: ${JWT_EXPIRATION}
+ KAFKA_BROKERS: kafka:9092
+ KAFKA_ENABLE_SSL: ${KAFKA_ENABLE_SSL}
+ KAFKA_CLIENT_ID: ${KAFKA_CLIENT_ID}
+ KAFKA_GROUP_ID: ${KAFKA_GROUP_ID}
+ JAEGER_AGENT_HOST: ${JAEGER_AGENT_HOST}
+ JAEGER_AGENT_PORT: ${JAEGER_AGENT_PORT}
+ OTEL_COLLECTOR_HOST: ${OTEL_COLLECTOR_HOST}
+ OTEL_COLLECTOR_PORT_GRPC: ${OTEL_COLLECTOR_PORT_GRPC}
+ OTEL_COLLECTOR_PORT_HTTP: ${OTEL_COLLECTOR_PORT_HTTP}
+ OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT}
+ depends_on:
+ - redis_broker
+ restart: on-failure
+ migrate:
+ build:
+ context: .
+ args:
+ NPM_LOG_LEVEL: notice
+ command: npm run db:init
+ working_dir: /app/server
+ environment:
+ BCRYPT_SALT: ${BCRYPT_SALT}
+ DB_URL: mongodb://${DB_USER}:${DB_PASSWORD}@db:27017/${DB_NAME}?authSource=admin
+ depends_on:
+ db:
+ condition: service_healthy
+ db:
+ image: mongo
+ ports:
+ - ${DB_PORT}:27017
+ environment:
+ POSTGRES_USER: ${DB_USER}
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ POSTGRES_DB: ${DB_NAME}
+ MONGO_INITDB_ROOT_USERNAME: ${DB_USER}
+ MONGO_INITDB_ROOT_PASSWORD: ${DB_PASSWORD}
+ MONGO_INITDB_DATABASE: ${DB_NAME}
+ MONGO_REPLICA_SET_NAME: rs0
+ volumes:
+ - mongo:/var/lib/mongosql/data
+ healthcheck:
+ test: "test $$(mongosh --quiet -u $${MONGO_INITDB_ROOT_USERNAME} -p
+ $${MONGO_INITDB_ROOT_PASSWORD} --eval \"try { rs.initiate({ _id:
+ 'rs0',members: [{ _id: 0, host: 'db' }] }).ok } catch (_) {
+ rs.status().ok}\") -eq 1"
+ timeout: 10s
+ interval: 10s
+ retries: 10
+ start_period: 5s
+ restart: always
+ entrypoint:
+ - /bin/bash
+ - -c
+ - openssl rand -base64 741 > /data/cert.crt; chmod 400 /data/cert.crt &&
+ chown 999 /data/cert.crt; /usr/local/bin/docker-entrypoint.sh mongod
+ --bind_ip_all --keyFile /data/cert.crt --replSet rs0
+ zookeeper:
+ image: confluentinc/cp-zookeeper:5.2.4
+ environment:
+ ZOOKEEPER_CLIENT_PORT: 2181
+ ZOOKEEPER_TICK_TIME: 2000
+ ports:
+ - 2181:2181
+ kafka:
+ image: confluentinc/cp-kafka:7.3.1
+ depends_on:
+ - zookeeper
+ ports:
+ - 9092:9092
+ - 9997:9997
+ environment:
+ KAFKA_BROKER_ID: 1
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://kafka:9092
+ KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
+ KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+ KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
+ KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
+ kafka-ui:
+ container_name: kafka-ui
+ image: provectuslabs/kafka-ui:latest
+ ports:
+ - 8080:8080
+ depends_on:
+ - zookeeper
+ - kafka
+ environment:
+ KAFKA_CLUSTERS_0_NAME: local
+ KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
+ KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181
+ KAFKA_CLUSTERS_0_JMXPORT: 9997
+ jaeger:
+ image: jaegertracing/all-in-one:latest
+ ports:
+ - ${JAEGER_AGENT_PORT}:${JAEGER_AGENT_PORT}
+ - 14268:14268
+ - 14250:4317
+ opentelemetry:
+ image: otel/opentelemetry-collector:latest
+ ports:
+ - ${OTEL_COLLECTOR_PORT_GRPC}:${OTEL_COLLECTOR_PORT_GRPC}
+ - ${OTEL_COLLECTOR_PORT_HTTP}:${OTEL_COLLECTOR_PORT_HTTP}
+ - 1888:1888
+ - 13133:13133
+ - 55670:55679
+ volumes:
+ - ./otel-config.yml:/etc/otel-config.yml
+ command:
+ - --config=/etc/otel-config.yml
+ depends_on:
+ - jaeger
+ redis:
+ container_name: ${REDIS_HOST}
+ image: redis:7
+ ports:
+ - ${REDIS_PORT}:6379
+ volumes:
+ - redis:/data
+ redis_broker:
+ container_name: ${REDIS_BROKER_HOST}
+ image: redis:7
+ ports:
+ - ${REDIS_BROKER_PORT}:6379
+ volumes:
+ - redis_broker:/redis-broker-data
+volumes:
+ postgres: ~
+ mongo: ~
+ redis:
+ driver: local
+ redis_broker:
+ driver: local
diff --git a/apps/vesst-discord-bot-backend-server/nest-cli.json b/apps/vesst-discord-bot-backend-server/nest-cli.json
new file mode 100644
index 0000000..b7b60ae
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/nest-cli.json
@@ -0,0 +1,10 @@
+{
+ "sourceRoot": "src",
+ "compilerOptions": {
+ "assets": [
+ {
+ "include": "swagger/**/*"
+ }
+ ]
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/otel-config.yml b/apps/vesst-discord-bot-backend-server/otel-config.yml
new file mode 100644
index 0000000..54047c1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/otel-config.yml
@@ -0,0 +1,36 @@
+receivers:
+ otlp:
+ protocols:
+ http:
+ endpoint: 0.0.0.0:4318
+ grpc:
+ endpoint: 0.0.0.0:4317
+processors:
+ batch:
+ timeout: 1s
+ resource:
+ attributes:
+ - key: test.key
+ value: "test-value"
+ action: insert
+exporters:
+ debug:
+ verbosity: detailed
+ otlp/jaeger:
+ endpoint: jaeger:4317 # This is the default port for Jaeger
+ tls:
+ insecure: true
+
+extensions:
+ health_check:
+ pprof:
+ endpoint: :1888
+ zpages:
+ endpoint: :55679
+service:
+ extensions: [pprof, zpages, health_check]
+ pipelines:
+ traces:
+ receivers: [otlp]
+ processors: [batch, resource]
+ exporters: [debug, otlp/jaeger]
diff --git a/apps/vesst-discord-bot-backend-server/package.json b/apps/vesst-discord-bot-backend-server/package.json
new file mode 100644
index 0000000..243acc5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/package.json
@@ -0,0 +1,92 @@
+{
+ "name": "@vesst-discord-bot-backend/server",
+ "private": true,
+ "scripts": {
+ "start": "nest start",
+ "start:watch": "nest start --watch",
+ "start:debug": "nest start --debug --watch",
+ "build": "nest build",
+ "test": "jest",
+ "seed": "ts-node scripts/seed.ts",
+ "db:migrate-save": "prisma migrate dev",
+ "db:migrate-up": "prisma migrate deploy",
+ "db:clean": "prisma migrate reset",
+ "db:init": "run-s seed",
+ "prisma:generate": "prisma generate",
+ "docker:dev": "docker-compose -f docker-compose.dev.yml up -d",
+ "package:container": "docker build .",
+ "compose:up": "docker-compose up -d",
+ "compose:down": "docker-compose down --volumes",
+ "ssl:generate": "./scripts/generate-ssl.sh",
+ "prisma:pull": "prisma db pull",
+ "prisma:push": " prisma db push"
+ },
+ "dependencies": {
+ "@amplication/opentelemetry-nestjs": "^4.5.0",
+ "@apollo/server": "^4.9.4",
+ "@grpc/grpc-js": "^1.9.3",
+ "@grpc/proto-loader": "^0.7.10",
+ "@nestjs/apollo": "12.0.9",
+ "@nestjs/cache-manager": "^2.1.0",
+ "@nestjs/common": "10.2.7",
+ "@nestjs/config": "3.1.1",
+ "@nestjs/core": "10.2.7",
+ "@nestjs/graphql": "12.0.9",
+ "@nestjs/jwt": "^10.1.1",
+ "@nestjs/microservices": "10.2.7",
+ "@nestjs/passport": "^10.0.2",
+ "@nestjs/platform-express": "10.2.7",
+ "@nestjs/serve-static": "4.0.0",
+ "@nestjs/swagger": "7.1.13",
+ "@prisma/client": "^5.4.2",
+ "@types/bcrypt": "5.0.0",
+ "bcrypt": "5.1.1",
+ "cache-manager": "5.2.4",
+ "cache-manager-ioredis-yet": "^1.2.2",
+ "class-transformer": "0.5.1",
+ "class-validator": "0.14.0",
+ "dotenv": "16.3.1",
+ "graphql": "^16.8.1",
+ "graphql-type-json": "0.3.2",
+ "ioredis": "^5.3.2",
+ "kafkajs": "^2.2.4",
+ "nest-access-control": "^3.1.0",
+ "nestjs-pino": "^3.5.0",
+ "npm-run-all": "4.1.5",
+ "openai": "^4.24.7",
+ "passport": "0.6.0",
+ "passport-http": "0.3.0",
+ "passport-jwt": "4.0.1",
+ "reflect-metadata": "0.1.13",
+ "ts-node": "10.9.2",
+ "type-fest": "2.19.0",
+ "validator": "13.11.0"
+ },
+ "devDependencies": {
+ "@nestjs/cli": "^10.1.18",
+ "@nestjs/testing": "^10.2.7",
+ "@types/cache-manager": "4.0.4",
+ "@types/express": "^4.17.19",
+ "@types/graphql-type-json": "0.3.3",
+ "@types/jest": "^29.5.5",
+ "@types/normalize-path": "3.0.0",
+ "@types/passport-http": "0.3.9",
+ "@types/passport-jwt": "3.0.10",
+ "@types/supertest": "^2.0.14",
+ "@types/validator": "^13.11.2",
+ "jest": "^29.7.0",
+ "jest-mock-extended": "^3.0.5",
+ "prisma": "^5.4.2",
+ "supertest": "^6.3.3",
+ "ts-jest": "^29.1.1",
+ "typescript": "^5.4.3"
+ },
+ "jest": {
+ "preset": "ts-jest",
+ "testEnvironment": "node",
+ "moduleNameMapper": {
+ "@app/custom-validators": "/src/validators"
+ },
+ "modulePathIgnorePatterns": ["/dist/"]
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/prisma/schema.prisma b/apps/vesst-discord-bot-backend-server/prisma/schema.prisma
new file mode 100644
index 0000000..fb0380e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/prisma/schema.prisma
@@ -0,0 +1,111 @@
+datasource db {
+ provider = "mongodb"
+ url = env("DB_URL")
+}
+
+generator client {
+ provider = "prisma-client-js"
+}
+
+model Slot {
+ bid Float?
+ createdAt DateTime @default(now())
+ description String?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ metrics Json?
+ name String?
+ updatedAt DateTime @updatedAt
+ user User? @relation(fields: [userId], references: [id])
+ userId String? @db.ObjectId
+}
+
+model Vouch {
+ badge String?
+ category String?
+ challenge String?
+ createdAt DateTime @default(now())
+ date DateTime?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ updatedAt DateTime @updatedAt
+ user User? @relation(fields: [userId], references: [id])
+ userId String? @db.ObjectId
+ vouchText String?
+}
+
+model Embed {
+ color String?
+ createdAt DateTime @default(now())
+ dateCreated DateTime?
+ description String?
+ footer String?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ title String?
+ updatedAt DateTime @updatedAt
+}
+
+model Ticket {
+ createdAt DateTime @default(now())
+ dateClosed DateTime?
+ dateCreated DateTime?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ issue String?
+ priority EnumTicketPriority?
+ status EnumTicketStatus?
+ updatedAt DateTime @updatedAt
+ user User? @relation(fields: [userId], references: [id])
+ userId String? @db.ObjectId
+}
+
+model Security {
+ action String?
+ createdAt DateTime @default(now())
+ date DateTime?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ status EnumSecurityStatus?
+ updatedAt DateTime @updatedAt
+ user User? @relation(fields: [userId], references: [id])
+ userId String? @db.ObjectId
+}
+
+model Entertainment {
+ createdAt DateTime @default(now())
+ details Json?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ name String?
+ typeField EnumEntertainmentTypeField?
+ updatedAt DateTime @updatedAt
+}
+
+model User {
+ createdAt DateTime @default(now())
+ discordId String?
+ email String? @unique
+ firstName String?
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ lastName String?
+ password String
+ reputation Int?
+ roles Json
+ securities Security[]
+ slots Slot[]
+ tickets Ticket[]
+ updatedAt DateTime @updatedAt
+ username String @unique
+ vouches Vouch[]
+}
+
+enum EnumTicketPriority {
+ Option1
+}
+
+enum EnumTicketStatus {
+ Option1
+}
+
+enum EnumSecurityStatus {
+ Option1
+}
+
+enum EnumEntertainmentTypeField {
+ Option1
+}
diff --git a/apps/vesst-discord-bot-backend-server/scripts/customSeed.ts b/apps/vesst-discord-bot-backend-server/scripts/customSeed.ts
new file mode 100644
index 0000000..6baf5f6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/scripts/customSeed.ts
@@ -0,0 +1,17 @@
+import { PrismaClient } from "@prisma/client";
+
+export async function customSeed() {
+ const client = new PrismaClient();
+ const username = "admin";
+
+ //replace this sample code to populate your database
+ //with data that is required for your service to start
+ await client.user.update({
+ where: { username: username },
+ data: {
+ username,
+ },
+ });
+
+ client.$disconnect();
+}
diff --git a/apps/vesst-discord-bot-backend-server/scripts/generate-ssl.sh b/apps/vesst-discord-bot-backend-server/scripts/generate-ssl.sh
new file mode 100644
index 0000000..927b8b1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/scripts/generate-ssl.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# Generate a self-signed certificate for the server to be used in development over HTTPS for local testing.
+# !!! DO NOT USE THIS IN PRODUCTION !!!
+
+certificates_dir="./.certs"
+certificates_file="server.crt"
+key_file="server.key"
+ca_key_file="ca.key"
+ca_cert_file="ca.crt"
+
+# Create the certificates directory if it doesn't exist
+if [ ! -d "$certificates_dir" ]; then
+ mkdir "$certificates_dir"
+fi
+
+# Generate the CA key and certificate
+openssl genrsa -out "$certificates_dir/$ca_key_file" 2048
+openssl req -x509 -new -nodes -key "$certificates_dir/$ca_key_file" -sha256 -days 1825 -out "$certificates_dir/$ca_cert_file" < {
+ console.error(error);
+ process.exit(1);
+ });
+}
+
+async function seed(bcryptSalt: Salt) {
+ console.info("Seeding database...");
+
+ const client = new PrismaClient();
+
+ const data = {
+ username: "admin",
+ password: await hash("admin", bcryptSalt),
+ roles: ["user"],
+ };
+
+ await client.user.upsert({
+ where: {
+ username: data.username,
+ },
+
+ update: {},
+ create: data,
+ });
+
+ void client.$disconnect();
+
+ console.info("Seeding database with custom seed...");
+ customSeed();
+
+ console.info("Seeded database successfully");
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/app.module.ts b/apps/vesst-discord-bot-backend-server/src/app.module.ts
new file mode 100644
index 0000000..cf968ef
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/app.module.ts
@@ -0,0 +1,126 @@
+import { Module } from "@nestjs/common";
+
+import {
+ OpenTelemetryModule,
+ PipeInjector,
+ ControllerInjector,
+ EventEmitterInjector,
+ GraphQLResolverInjector,
+ GuardInjector,
+} from "@amplication/opentelemetry-nestjs";
+
+import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
+import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
+import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
+import { CacheModule } from "@nestjs/cache-manager";
+import { redisStore } from "cache-manager-ioredis-yet";
+import { RedisModule } from "./redis/redis.module";
+import { SlotModule } from "./slot/slot.module";
+import { VouchModule } from "./vouch/vouch.module";
+import { EmbedModule } from "./embed/embed.module";
+import { TicketModule } from "./ticket/ticket.module";
+import { SecurityModule } from "./security/security.module";
+import { EntertainmentModule } from "./entertainment/entertainment.module";
+import { UserModule } from "./user/user.module";
+import { AuthenticationModule } from "./authentication/authentication.module";
+import { HealthModule } from "./health/health.module";
+import { PrismaModule } from "./prisma/prisma.module";
+import { SecretsManagerModule } from "./providers/secrets/secretsManager.module";
+import { KafkaModule } from "./redis/kafka.module";
+import { ServeStaticModule } from "@nestjs/serve-static";
+import { ServeStaticOptionsService } from "./serveStaticOptions.service";
+import { ConfigModule, ConfigService } from "@nestjs/config";
+import { GraphQLModule } from "@nestjs/graphql";
+import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
+
+import { LoggerModule } from "./logger/logger.module";
+
+import { ACLModule } from "./auth/acl.module";
+import { AuthModule } from "./auth/auth.module";
+
+@Module({
+ controllers: [],
+ imports: [
+ ACLModule,
+ AuthModule,
+ KafkaModule,
+ LoggerModule,
+ SlotModule,
+ VouchModule,
+ EmbedModule,
+ TicketModule,
+ SecurityModule,
+ EntertainmentModule,
+ UserModule,
+ AuthenticationModule,
+ HealthModule,
+ PrismaModule,
+ SecretsManagerModule,
+ ConfigModule.forRoot({ isGlobal: true }),
+ ServeStaticModule.forRootAsync({
+ useClass: ServeStaticOptionsService,
+ }),
+ GraphQLModule.forRootAsync({
+ driver: ApolloDriver,
+ useFactory: (configService: ConfigService) => {
+ const playground = configService.get("GRAPHQL_PLAYGROUND");
+ const introspection = configService.get("GRAPHQL_INTROSPECTION");
+ return {
+ autoSchemaFile: "schema.graphql",
+ sortSchema: true,
+ playground,
+ introspection: playground || introspection,
+ };
+ },
+ inject: [ConfigService],
+ imports: [ConfigModule],
+ }),
+ OpenTelemetryModule.forRoot({
+ serviceName: "VESSTDiscordBotBackend",
+ spanProcessor: new BatchSpanProcessor(new OTLPTraceExporter()),
+ instrumentations: [
+ new HttpInstrumentation({
+ requestHook: (span, request) => {
+ if (request.method)
+ span.setAttribute("http.method", request.method);
+ },
+ }),
+ ],
+
+ traceAutoInjectors: [
+ ControllerInjector,
+ EventEmitterInjector,
+ GraphQLResolverInjector,
+ GuardInjector,
+ PipeInjector,
+ ],
+ }),
+ CacheModule.registerAsync({
+ isGlobal: true,
+ imports: [ConfigModule],
+
+ useFactory: async (configService: ConfigService) => {
+ const host = configService.get("REDIS_HOST");
+ const port = configService.get("REDIS_PORT");
+ const username = configService.get("REDIS_USERNAME");
+ const password = configService.get("REDIS_PASSWORD");
+ const ttl = configService.get("REDIS_TTL", 5000);
+
+ return {
+ store: await redisStore({
+ host: host,
+ port: port,
+ username: username,
+ password: password,
+ ttl: ttl,
+ }),
+ };
+ },
+
+ inject: [ConfigService],
+ }),
+ RedisModule,
+ ],
+ providers: [],
+})
+export class AppModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/Credentials.ts b/apps/vesst-discord-bot-backend-server/src/auth/Credentials.ts
new file mode 100644
index 0000000..9ac6798
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/Credentials.ts
@@ -0,0 +1,21 @@
+import { ApiProperty } from "@nestjs/swagger";
+import { InputType, Field } from "@nestjs/graphql";
+import { IsString } from "class-validator";
+
+@InputType()
+export class Credentials {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String, { nullable: false })
+ username!: string;
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String, { nullable: false })
+ password!: string;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/IAuthStrategy.ts b/apps/vesst-discord-bot-backend-server/src/auth/IAuthStrategy.ts
new file mode 100644
index 0000000..7406267
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/IAuthStrategy.ts
@@ -0,0 +1,6 @@
+import { UserInfo } from "./UserInfo";
+
+export interface IAuthStrategy {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ validate: (...any: any) => Promise;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/ITokenService.ts b/apps/vesst-discord-bot-backend-server/src/auth/ITokenService.ts
new file mode 100644
index 0000000..7983189
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/ITokenService.ts
@@ -0,0 +1,9 @@
+export interface ITokenPayload {
+ id: string;
+ username: string;
+ password: string;
+}
+
+export interface ITokenService {
+ createToken: ({ id, username, password }: ITokenPayload) => Promise;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/LoginArgs.ts b/apps/vesst-discord-bot-backend-server/src/auth/LoginArgs.ts
new file mode 100644
index 0000000..66a0b2f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/LoginArgs.ts
@@ -0,0 +1,12 @@
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { Credentials } from "./Credentials";
+
+@ArgsType()
+export class LoginArgs {
+ @Field(() => Credentials, { nullable: false })
+ @Type(() => Credentials)
+ @ValidateNested()
+ credentials!: Credentials;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/UserInfo.ts b/apps/vesst-discord-bot-backend-server/src/auth/UserInfo.ts
new file mode 100644
index 0000000..ef61dc4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/UserInfo.ts
@@ -0,0 +1,14 @@
+import { Field, ObjectType } from "@nestjs/graphql";
+import { User } from "../user/base/User";
+
+@ObjectType()
+export class UserInfo implements Partial {
+ @Field(() => String)
+ id!: string;
+ @Field(() => String)
+ username!: string;
+ @Field(() => [String])
+ roles!: string[];
+ @Field(() => String, { nullable: true })
+ accessToken?: string;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/abac.util.ts b/apps/vesst-discord-bot-backend-server/src/auth/abac.util.ts
new file mode 100644
index 0000000..2f0dcab
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/abac.util.ts
@@ -0,0 +1,19 @@
+import { Permission } from "accesscontrol";
+
+/**
+ * @returns attributes not allowed to appear on given data according to given
+ * attributeMatchers
+ */
+export function getInvalidAttributes(
+ permission: Permission,
+ // eslint-disable-next-line @typescript-eslint/ban-types
+ data: Object
+): string[] {
+ // The structuredClone call is necessary because the
+ // `Permission.filter` function doesn't consider objects
+ // with null prototypes. And in graphql requests, the
+ // object passed here by the request interceptor is an object
+ // with a null prototype.
+ const filteredData = permission.filter(structuredClone(data));
+ return Object.keys(data).filter((key) => !(key in filteredData));
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/acl.module.ts b/apps/vesst-discord-bot-backend-server/src/auth/acl.module.ts
new file mode 100644
index 0000000..040e7e5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/acl.module.ts
@@ -0,0 +1,6 @@
+import { AccessControlModule, RolesBuilder } from "nest-access-control";
+
+import grants from "../grants.json";
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export const ACLModule = AccessControlModule.forRoles(new RolesBuilder(grants));
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/auth.controller.ts b/apps/vesst-discord-bot-backend-server/src/auth/auth.controller.ts
new file mode 100644
index 0000000..7ae732f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/auth.controller.ts
@@ -0,0 +1,15 @@
+import { Body, Controller, Post } from "@nestjs/common";
+import { ApiTags } from "@nestjs/swagger";
+import { AuthService } from "./auth.service";
+import { Credentials } from "../auth/Credentials";
+import { UserInfo } from "./UserInfo";
+
+@ApiTags("auth")
+@Controller()
+export class AuthController {
+ constructor(private readonly authService: AuthService) {}
+ @Post("login")
+ async login(@Body() body: Credentials): Promise {
+ return this.authService.login(body);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/auth.module.ts b/apps/vesst-discord-bot-backend-server/src/auth/auth.module.ts
new file mode 100644
index 0000000..d69fd95
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/auth.module.ts
@@ -0,0 +1,57 @@
+import { forwardRef, Module } from "@nestjs/common";
+import { ConfigService } from "@nestjs/config";
+import { JwtModule } from "@nestjs/jwt";
+import { PassportModule } from "@nestjs/passport";
+import { JWT_EXPIRATION } from "../constants";
+import { SecretsManagerModule } from "../providers/secrets/secretsManager.module";
+import { SecretsManagerService } from "../providers/secrets/secretsManager.service";
+import { EnumSecretsNameKey } from "../providers/secrets/secretsNameKey.enum";
+import { AuthController } from "./auth.controller";
+import { AuthResolver } from "./auth.resolver";
+import { AuthService } from "./auth.service";
+import { JwtStrategy } from "./jwt/jwt.strategy";
+import { jwtSecretFactory } from "./jwt/jwtSecretFactory";
+import { PasswordService } from "./password.service";
+import { TokenService } from "./token.service";
+import { UserModule } from "../user/user.module";
+@Module({
+ imports: [
+ forwardRef(() => UserModule),
+ PassportModule,
+ SecretsManagerModule,
+ JwtModule.registerAsync({
+ imports: [SecretsManagerModule],
+ inject: [SecretsManagerService, ConfigService],
+ useFactory: async (
+ secretsService: SecretsManagerService,
+ configService: ConfigService
+ ) => {
+ const secret = await secretsService.getSecret(
+ EnumSecretsNameKey.JwtSecretKey
+ );
+ const expiresIn = configService.get(JWT_EXPIRATION);
+ if (!secret) {
+ throw new Error("Didn't get a valid jwt secret");
+ }
+ if (!expiresIn) {
+ throw new Error("Jwt expire in value is not valid");
+ }
+ return {
+ secret: secret,
+ signOptions: { expiresIn },
+ };
+ },
+ }),
+ ],
+ providers: [
+ AuthService,
+ PasswordService,
+ AuthResolver,
+ JwtStrategy,
+ jwtSecretFactory,
+ TokenService,
+ ],
+ controllers: [AuthController],
+ exports: [AuthService, PasswordService],
+})
+export class AuthModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/auth.resolver.ts b/apps/vesst-discord-bot-backend-server/src/auth/auth.resolver.ts
new file mode 100644
index 0000000..c186f41
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/auth.resolver.ts
@@ -0,0 +1,23 @@
+import * as common from "@nestjs/common";
+import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
+import * as gqlACGuard from "../auth/gqlAC.guard";
+import { AuthService } from "./auth.service";
+import { GqlDefaultAuthGuard } from "./gqlDefaultAuth.guard";
+import { UserData } from "./userData.decorator";
+import { LoginArgs } from "./LoginArgs";
+import { UserInfo } from "./UserInfo";
+
+@Resolver(UserInfo)
+export class AuthResolver {
+ constructor(private readonly authService: AuthService) {}
+ @Mutation(() => UserInfo)
+ async login(@Args() args: LoginArgs): Promise {
+ return this.authService.login(args.credentials);
+ }
+
+ @Query(() => UserInfo)
+ @common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+ async userInfo(@UserData() entityInfo: UserInfo): Promise {
+ return entityInfo;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/auth.service.spec.ts b/apps/vesst-discord-bot-backend-server/src/auth/auth.service.spec.ts
new file mode 100644
index 0000000..90b04f4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/auth.service.spec.ts
@@ -0,0 +1,114 @@
+import { Test, TestingModule } from "@nestjs/testing";
+import { AuthService } from "./auth.service";
+import { Credentials } from "./Credentials";
+import { PasswordService } from "./password.service";
+import { TokenService } from "./token.service";
+import { VALID_ID } from "../tests/auth/constants";
+import { UserService } from "../user/user.service";
+
+const VALID_CREDENTIALS: Credentials = {
+ username: "Valid User",
+ password: "Valid User Password",
+};
+const INVALID_CREDENTIALS: Credentials = {
+ username: "Invalid User",
+ password: "Invalid User Password",
+};
+const USER: any = {
+ ...VALID_CREDENTIALS,
+ createdAt: new Date(),
+ firstName: "ofek",
+ id: VALID_ID,
+ lastName: "gabay",
+ roles: ["admin"],
+ updatedAt: new Date(),
+};
+
+const SIGN_TOKEN = "SIGN_TOKEN";
+
+const authEntityService = {
+ user(args: { where: { username: string } }): any | null {
+ if (args.where.username === VALID_CREDENTIALS.username) {
+ return USER;
+ }
+ return null;
+ },
+};
+
+const passwordService = {
+ compare(password: string, encrypted: string) {
+ return true;
+ },
+};
+
+const tokenService = {
+ createToken(username: string, password: string) {
+ return SIGN_TOKEN;
+ },
+};
+
+describe("AuthService", () => {
+ //ARRANGE
+ let service: AuthService;
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ {
+ provide: UserService,
+ useValue: authEntityService,
+ },
+ {
+ provide: PasswordService,
+ useValue: passwordService,
+ },
+ {
+ provide: TokenService,
+ useValue: tokenService,
+ },
+ AuthService,
+ ],
+ }).compile();
+
+ service = module.get(AuthService);
+ });
+
+ it("should be defined", () => {
+ expect(service).toBeDefined();
+ });
+
+ describe("Testing the authService.validateUser()", () => {
+ it("should validate a valid user", async () => {
+ await expect(
+ service.validateUser(
+ VALID_CREDENTIALS.username,
+ VALID_CREDENTIALS.password
+ )
+ ).resolves.toEqual({
+ username: USER.username,
+ roles: USER.roles,
+ id: USER.id,
+ });
+ });
+
+ it("should not validate a invalid user", async () => {
+ await expect(
+ service.validateUser(
+ INVALID_CREDENTIALS.username,
+ INVALID_CREDENTIALS.password
+ )
+ ).resolves.toBe(null);
+ });
+ });
+
+ describe("Testing the authService.login()", () => {
+ it("should return userInfo object for correct username and password", async () => {
+ const loginResult = await service.login(VALID_CREDENTIALS);
+ expect(loginResult).toEqual({
+ username: USER.username,
+ roles: USER.roles,
+ accessToken: SIGN_TOKEN,
+ id: USER.id,
+ });
+ });
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/auth.service.ts b/apps/vesst-discord-bot-backend-server/src/auth/auth.service.ts
new file mode 100644
index 0000000..9f6add2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/auth.service.ts
@@ -0,0 +1,49 @@
+import { Injectable, UnauthorizedException } from "@nestjs/common";
+import { Credentials } from "./Credentials";
+import { PasswordService } from "./password.service";
+import { TokenService } from "./token.service";
+import { UserInfo } from "./UserInfo";
+import { UserService } from "../user/user.service";
+
+@Injectable()
+export class AuthService {
+ constructor(
+ private readonly passwordService: PasswordService,
+ private readonly tokenService: TokenService,
+ private readonly userService: UserService
+ ) {}
+
+ async validateUser(
+ username: string,
+ password: string
+ ): Promise {
+ const user = await this.userService.user({
+ where: { username },
+ });
+ if (user && (await this.passwordService.compare(password, user.password))) {
+ const { id, roles } = user;
+ const roleList = roles as string[];
+ return { id, username, roles: roleList };
+ }
+ return null;
+ }
+ async login(credentials: Credentials): Promise {
+ const { username, password } = credentials;
+ const user = await this.validateUser(
+ credentials.username,
+ credentials.password
+ );
+ if (!user) {
+ throw new UnauthorizedException("The passed credentials are incorrect");
+ }
+ const accessToken = await this.tokenService.createToken({
+ id: user.id,
+ username,
+ password,
+ });
+ return {
+ accessToken,
+ ...user,
+ };
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/base/token.service.base.ts b/apps/vesst-discord-bot-backend-server/src/auth/base/token.service.base.ts
new file mode 100644
index 0000000..f25fdb5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/base/token.service.base.ts
@@ -0,0 +1,25 @@
+/* eslint-disable import/no-unresolved */
+import { Injectable } from "@nestjs/common";
+import { JwtService } from "@nestjs/jwt";
+import { INVALID_PASSWORD_ERROR, INVALID_USERNAME_ERROR } from "../constants";
+import { ITokenService, ITokenPayload } from "../ITokenService";
+/**
+ * TokenServiceBase is a jwt bearer implementation of ITokenService
+ */
+@Injectable()
+export class TokenServiceBase implements ITokenService {
+ constructor(protected readonly jwtService: JwtService) {}
+ /**
+ *
+ * @object { id: String, username: String, password: String}
+ * @returns a jwt token sign with the username and user id
+ */
+ createToken({ id, username, password }: ITokenPayload): Promise {
+ if (!username) return Promise.reject(INVALID_USERNAME_ERROR);
+ if (!password) return Promise.reject(INVALID_PASSWORD_ERROR);
+ return this.jwtService.signAsync({
+ sub: id,
+ username,
+ });
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/constants.ts b/apps/vesst-discord-bot-backend-server/src/auth/constants.ts
new file mode 100644
index 0000000..59f9f7d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/constants.ts
@@ -0,0 +1,2 @@
+export const INVALID_USERNAME_ERROR = "Invalid username";
+export const INVALID_PASSWORD_ERROR = "Invalid password";
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/defaultAuth.guard.ts b/apps/vesst-discord-bot-backend-server/src/auth/defaultAuth.guard.ts
new file mode 100644
index 0000000..33a530c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/defaultAuth.guard.ts
@@ -0,0 +1,27 @@
+import { Observable } from "rxjs";
+import { ExecutionContext, Injectable } from "@nestjs/common";
+import { Reflector } from "@nestjs/core";
+import { IS_PUBLIC_KEY } from "../decorators/public.decorator";
+import { JwtAuthGuard } from "./jwt/jwtAuth.guard";
+
+@Injectable()
+export class DefaultAuthGuard extends JwtAuthGuard {
+ constructor(private readonly reflector: Reflector) {
+ super();
+ }
+
+ canActivate(
+ context: ExecutionContext
+ ): boolean | Promise | Observable {
+ const isPublic = this.reflector.get(
+ IS_PUBLIC_KEY,
+ context.getHandler()
+ );
+
+ if (isPublic) {
+ return true;
+ }
+
+ return super.canActivate(context);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/gqlAC.guard.ts b/apps/vesst-discord-bot-backend-server/src/auth/gqlAC.guard.ts
new file mode 100644
index 0000000..dacac55
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/gqlAC.guard.ts
@@ -0,0 +1,11 @@
+import { ExecutionContext } from "@nestjs/common";
+import { GqlExecutionContext } from "@nestjs/graphql";
+import { ACGuard } from "nest-access-control";
+
+export class GqlACGuard extends ACGuard {
+ async getUser(context: ExecutionContext): Promise {
+ const ctx = GqlExecutionContext.create(context);
+ const request = ctx.getContext<{ req: { user: User } }>().req;
+ return request.user;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/gqlDefaultAuth.guard.ts b/apps/vesst-discord-bot-backend-server/src/auth/gqlDefaultAuth.guard.ts
new file mode 100644
index 0000000..abebd93
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/gqlDefaultAuth.guard.ts
@@ -0,0 +1,12 @@
+import { ExecutionContext } from "@nestjs/common";
+import { GqlExecutionContext } from "@nestjs/graphql";
+import type { Request } from "express";
+import { DefaultAuthGuard } from "./defaultAuth.guard";
+
+export class GqlDefaultAuthGuard extends DefaultAuthGuard {
+ // This method is required for the interface - do not delete it.
+ getRequest(context: ExecutionContext): Request {
+ const ctx = GqlExecutionContext.create(context);
+ return ctx.getContext<{ req: Request }>().req;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/gqlUserRoles.decorator.ts b/apps/vesst-discord-bot-backend-server/src/auth/gqlUserRoles.decorator.ts
new file mode 100644
index 0000000..5ea256b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/gqlUserRoles.decorator.ts
@@ -0,0 +1,19 @@
+import { createParamDecorator, ExecutionContext } from "@nestjs/common";
+import { GqlExecutionContext } from "@nestjs/graphql";
+
+/**
+ * Access the user roles from the request object i.e `req.user.roles`.
+ *
+ * You can pass an optional property key to the decorator to get it from the user object
+ * e.g `@UserRoles('permissions')` will return the `req.user.permissions` instead.
+ */
+export const UserRoles = createParamDecorator(
+ (data: string, context: ExecutionContext) => {
+ const ctx = GqlExecutionContext.create(context);
+ const request = ctx.getContext<{ req: { user: any } }>().req;
+ if (!request.user) {
+ return null;
+ }
+ return data ? request.user[data] : request.user.roles;
+ }
+);
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/jwt/base/jwt.strategy.base.ts b/apps/vesst-discord-bot-backend-server/src/auth/jwt/base/jwt.strategy.base.ts
new file mode 100644
index 0000000..26da6a7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/jwt/base/jwt.strategy.base.ts
@@ -0,0 +1,40 @@
+import { UnauthorizedException } from "@nestjs/common";
+import { PassportStrategy } from "@nestjs/passport";
+import { ExtractJwt, Strategy } from "passport-jwt";
+import { IAuthStrategy } from "../../IAuthStrategy";
+import { UserInfo } from "../../UserInfo";
+import { UserService } from "../../../user/user.service";
+
+export class JwtStrategyBase
+ extends PassportStrategy(Strategy)
+ implements IAuthStrategy
+{
+ constructor(
+ protected readonly secretOrKey: string,
+ protected readonly userService: UserService
+ ) {
+ super({
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
+ ignoreExpiration: false,
+ secretOrKey,
+ });
+ }
+
+ async validate(payload: UserInfo): Promise {
+ const { username } = payload;
+ const user = await this.userService.user({
+ where: { username },
+ });
+ if (!user) {
+ throw new UnauthorizedException();
+ }
+ if (
+ !Array.isArray(user.roles) ||
+ typeof user.roles !== "object" ||
+ user.roles === null
+ ) {
+ throw new Error("User roles is not a valid value");
+ }
+ return { ...user, roles: user.roles as string[] };
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwt.strategy.ts b/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwt.strategy.ts
new file mode 100644
index 0000000..13395e5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwt.strategy.ts
@@ -0,0 +1,14 @@
+import { Inject, Injectable } from "@nestjs/common";
+import { JWT_SECRET_KEY_PROVIDER_NAME } from "../../constants";
+import { JwtStrategyBase } from "./base/jwt.strategy.base";
+import { UserService } from "../../user/user.service";
+
+@Injectable()
+export class JwtStrategy extends JwtStrategyBase {
+ constructor(
+ @Inject(JWT_SECRET_KEY_PROVIDER_NAME) secretOrKey: string,
+ protected readonly userService: UserService
+ ) {
+ super(secretOrKey, userService);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwtAuth.guard.ts b/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwtAuth.guard.ts
new file mode 100644
index 0000000..f0c5570
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwtAuth.guard.ts
@@ -0,0 +1,3 @@
+import { AuthGuard } from "@nestjs/passport";
+
+export class JwtAuthGuard extends AuthGuard("jwt") {}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwtSecretFactory.ts b/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwtSecretFactory.ts
new file mode 100644
index 0000000..8ca4d74
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/jwt/jwtSecretFactory.ts
@@ -0,0 +1,19 @@
+import { JWT_SECRET_KEY_PROVIDER_NAME } from "../../constants";
+import { SecretsManagerService } from "../../providers/secrets/secretsManager.service";
+import { EnumSecretsNameKey } from "../../providers/secrets/secretsNameKey.enum";
+
+export const jwtSecretFactory = {
+ provide: JWT_SECRET_KEY_PROVIDER_NAME,
+ useFactory: async (
+ secretsService: SecretsManagerService
+ ): Promise => {
+ const secret = await secretsService.getSecret(
+ EnumSecretsNameKey.JwtSecretKey
+ );
+ if (secret) {
+ return secret;
+ }
+ throw new Error("jwtSecretFactory missing secret");
+ },
+ inject: [SecretsManagerService],
+};
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/password.service.spec.ts b/apps/vesst-discord-bot-backend-server/src/auth/password.service.spec.ts
new file mode 100644
index 0000000..309c8c0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/password.service.spec.ts
@@ -0,0 +1,69 @@
+import { ConfigService } from "@nestjs/config";
+import { Test, TestingModule } from "@nestjs/testing";
+import { PasswordService } from "./password.service";
+
+const EXAMPLE_PASSWORD = "examplePassword";
+const EXAMPLE_HASHED_PASSWORD = "exampleHashedPassword";
+
+const EXAMPLE_SALT_OR_ROUNDS = 1;
+
+const configServiceGetMock = jest.fn(() => {
+ return EXAMPLE_SALT_OR_ROUNDS;
+});
+
+jest.mock("bcrypt", () => ({
+ hash: jest.fn(),
+ compare: jest.fn(),
+}));
+
+const { hash, compare } = jest.requireMock("bcrypt");
+
+hash.mockImplementation(async () => EXAMPLE_HASHED_PASSWORD);
+
+compare.mockImplementation(async () => true);
+
+describe("PasswordService", () => {
+ let service: PasswordService;
+
+ beforeEach(async () => {
+ jest.clearAllMocks();
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ PasswordService,
+ {
+ provide: ConfigService,
+ useClass: jest.fn(() => ({
+ get: configServiceGetMock,
+ })),
+ },
+ ],
+ imports: [],
+ }).compile();
+
+ service = module.get(PasswordService);
+ });
+
+ it("should be defined", () => {
+ expect(service).toBeDefined();
+ });
+
+ it("should have salt defined", () => {
+ expect(service.salt).toEqual(EXAMPLE_SALT_OR_ROUNDS);
+ });
+
+ it("should compare a password", async () => {
+ const args = {
+ password: EXAMPLE_PASSWORD,
+ hashedPassword: EXAMPLE_HASHED_PASSWORD,
+ };
+ await expect(
+ service.compare(args.password, args.hashedPassword)
+ ).resolves.toEqual(true);
+ });
+
+ it("should hash a password", async () => {
+ await expect(service.hash(EXAMPLE_PASSWORD)).resolves.toEqual(
+ EXAMPLE_HASHED_PASSWORD
+ );
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/password.service.ts b/apps/vesst-discord-bot-backend-server/src/auth/password.service.ts
new file mode 100644
index 0000000..377b64b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/password.service.ts
@@ -0,0 +1,64 @@
+import { Injectable } from "@nestjs/common";
+import { hash, compare } from "bcrypt";
+import { ConfigService } from "@nestjs/config";
+
+/** Salt or number of rounds to generate a salt */
+export type Salt = string | number;
+
+const BCRYPT_SALT_VAR = "BCRYPT_SALT";
+const UNDEFINED_SALT_OR_ROUNDS_ERROR = `${BCRYPT_SALT_VAR} is not defined`;
+const SALT_OR_ROUNDS_TYPE_ERROR = `${BCRYPT_SALT_VAR} must be a positive integer or text`;
+
+@Injectable()
+export class PasswordService {
+ /**
+ * the salt to be used to hash the password. if specified as a number then a
+ * salt will be generated with the specified number of rounds and used
+ */
+ salt: Salt;
+
+ constructor(private configService: ConfigService) {
+ const saltOrRounds = this.configService.get(BCRYPT_SALT_VAR);
+ this.salt = parseSalt(saltOrRounds);
+ }
+
+ /**
+ *
+ * @param password the password to be encrypted.
+ * @param encrypted the encrypted password to be compared against.
+ * @returns whether the password match the encrypted password
+ */
+ compare(password: string, encrypted: string): Promise {
+ return compare(password, encrypted);
+ }
+
+ /**
+ * @param password the password to be encrypted
+ * @return encrypted password
+ */
+ hash(password: string): Promise {
+ return hash(password, this.salt);
+ }
+}
+
+/**
+ * Parses a salt environment variable value.
+ * If a number string value is given tries to parse it as a number of rounds to generate a salt
+ * @param value salt environment variable value
+ * @returns salt or number of rounds to generate a salt
+ */
+export function parseSalt(value: string | undefined): Salt {
+ if (value === undefined) {
+ throw new Error(UNDEFINED_SALT_OR_ROUNDS_ERROR);
+ }
+
+ const rounds = Number(value);
+
+ if (Number.isNaN(rounds)) {
+ return value;
+ }
+ if (!Number.isInteger(rounds) || rounds < 0) {
+ throw new Error(SALT_OR_ROUNDS_TYPE_ERROR);
+ }
+ return rounds;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/token.service.ts b/apps/vesst-discord-bot-backend-server/src/auth/token.service.ts
new file mode 100644
index 0000000..2ee079c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/token.service.ts
@@ -0,0 +1,5 @@
+import { ITokenService } from "./ITokenService";
+
+import { TokenServiceBase } from "./base/token.service.base";
+
+export class TokenService extends TokenServiceBase implements ITokenService {}
diff --git a/apps/vesst-discord-bot-backend-server/src/auth/userData.decorator.ts b/apps/vesst-discord-bot-backend-server/src/auth/userData.decorator.ts
new file mode 100644
index 0000000..6a40ad1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/auth/userData.decorator.ts
@@ -0,0 +1,30 @@
+import { createParamDecorator, ExecutionContext } from "@nestjs/common";
+import { GqlContextType, GqlExecutionContext } from "@nestjs/graphql";
+import { User } from "@prisma/client";
+
+/**
+ * Access the user data from the request object i.e `req.user`.
+ */
+function userFactory(ctx: ExecutionContext): User {
+ const contextType = ctx.getType();
+ if (contextType === "http") {
+ // do something that is only important in the context of regular HTTP requests (REST)
+ const { user } = ctx.switchToHttp().getRequest();
+ return user;
+ } else if (contextType === "rpc") {
+ // do something that is only important in the context of Microservice requests
+ throw new Error("Rpc context is not implemented yet");
+ } else if (contextType === "ws") {
+ // do something that is only important in the context of Websockets requests
+ throw new Error("Websockets context is not implemented yet");
+ } else if (ctx.getType() === "graphql") {
+ // do something that is only important in the context of GraphQL requests
+ const gqlExecutionContext = GqlExecutionContext.create(ctx);
+ return gqlExecutionContext.getContext().req.user;
+ }
+ throw new Error("Invalid context");
+}
+
+export const UserData = createParamDecorator(
+ (data, ctx: ExecutionContext) => userFactory(ctx)
+);
diff --git a/apps/vesst-discord-bot-backend-server/src/authentication/RbacDto.ts b/apps/vesst-discord-bot-backend-server/src/authentication/RbacDto.ts
new file mode 100644
index 0000000..c7be88b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/authentication/RbacDto.ts
@@ -0,0 +1,33 @@
+import { ArgsType, ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { Type } from "class-transformer";
+
+@ArgsType()
+@ObjectType("RbacDtoObject")
+class RbacDto {
+ @Field(() => String)
+ @ApiProperty({
+ required: true,
+ type: () => String
+ })
+ @Type(() => String)
+ userId!: string;
+
+ @Field(() => String)
+ @ApiProperty({
+ required: true,
+ type: () => String
+ })
+ @Type(() => String)
+ role!: string;
+
+ @Field(() => [String])
+ @ApiProperty({
+ required: true,
+ type: () => [String]
+ })
+ @Type(() => String)
+ permissions!: string;
+}
+
+export { RbacDto as RbacDto };
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/authentication/TwoFaDto.ts b/apps/vesst-discord-bot-backend-server/src/authentication/TwoFaDto.ts
new file mode 100644
index 0000000..02d2246
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/authentication/TwoFaDto.ts
@@ -0,0 +1,24 @@
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class TwoFaDto {
+ @Field(() => String)
+ @ApiProperty({
+ required: true,
+ type: () => String
+ })
+ @Type(() => String)
+ userId!: string;
+
+ @Field(() => String)
+ @ApiProperty({
+ required: true,
+ type: () => String
+ })
+ @Type(() => String)
+ twoFACode!: string;
+}
+
+export { TwoFaDto as TwoFaDto };
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/authentication/authentication.controller.ts b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.controller.ts
new file mode 100644
index 0000000..9fd9be8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.controller.ts
@@ -0,0 +1,80 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import * as errors from "../errors";
+import { AuthenticationService } from "./authentication.service";
+import { TwoFaDto } from "./TwoFaDto";
+import { RbacDto } from "./RbacDto";
+
+@swagger.ApiTags("authentications")
+@common.Controller("authentications")
+export class AuthenticationController {
+ constructor(protected readonly service: AuthenticationService) {}
+
+ @common.Post("/rbac/assign-role")
+ @swagger.ApiOkResponse({
+ type: Boolean
+ })
+ @swagger.ApiNotFoundResponse({
+ type: errors.NotFoundException
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException
+ })
+ async AssignRole(
+ @common.Body()
+ body: TwoFaDto
+ ): Promise {
+ return this.service.AssignRole(body);
+ }
+
+ @common.Post("/2fa/generate")
+ @swagger.ApiOkResponse({
+ type: String
+ })
+ @swagger.ApiNotFoundResponse({
+ type: errors.NotFoundException
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException
+ })
+ async Generate2FaCode(
+ @common.Body()
+ body: TwoFaDto
+ ): Promise {
+ return this.service.Generate2FaCode(body);
+ }
+
+ @common.Get("/rbac/permissions/:userId")
+ @swagger.ApiOkResponse({
+ type: RbacDto
+ })
+ @swagger.ApiNotFoundResponse({
+ type: errors.NotFoundException
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException
+ })
+ async GetUserPermissions(
+ @common.Body()
+ body: TwoFaDto
+ ): Promise {
+ return this.service.GetUserPermissions(body);
+ }
+
+ @common.Post("/2fa/verify")
+ @swagger.ApiOkResponse({
+ type: Boolean
+ })
+ @swagger.ApiNotFoundResponse({
+ type: errors.NotFoundException
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException
+ })
+ async Verify2FaCode(
+ @common.Body()
+ body: TwoFaDto
+ ): Promise {
+ return this.service.Verify2FaCode(body);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/authentication/authentication.module.ts b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.module.ts
new file mode 100644
index 0000000..28d6783
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.module.ts
@@ -0,0 +1,11 @@
+import { Module } from "@nestjs/common";
+import { AuthenticationService } from "./authentication.service";
+import { AuthenticationController } from "./authentication.controller";
+import { AuthenticationResolver } from "./authentication.resolver";
+
+@Module({
+ controllers: [AuthenticationController],
+ providers: [AuthenticationService, AuthenticationResolver],
+ exports: [AuthenticationService],
+})
+export class AuthenticationModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/authentication/authentication.resolver.ts b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.resolver.ts
new file mode 100644
index 0000000..25b5bef
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.resolver.ts
@@ -0,0 +1,40 @@
+import * as graphql from "@nestjs/graphql";
+import { RbacDto } from "./RbacDto";
+import { TwoFaDto } from "./TwoFaDto";
+import { AuthenticationService } from "./authentication.service";
+
+export class AuthenticationResolver {
+ constructor(protected readonly service: AuthenticationService) {}
+
+ @graphql.Mutation(() => Boolean)
+ async AssignRole(
+ @graphql.Args()
+ args: RbacDto
+ ): Promise {
+ return this.service.AssignRole(args);
+ }
+
+ @graphql.Mutation(() => String)
+ async Generate2FaCode(
+ @graphql.Args()
+ args: TwoFaDto
+ ): Promise {
+ return this.service.Generate2FaCode(args);
+ }
+
+ @graphql.Query(() => [RbacDto])
+ async GetUserPermissions(
+ @graphql.Args("args")
+ args: string
+ ): Promise {
+ return this.service.GetUserPermissions(args);
+ }
+
+ @graphql.Mutation(() => Boolean)
+ async Verify2FaCode(
+ @graphql.Args()
+ args: TwoFaDto
+ ): Promise {
+ return this.service.Verify2FaCode(args);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/authentication/authentication.service.ts b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.service.ts
new file mode 100644
index 0000000..78a616f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/authentication/authentication.service.ts
@@ -0,0 +1,20 @@
+import { Injectable } from "@nestjs/common";
+import { RbacDto } from "./RbacDto";
+import { TwoFaDto } from "./TwoFaDto";
+
+@Injectable()
+export class AuthenticationService {
+ constructor() {}
+ async AssignRole(args: RbacDto): Promise {
+ throw new Error("Not implemented");
+ }
+ async Generate2FaCode(args: TwoFaDto): Promise {
+ throw new Error("Not implemented");
+ }
+ async GetUserPermissions(args: string): Promise {
+ throw new Error("Not implemented");
+ }
+ async Verify2FaCode(args: TwoFaDto): Promise {
+ throw new Error("Not implemented");
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/connectMicroservices.ts b/apps/vesst-discord-bot-backend-server/src/connectMicroservices.ts
new file mode 100644
index 0000000..d9a7438
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/connectMicroservices.ts
@@ -0,0 +1,13 @@
+import { INestApplication } from "@nestjs/common";
+import { ConfigService } from "@nestjs/config";
+import { grpcClientOptions } from "./grpc.client.options";
+import { generateKafkaClientOptions } from "./kafka/generateKafkaClientOptions";
+import { MicroserviceOptions } from "@nestjs/microservices";
+import { generateRedisClientOptions } from "./redis/generateRedisClientOptions";
+
+export async function connectMicroservices(app: INestApplication) {
+ const configService = app.get(ConfigService);
+ app.connectMicroservice(grpcClientOptions);
+ app.connectMicroservice(generateKafkaClientOptions(configService));
+ app.connectMicroservice(generateRedisClientOptions(configService));
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/constants.ts b/apps/vesst-discord-bot-backend-server/src/constants.ts
new file mode 100644
index 0000000..e131049
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/constants.ts
@@ -0,0 +1,2 @@
+export const JWT_SECRET_KEY_PROVIDER_NAME = "JWT_SECRET_KEY";
+export const JWT_EXPIRATION = "JWT_EXPIRATION";
diff --git a/apps/vesst-discord-bot-backend-server/src/decorators/api-nested-query.decorator.ts b/apps/vesst-discord-bot-backend-server/src/decorators/api-nested-query.decorator.ts
new file mode 100644
index 0000000..9fd5ba3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/decorators/api-nested-query.decorator.ts
@@ -0,0 +1,80 @@
+import { applyDecorators } from "@nestjs/common";
+import {
+ ApiExtraModels,
+ ApiQuery,
+ ApiQueryOptions,
+ getSchemaPath,
+} from "@nestjs/swagger";
+import "reflect-metadata";
+
+const generateApiQueryObject = (
+ prop: any,
+ propType: any,
+ required: boolean,
+ isArray: boolean
+): ApiQueryOptions => {
+ if (propType === Number) {
+ return {
+ required,
+ name: prop,
+ style: "deepObject",
+ explode: true,
+ type: "number",
+ isArray,
+ };
+ } else if (propType === String) {
+ return {
+ required,
+ name: prop,
+ style: "deepObject",
+ explode: true,
+ type: "string",
+ isArray,
+ };
+ } else {
+ return {
+ required,
+ name: prop,
+ style: "deepObject",
+ explode: true,
+ type: "object",
+ isArray,
+ schema: {
+ $ref: getSchemaPath(propType),
+ },
+ };
+ }
+};
+
+// eslint-disable-next-line @typescript-eslint/ban-types,@typescript-eslint/explicit-module-boundary-types,@typescript-eslint/naming-convention
+export function ApiNestedQuery(query: Function) {
+ const constructor = query.prototype;
+ const properties = Reflect.getMetadata(
+ "swagger/apiModelPropertiesArray",
+ constructor
+ ).map((prop: any) => prop.slice(1));
+
+ const decorators = properties
+ .map((property: any) => {
+ const { required, isArray } = Reflect.getMetadata(
+ "swagger/apiModelProperties",
+ constructor,
+ property
+ );
+ const propertyType = Reflect.getMetadata(
+ "design:type",
+ constructor,
+ property
+ );
+ const typedQuery = generateApiQueryObject(
+ property,
+ propertyType,
+ required,
+ isArray
+ );
+ return [ApiExtraModels(propertyType), ApiQuery(typedQuery)];
+ })
+ .flat();
+
+ return applyDecorators(...decorators);
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/decorators/public.decorator.ts b/apps/vesst-discord-bot-backend-server/src/decorators/public.decorator.ts
new file mode 100644
index 0000000..9eab4e0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/decorators/public.decorator.ts
@@ -0,0 +1,10 @@
+import { applyDecorators, SetMetadata } from "@nestjs/common";
+
+export const IS_PUBLIC_KEY = "isPublic";
+
+const PublicAuthMiddleware = SetMetadata(IS_PUBLIC_KEY, true);
+const PublicAuthSwagger = SetMetadata("swagger/apiSecurity", ["isPublic"]);
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export const Public = () =>
+ applyDecorators(PublicAuthMiddleware, PublicAuthSwagger);
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/CreateEmbedArgs.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/CreateEmbedArgs.ts
new file mode 100644
index 0000000..8245ae5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/CreateEmbedArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedCreateInput } from "./EmbedCreateInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class CreateEmbedArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EmbedCreateInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedCreateInput)
+ @Field(() => EmbedCreateInput, { nullable: false })
+ data!: EmbedCreateInput;
+}
+
+export { CreateEmbedArgs as CreateEmbedArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/DeleteEmbedArgs.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/DeleteEmbedArgs.ts
new file mode 100644
index 0000000..8c8c0b8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/DeleteEmbedArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class DeleteEmbedArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EmbedWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedWhereUniqueInput)
+ @Field(() => EmbedWhereUniqueInput, { nullable: false })
+ where!: EmbedWhereUniqueInput;
+}
+
+export { DeleteEmbedArgs as DeleteEmbedArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/Embed.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/Embed.ts
new file mode 100644
index 0000000..36a9d8f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/Embed.ts
@@ -0,0 +1,103 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString, MaxLength, IsOptional, IsDate } from "class-validator";
+import { Type } from "class-transformer";
+
+@ObjectType()
+class Embed {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ color!: string | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ createdAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateCreated!: Date | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ description!: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ footer!: string | null;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ title!: string | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ updatedAt!: Date;
+}
+
+export { Embed as Embed };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedCountArgs.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedCountArgs.ts
new file mode 100644
index 0000000..f834081
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedCountArgs.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedWhereInput } from "./EmbedWhereInput";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class EmbedCountArgs {
+ @ApiProperty({
+ required: false,
+ type: () => EmbedWhereInput,
+ })
+ @Field(() => EmbedWhereInput, { nullable: true })
+ @Type(() => EmbedWhereInput)
+ where?: EmbedWhereInput;
+}
+
+export { EmbedCountArgs as EmbedCountArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedCreateInput.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedCreateInput.ts
new file mode 100644
index 0000000..3c048a6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedCreateInput.ts
@@ -0,0 +1,79 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString, MaxLength, IsOptional, IsDate } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class EmbedCreateInput {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ color?: string | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateCreated?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ description?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ footer?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ title?: string | null;
+}
+
+export { EmbedCreateInput as EmbedCreateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedFindManyArgs.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedFindManyArgs.ts
new file mode 100644
index 0000000..fa12468
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedFindManyArgs.ts
@@ -0,0 +1,62 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedWhereInput } from "./EmbedWhereInput";
+import { IsOptional, ValidateNested, IsInt } from "class-validator";
+import { Type } from "class-transformer";
+import { EmbedOrderByInput } from "./EmbedOrderByInput";
+
+@ArgsType()
+class EmbedFindManyArgs {
+ @ApiProperty({
+ required: false,
+ type: () => EmbedWhereInput,
+ })
+ @IsOptional()
+ @ValidateNested()
+ @Field(() => EmbedWhereInput, { nullable: true })
+ @Type(() => EmbedWhereInput)
+ where?: EmbedWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: [EmbedOrderByInput],
+ })
+ @IsOptional()
+ @ValidateNested({ each: true })
+ @Field(() => [EmbedOrderByInput], { nullable: true })
+ @Type(() => EmbedOrderByInput)
+ orderBy?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ skip?: number;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ take?: number;
+}
+
+export { EmbedFindManyArgs as EmbedFindManyArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedFindUniqueArgs.ts
new file mode 100644
index 0000000..5f29cce
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedFindUniqueArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class EmbedFindUniqueArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EmbedWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedWhereUniqueInput)
+ @Field(() => EmbedWhereUniqueInput, { nullable: false })
+ where!: EmbedWhereUniqueInput;
+}
+
+export { EmbedFindUniqueArgs as EmbedFindUniqueArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedListRelationFilter.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedListRelationFilter.ts
new file mode 100644
index 0000000..6447857
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedListRelationFilter.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedWhereInput } from "./EmbedWhereInput";
+import { ValidateNested, IsOptional } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class EmbedListRelationFilter {
+ @ApiProperty({
+ required: false,
+ type: () => EmbedWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedWhereInput)
+ @IsOptional()
+ @Field(() => EmbedWhereInput, {
+ nullable: true,
+ })
+ every?: EmbedWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => EmbedWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedWhereInput)
+ @IsOptional()
+ @Field(() => EmbedWhereInput, {
+ nullable: true,
+ })
+ some?: EmbedWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => EmbedWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedWhereInput)
+ @IsOptional()
+ @Field(() => EmbedWhereInput, {
+ nullable: true,
+ })
+ none?: EmbedWhereInput;
+}
+export { EmbedListRelationFilter as EmbedListRelationFilter };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedOrderByInput.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedOrderByInput.ts
new file mode 100644
index 0000000..0cc593f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedOrderByInput.ts
@@ -0,0 +1,111 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsOptional, IsEnum } from "class-validator";
+import { SortOrder } from "../../util/SortOrder";
+
+@InputType({
+ isAbstract: true,
+ description: undefined,
+})
+class EmbedOrderByInput {
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ color?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ createdAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ dateCreated?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ description?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ footer?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ id?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ title?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ updatedAt?: SortOrder;
+}
+
+export { EmbedOrderByInput as EmbedOrderByInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedUpdateInput.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedUpdateInput.ts
new file mode 100644
index 0000000..fe7fdbf
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedUpdateInput.ts
@@ -0,0 +1,79 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString, MaxLength, IsOptional, IsDate } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class EmbedUpdateInput {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ color?: string | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateCreated?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ description?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ footer?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ title?: string | null;
+}
+
+export { EmbedUpdateInput as EmbedUpdateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedWhereInput.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedWhereInput.ts
new file mode 100644
index 0000000..36f6fd8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedWhereInput.ts
@@ -0,0 +1,89 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { Type } from "class-transformer";
+import { IsOptional } from "class-validator";
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+
+@InputType()
+class EmbedWhereInput {
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ color?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: DateTimeNullableFilter,
+ })
+ @Type(() => DateTimeNullableFilter)
+ @IsOptional()
+ @Field(() => DateTimeNullableFilter, {
+ nullable: true,
+ })
+ dateCreated?: DateTimeNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ description?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ footer?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ id?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ title?: StringNullableFilter;
+}
+
+export { EmbedWhereInput as EmbedWhereInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedWhereUniqueInput.ts
new file mode 100644
index 0000000..6df8838
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/EmbedWhereUniqueInput.ts
@@ -0,0 +1,27 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString } from "class-validator";
+
+@InputType()
+class EmbedWhereUniqueInput {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+}
+
+export { EmbedWhereUniqueInput as EmbedWhereUniqueInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/UpdateEmbedArgs.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/UpdateEmbedArgs.ts
new file mode 100644
index 0000000..9314106
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/UpdateEmbedArgs.ts
@@ -0,0 +1,40 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { EmbedUpdateInput } from "./EmbedUpdateInput";
+
+@ArgsType()
+class UpdateEmbedArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EmbedWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedWhereUniqueInput)
+ @Field(() => EmbedWhereUniqueInput, { nullable: false })
+ where!: EmbedWhereUniqueInput;
+
+ @ApiProperty({
+ required: true,
+ type: () => EmbedUpdateInput,
+ })
+ @ValidateNested()
+ @Type(() => EmbedUpdateInput)
+ @Field(() => EmbedUpdateInput, { nullable: false })
+ data!: EmbedUpdateInput;
+}
+
+export { UpdateEmbedArgs as UpdateEmbedArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/embed.controller.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.controller.base.spec.ts
new file mode 100644
index 0000000..7b03dba
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.controller.base.spec.ts
@@ -0,0 +1,214 @@
+import { Test } from "@nestjs/testing";
+import {
+ INestApplication,
+ HttpStatus,
+ ExecutionContext,
+ CallHandler,
+} from "@nestjs/common";
+import request from "supertest";
+import { ACGuard } from "nest-access-control";
+import { DefaultAuthGuard } from "../../auth/defaultAuth.guard";
+import { ACLModule } from "../../auth/acl.module";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { map } from "rxjs";
+import { EmbedController } from "../embed.controller";
+import { EmbedService } from "../embed.service";
+
+const nonExistingId = "nonExistingId";
+const existingId = "existingId";
+const CREATE_INPUT = {
+ color: "exampleColor",
+ createdAt: new Date(),
+ dateCreated: new Date(),
+ description: "exampleDescription",
+ footer: "exampleFooter",
+ id: "exampleId",
+ title: "exampleTitle",
+ updatedAt: new Date(),
+};
+const CREATE_RESULT = {
+ color: "exampleColor",
+ createdAt: new Date(),
+ dateCreated: new Date(),
+ description: "exampleDescription",
+ footer: "exampleFooter",
+ id: "exampleId",
+ title: "exampleTitle",
+ updatedAt: new Date(),
+};
+const FIND_MANY_RESULT = [
+ {
+ color: "exampleColor",
+ createdAt: new Date(),
+ dateCreated: new Date(),
+ description: "exampleDescription",
+ footer: "exampleFooter",
+ id: "exampleId",
+ title: "exampleTitle",
+ updatedAt: new Date(),
+ },
+];
+const FIND_ONE_RESULT = {
+ color: "exampleColor",
+ createdAt: new Date(),
+ dateCreated: new Date(),
+ description: "exampleDescription",
+ footer: "exampleFooter",
+ id: "exampleId",
+ title: "exampleTitle",
+ updatedAt: new Date(),
+};
+
+const service = {
+ createEmbed() {
+ return CREATE_RESULT;
+ },
+ embeds: () => FIND_MANY_RESULT,
+ embed: ({ where }: { where: { id: string } }) => {
+ switch (where.id) {
+ case existingId:
+ return FIND_ONE_RESULT;
+ case nonExistingId:
+ return null;
+ }
+ },
+};
+
+const basicAuthGuard = {
+ canActivate: (context: ExecutionContext) => {
+ const argumentHost = context.switchToHttp();
+ const request = argumentHost.getRequest();
+ request.user = {
+ roles: ["user"],
+ };
+ return true;
+ },
+};
+
+const acGuard = {
+ canActivate: () => {
+ return true;
+ },
+};
+
+const aclFilterResponseInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle().pipe(
+ map((data) => {
+ return data;
+ })
+ );
+ },
+};
+const aclValidateRequestInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle();
+ },
+};
+
+describe("Embed", () => {
+ let app: INestApplication;
+
+ beforeAll(async () => {
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ {
+ provide: EmbedService,
+ useValue: service,
+ },
+ ],
+ controllers: [EmbedController],
+ imports: [ACLModule],
+ })
+ .overrideGuard(DefaultAuthGuard)
+ .useValue(basicAuthGuard)
+ .overrideGuard(ACGuard)
+ .useValue(acGuard)
+ .overrideInterceptor(AclFilterResponseInterceptor)
+ .useValue(aclFilterResponseInterceptor)
+ .overrideInterceptor(AclValidateRequestInterceptor)
+ .useValue(aclValidateRequestInterceptor)
+ .compile();
+
+ app = moduleRef.createNestApplication();
+ await app.init();
+ });
+
+ test("POST /embeds", async () => {
+ await request(app.getHttpServer())
+ .post("/embeds")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ dateCreated: CREATE_RESULT.dateCreated.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("GET /embeds", async () => {
+ await request(app.getHttpServer())
+ .get("/embeds")
+ .expect(HttpStatus.OK)
+ .expect([
+ {
+ ...FIND_MANY_RESULT[0],
+ createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(),
+ dateCreated: FIND_MANY_RESULT[0].dateCreated.toISOString(),
+ updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(),
+ },
+ ]);
+ });
+
+ test("GET /embeds/:id non existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/embeds"}/${nonExistingId}`)
+ .expect(HttpStatus.NOT_FOUND)
+ .expect({
+ statusCode: HttpStatus.NOT_FOUND,
+ message: `No resource was found for {"${"id"}":"${nonExistingId}"}`,
+ error: "Not Found",
+ });
+ });
+
+ test("GET /embeds/:id existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/embeds"}/${existingId}`)
+ .expect(HttpStatus.OK)
+ .expect({
+ ...FIND_ONE_RESULT,
+ createdAt: FIND_ONE_RESULT.createdAt.toISOString(),
+ dateCreated: FIND_ONE_RESULT.dateCreated.toISOString(),
+ updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("POST /embeds existing resource", async () => {
+ const agent = request(app.getHttpServer());
+ await agent
+ .post("/embeds")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ dateCreated: CREATE_RESULT.dateCreated.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ })
+ .then(function () {
+ agent
+ .post("/embeds")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CONFLICT)
+ .expect({
+ statusCode: HttpStatus.CONFLICT,
+ });
+ });
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/embed.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.controller.base.ts
new file mode 100644
index 0000000..015674f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.controller.base.ts
@@ -0,0 +1,207 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import * as nestAccessControl from "nest-access-control";
+import * as defaultAuthGuard from "../../auth/defaultAuth.guard";
+import { EmbedService } from "../embed.service";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { EmbedCreateInput } from "./EmbedCreateInput";
+import { Embed } from "./Embed";
+import { EmbedFindManyArgs } from "./EmbedFindManyArgs";
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+import { EmbedUpdateInput } from "./EmbedUpdateInput";
+
+@swagger.ApiBearerAuth()
+@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard)
+export class EmbedControllerBase {
+ constructor(
+ protected readonly service: EmbedService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Embed })
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "create",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async createEmbed(@common.Body() data: EmbedCreateInput): Promise {
+ return await this.service.createEmbed({
+ data: data,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Embed] })
+ @ApiNestedQuery(EmbedFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "read",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async embeds(@common.Req() request: Request): Promise {
+ const args = plainToClass(EmbedFindManyArgs, request.query);
+ return this.service.embeds({
+ ...args,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Embed })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "read",
+ possession: "own",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async embed(
+ @common.Param() params: EmbedWhereUniqueInput
+ ): Promise {
+ const result = await this.service.embed({
+ where: params,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Embed })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "update",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async updateEmbed(
+ @common.Param() params: EmbedWhereUniqueInput,
+ @common.Body() data: EmbedUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateEmbed({
+ where: params,
+ data: data,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Embed })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "delete",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async deleteEmbed(
+ @common.Param() params: EmbedWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteEmbed({
+ where: params,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/embed.grpc.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.grpc.controller.base.ts
new file mode 100644
index 0000000..71b6306
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.grpc.controller.base.ts
@@ -0,0 +1,161 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import { GrpcMethod } from "@nestjs/microservices";
+import { EmbedService } from "../embed.service";
+import { EmbedCreateInput } from "./EmbedCreateInput";
+import { EmbedWhereInput } from "./EmbedWhereInput";
+import { EmbedWhereUniqueInput } from "./EmbedWhereUniqueInput";
+import { EmbedFindManyArgs } from "./EmbedFindManyArgs";
+import { EmbedUpdateInput } from "./EmbedUpdateInput";
+import { Embed } from "./Embed";
+
+export class EmbedGrpcControllerBase {
+ constructor(protected readonly service: EmbedService) {}
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Embed })
+ @GrpcMethod("EmbedService", "createEmbed")
+ async createEmbed(@common.Body() data: EmbedCreateInput): Promise {
+ return await this.service.createEmbed({
+ data: data,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Embed] })
+ @ApiNestedQuery(EmbedFindManyArgs)
+ @GrpcMethod("EmbedService", "embeds")
+ async embeds(@common.Req() request: Request): Promise {
+ const args = plainToClass(EmbedFindManyArgs, request.query);
+ return this.service.embeds({
+ ...args,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Embed })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("EmbedService", "embed")
+ async embed(
+ @common.Param() params: EmbedWhereUniqueInput
+ ): Promise {
+ const result = await this.service.embed({
+ where: params,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Embed })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("EmbedService", "updateEmbed")
+ async updateEmbed(
+ @common.Param() params: EmbedWhereUniqueInput,
+ @common.Body() data: EmbedUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateEmbed({
+ where: params,
+ data: data,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Embed })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("EmbedService", "deleteEmbed")
+ async deleteEmbed(
+ @common.Param() params: EmbedWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteEmbed({
+ where: params,
+ select: {
+ color: true,
+ createdAt: true,
+ dateCreated: true,
+ description: true,
+ footer: true,
+ id: true,
+ title: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/embed.module.base.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.module.base.ts
new file mode 100644
index 0000000..7921066
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.module.base.ts
@@ -0,0 +1,18 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { Module } from "@nestjs/common";
+import { ACLModule } from "../../auth/acl.module";
+@Module({
+ imports: [ACLModule],
+ exports: [ACLModule],
+})
+export class EmbedModuleBase {}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/embed.resolver.base.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.resolver.base.ts
new file mode 100644
index 0000000..8ec3f9a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.resolver.base.ts
@@ -0,0 +1,140 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as graphql from "@nestjs/graphql";
+import { GraphQLError } from "graphql";
+import { isRecordNotFoundError } from "../../prisma.util";
+import { MetaQueryPayload } from "../../util/MetaQueryPayload";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { Embed } from "./Embed";
+import { EmbedCountArgs } from "./EmbedCountArgs";
+import { EmbedFindManyArgs } from "./EmbedFindManyArgs";
+import { EmbedFindUniqueArgs } from "./EmbedFindUniqueArgs";
+import { CreateEmbedArgs } from "./CreateEmbedArgs";
+import { UpdateEmbedArgs } from "./UpdateEmbedArgs";
+import { DeleteEmbedArgs } from "./DeleteEmbedArgs";
+import { EmbedService } from "../embed.service";
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Embed)
+export class EmbedResolverBase {
+ constructor(
+ protected readonly service: EmbedService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+
+ @graphql.Query(() => MetaQueryPayload)
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "read",
+ possession: "any",
+ })
+ async _embedsMeta(
+ @graphql.Args() args: EmbedCountArgs
+ ): Promise {
+ const result = await this.service.count(args);
+ return {
+ count: result,
+ };
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => [Embed])
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "read",
+ possession: "any",
+ })
+ async embeds(@graphql.Args() args: EmbedFindManyArgs): Promise {
+ return this.service.embeds(args);
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => Embed, { nullable: true })
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "read",
+ possession: "own",
+ })
+ async embed(
+ @graphql.Args() args: EmbedFindUniqueArgs
+ ): Promise {
+ const result = await this.service.embed(args);
+ if (result === null) {
+ return null;
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Embed)
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "create",
+ possession: "any",
+ })
+ async createEmbed(@graphql.Args() args: CreateEmbedArgs): Promise {
+ return await this.service.createEmbed({
+ ...args,
+ data: args.data,
+ });
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Embed)
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "update",
+ possession: "any",
+ })
+ async updateEmbed(
+ @graphql.Args() args: UpdateEmbedArgs
+ ): Promise {
+ try {
+ return await this.service.updateEmbed({
+ ...args,
+ data: args.data,
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @graphql.Mutation(() => Embed)
+ @nestAccessControl.UseRoles({
+ resource: "Embed",
+ action: "delete",
+ possession: "any",
+ })
+ async deleteEmbed(
+ @graphql.Args() args: DeleteEmbedArgs
+ ): Promise {
+ try {
+ return await this.service.deleteEmbed(args);
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/base/embed.service.base.ts b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.service.base.ts
new file mode 100644
index 0000000..b6805b6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/base/embed.service.base.ts
@@ -0,0 +1,37 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { PrismaService } from "../../prisma/prisma.service";
+import { Prisma, Embed as PrismaEmbed } from "@prisma/client";
+
+export class EmbedServiceBase {
+ constructor(protected readonly prisma: PrismaService) {}
+
+ async count(args: Omit): Promise {
+ return this.prisma.embed.count(args);
+ }
+
+ async embeds(args: Prisma.EmbedFindManyArgs): Promise {
+ return this.prisma.embed.findMany(args);
+ }
+ async embed(args: Prisma.EmbedFindUniqueArgs): Promise {
+ return this.prisma.embed.findUnique(args);
+ }
+ async createEmbed(args: Prisma.EmbedCreateArgs): Promise {
+ return this.prisma.embed.create(args);
+ }
+ async updateEmbed(args: Prisma.EmbedUpdateArgs): Promise {
+ return this.prisma.embed.update(args);
+ }
+ async deleteEmbed(args: Prisma.EmbedDeleteArgs): Promise {
+ return this.prisma.embed.delete(args);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/embed.controller.ts b/apps/vesst-discord-bot-backend-server/src/embed/embed.controller.ts
new file mode 100644
index 0000000..6124d21
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/embed.controller.ts
@@ -0,0 +1,17 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import * as nestAccessControl from "nest-access-control";
+import { EmbedService } from "./embed.service";
+import { EmbedControllerBase } from "./base/embed.controller.base";
+
+@swagger.ApiTags("embeds")
+@common.Controller("embeds")
+export class EmbedController extends EmbedControllerBase {
+ constructor(
+ protected readonly service: EmbedService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/embed.grpc.controller.ts b/apps/vesst-discord-bot-backend-server/src/embed/embed.grpc.controller.ts
new file mode 100644
index 0000000..66f1c58
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/embed.grpc.controller.ts
@@ -0,0 +1,12 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { EmbedService } from "./embed.service";
+import { EmbedGrpcControllerBase } from "./base/embed.grpc.controller.base";
+
+@swagger.ApiTags("embeds")
+@common.Controller("embeds")
+export class EmbedGrpcController extends EmbedGrpcControllerBase {
+ constructor(protected readonly service: EmbedService) {
+ super(service);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/embed.module.ts b/apps/vesst-discord-bot-backend-server/src/embed/embed.module.ts
new file mode 100644
index 0000000..6588040
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/embed.module.ts
@@ -0,0 +1,15 @@
+import { Module, forwardRef } from "@nestjs/common";
+import { AuthModule } from "../auth/auth.module";
+import { EmbedModuleBase } from "./base/embed.module.base";
+import { EmbedService } from "./embed.service";
+import { EmbedController } from "./embed.controller";
+import { EmbedGrpcController } from "./embed.grpc.controller";
+import { EmbedResolver } from "./embed.resolver";
+
+@Module({
+ imports: [EmbedModuleBase, forwardRef(() => AuthModule)],
+ controllers: [EmbedController, EmbedGrpcController],
+ providers: [EmbedService, EmbedResolver],
+ exports: [EmbedService],
+})
+export class EmbedModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/embed.proto b/apps/vesst-discord-bot-backend-server/src/embed/embed.proto
new file mode 100644
index 0000000..9ca27eb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/embed.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+ package embed;
+service EmbedService {
+ rpc createEmbed (EmbedCreateInput) returns (Embed) {}
+rpc embeds (findManyParams) returns (stream Embed) {}
+rpc embed (EmbedWhereUniqueInput) returns (Embed) {}
+rpc updateEmbed (EmbedUpdateInput) returns (Embed) {}
+rpc deleteEmbed (EmbedWhereUniqueInput) returns (Embed) {}
+ }
+message EmbedCreateInput {
+string color = 1;
+string createdAt = 2;
+string dateCreated = 3;
+string description = 4;
+string footer = 5;
+string id = 6;
+string title = 7;
+string updatedAt = 8;
+};
+message Embed {
+string color = 1;
+string createdAt = 2;
+string dateCreated = 3;
+string description = 4;
+string footer = 5;
+string id = 6;
+string title = 7;
+string updatedAt = 8;
+};
+message EmbedWhereUniqueInput {
+string color = 1;
+string createdAt = 2;
+string dateCreated = 3;
+string description = 4;
+string footer = 5;
+string id = 6;
+string title = 7;
+string updatedAt = 8;
+};
+message EmbedUpdateInput {
+string color = 1;
+string createdAt = 2;
+string dateCreated = 3;
+string description = 4;
+string footer = 5;
+string id = 6;
+string title = 7;
+string updatedAt = 8;
+};
+message findManyParams {
+
+};
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/embed.resolver.ts b/apps/vesst-discord-bot-backend-server/src/embed/embed.resolver.ts
new file mode 100644
index 0000000..be703ad
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/embed.resolver.ts
@@ -0,0 +1,20 @@
+import * as graphql from "@nestjs/graphql";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { EmbedResolverBase } from "./base/embed.resolver.base";
+import { Embed } from "./base/Embed";
+import { EmbedService } from "./embed.service";
+
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Embed)
+export class EmbedResolver extends EmbedResolverBase {
+ constructor(
+ protected readonly service: EmbedService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/embed/embed.service.ts b/apps/vesst-discord-bot-backend-server/src/embed/embed.service.ts
new file mode 100644
index 0000000..a8226cb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/embed/embed.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../prisma/prisma.service";
+import { EmbedServiceBase } from "./base/embed.service.base";
+
+@Injectable()
+export class EmbedService extends EmbedServiceBase {
+ constructor(protected readonly prisma: PrismaService) {
+ super(prisma);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/CreateEntertainmentArgs.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/CreateEntertainmentArgs.ts
new file mode 100644
index 0000000..2bae324
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/CreateEntertainmentArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentCreateInput } from "./EntertainmentCreateInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class CreateEntertainmentArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EntertainmentCreateInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentCreateInput)
+ @Field(() => EntertainmentCreateInput, { nullable: false })
+ data!: EntertainmentCreateInput;
+}
+
+export { CreateEntertainmentArgs as CreateEntertainmentArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/DeleteEntertainmentArgs.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/DeleteEntertainmentArgs.ts
new file mode 100644
index 0000000..a1396c1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/DeleteEntertainmentArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class DeleteEntertainmentArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EntertainmentWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentWhereUniqueInput)
+ @Field(() => EntertainmentWhereUniqueInput, { nullable: false })
+ where!: EntertainmentWhereUniqueInput;
+}
+
+export { DeleteEntertainmentArgs as DeleteEntertainmentArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/Entertainment.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/Entertainment.ts
new file mode 100644
index 0000000..14c202a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/Entertainment.ts
@@ -0,0 +1,87 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsDate,
+ IsOptional,
+ IsString,
+ MaxLength,
+ IsEnum,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { JsonValue } from "type-fest";
+import { EnumEntertainmentTypeField } from "./EnumEntertainmentTypeField";
+
+@ObjectType()
+class Entertainment {
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ createdAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ details!: JsonValue;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ name!: string | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumEntertainmentTypeField,
+ })
+ @IsEnum(EnumEntertainmentTypeField)
+ @IsOptional()
+ @Field(() => EnumEntertainmentTypeField, {
+ nullable: true,
+ })
+ typeField?: "Option1" | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ updatedAt!: Date;
+}
+
+export { Entertainment as Entertainment };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentCountArgs.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentCountArgs.ts
new file mode 100644
index 0000000..84ed63f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentCountArgs.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class EntertainmentCountArgs {
+ @ApiProperty({
+ required: false,
+ type: () => EntertainmentWhereInput,
+ })
+ @Field(() => EntertainmentWhereInput, { nullable: true })
+ @Type(() => EntertainmentWhereInput)
+ where?: EntertainmentWhereInput;
+}
+
+export { EntertainmentCountArgs as EntertainmentCountArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentCreateInput.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentCreateInput.ts
new file mode 100644
index 0000000..cf1f9c4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentCreateInput.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsJSONValue } from "../../validators";
+import { IsOptional, IsString, MaxLength, IsEnum } from "class-validator";
+import { GraphQLJSON } from "graphql-type-json";
+import { InputJsonValue } from "../../types";
+import { EnumEntertainmentTypeField } from "./EnumEntertainmentTypeField";
+
+@InputType()
+class EntertainmentCreateInput {
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ details?: InputJsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ name?: string | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumEntertainmentTypeField,
+ })
+ @IsEnum(EnumEntertainmentTypeField)
+ @IsOptional()
+ @Field(() => EnumEntertainmentTypeField, {
+ nullable: true,
+ })
+ typeField?: "Option1" | null;
+}
+
+export { EntertainmentCreateInput as EntertainmentCreateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentFindManyArgs.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentFindManyArgs.ts
new file mode 100644
index 0000000..ce7a3c1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentFindManyArgs.ts
@@ -0,0 +1,62 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+import { IsOptional, ValidateNested, IsInt } from "class-validator";
+import { Type } from "class-transformer";
+import { EntertainmentOrderByInput } from "./EntertainmentOrderByInput";
+
+@ArgsType()
+class EntertainmentFindManyArgs {
+ @ApiProperty({
+ required: false,
+ type: () => EntertainmentWhereInput,
+ })
+ @IsOptional()
+ @ValidateNested()
+ @Field(() => EntertainmentWhereInput, { nullable: true })
+ @Type(() => EntertainmentWhereInput)
+ where?: EntertainmentWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: [EntertainmentOrderByInput],
+ })
+ @IsOptional()
+ @ValidateNested({ each: true })
+ @Field(() => [EntertainmentOrderByInput], { nullable: true })
+ @Type(() => EntertainmentOrderByInput)
+ orderBy?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ skip?: number;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ take?: number;
+}
+
+export { EntertainmentFindManyArgs as EntertainmentFindManyArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentFindUniqueArgs.ts
new file mode 100644
index 0000000..d51d085
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentFindUniqueArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class EntertainmentFindUniqueArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EntertainmentWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentWhereUniqueInput)
+ @Field(() => EntertainmentWhereUniqueInput, { nullable: false })
+ where!: EntertainmentWhereUniqueInput;
+}
+
+export { EntertainmentFindUniqueArgs as EntertainmentFindUniqueArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentListRelationFilter.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentListRelationFilter.ts
new file mode 100644
index 0000000..d01cec4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentListRelationFilter.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+import { ValidateNested, IsOptional } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class EntertainmentListRelationFilter {
+ @ApiProperty({
+ required: false,
+ type: () => EntertainmentWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentWhereInput)
+ @IsOptional()
+ @Field(() => EntertainmentWhereInput, {
+ nullable: true,
+ })
+ every?: EntertainmentWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => EntertainmentWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentWhereInput)
+ @IsOptional()
+ @Field(() => EntertainmentWhereInput, {
+ nullable: true,
+ })
+ some?: EntertainmentWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => EntertainmentWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentWhereInput)
+ @IsOptional()
+ @Field(() => EntertainmentWhereInput, {
+ nullable: true,
+ })
+ none?: EntertainmentWhereInput;
+}
+export { EntertainmentListRelationFilter as EntertainmentListRelationFilter };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentOrderByInput.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentOrderByInput.ts
new file mode 100644
index 0000000..db7d02b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentOrderByInput.ts
@@ -0,0 +1,89 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsOptional, IsEnum } from "class-validator";
+import { SortOrder } from "../../util/SortOrder";
+
+@InputType({
+ isAbstract: true,
+ description: undefined,
+})
+class EntertainmentOrderByInput {
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ createdAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ details?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ id?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ name?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ typeField?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ updatedAt?: SortOrder;
+}
+
+export { EntertainmentOrderByInput as EntertainmentOrderByInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentUpdateInput.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentUpdateInput.ts
new file mode 100644
index 0000000..5b853f0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentUpdateInput.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsJSONValue } from "../../validators";
+import { IsOptional, IsString, MaxLength, IsEnum } from "class-validator";
+import { GraphQLJSON } from "graphql-type-json";
+import { InputJsonValue } from "../../types";
+import { EnumEntertainmentTypeField } from "./EnumEntertainmentTypeField";
+
+@InputType()
+class EntertainmentUpdateInput {
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ details?: InputJsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ name?: string | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumEntertainmentTypeField,
+ })
+ @IsEnum(EnumEntertainmentTypeField)
+ @IsOptional()
+ @Field(() => EnumEntertainmentTypeField, {
+ nullable: true,
+ })
+ typeField?: "Option1" | null;
+}
+
+export { EntertainmentUpdateInput as EntertainmentUpdateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentWhereInput.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentWhereInput.ts
new file mode 100644
index 0000000..f7b6fbb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentWhereInput.ts
@@ -0,0 +1,68 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { JsonFilter } from "../../util/JsonFilter";
+import { Type } from "class-transformer";
+import { IsOptional, IsEnum } from "class-validator";
+import { StringFilter } from "../../util/StringFilter";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { EnumEntertainmentTypeField } from "./EnumEntertainmentTypeField";
+
+@InputType()
+class EntertainmentWhereInput {
+ @ApiProperty({
+ required: false,
+ type: JsonFilter,
+ })
+ @Type(() => JsonFilter)
+ @IsOptional()
+ @Field(() => JsonFilter, {
+ nullable: true,
+ })
+ details?: JsonFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ id?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ name?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumEntertainmentTypeField,
+ })
+ @IsEnum(EnumEntertainmentTypeField)
+ @IsOptional()
+ @Field(() => EnumEntertainmentTypeField, {
+ nullable: true,
+ })
+ typeField?: "Option1";
+}
+
+export { EntertainmentWhereInput as EntertainmentWhereInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentWhereUniqueInput.ts
new file mode 100644
index 0000000..5f63355
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EntertainmentWhereUniqueInput.ts
@@ -0,0 +1,27 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString } from "class-validator";
+
+@InputType()
+class EntertainmentWhereUniqueInput {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+}
+
+export { EntertainmentWhereUniqueInput as EntertainmentWhereUniqueInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/EnumEntertainmentTypeField.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EnumEntertainmentTypeField.ts
new file mode 100644
index 0000000..1dfa17c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/EnumEntertainmentTypeField.ts
@@ -0,0 +1,20 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { registerEnumType } from "@nestjs/graphql";
+
+export enum EnumEntertainmentTypeField {
+ Option_1 = "Option1",
+}
+
+registerEnumType(EnumEntertainmentTypeField, {
+ name: "EnumEntertainmentTypeField",
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/UpdateEntertainmentArgs.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/UpdateEntertainmentArgs.ts
new file mode 100644
index 0000000..10156a2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/UpdateEntertainmentArgs.ts
@@ -0,0 +1,40 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { EntertainmentUpdateInput } from "./EntertainmentUpdateInput";
+
+@ArgsType()
+class UpdateEntertainmentArgs {
+ @ApiProperty({
+ required: true,
+ type: () => EntertainmentWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentWhereUniqueInput)
+ @Field(() => EntertainmentWhereUniqueInput, { nullable: false })
+ where!: EntertainmentWhereUniqueInput;
+
+ @ApiProperty({
+ required: true,
+ type: () => EntertainmentUpdateInput,
+ })
+ @ValidateNested()
+ @Type(() => EntertainmentUpdateInput)
+ @Field(() => EntertainmentUpdateInput, { nullable: false })
+ data!: EntertainmentUpdateInput;
+}
+
+export { UpdateEntertainmentArgs as UpdateEntertainmentArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.controller.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.controller.base.spec.ts
new file mode 100644
index 0000000..f77f3f1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.controller.base.spec.ts
@@ -0,0 +1,194 @@
+import { Test } from "@nestjs/testing";
+import {
+ INestApplication,
+ HttpStatus,
+ ExecutionContext,
+ CallHandler,
+} from "@nestjs/common";
+import request from "supertest";
+import { ACGuard } from "nest-access-control";
+import { DefaultAuthGuard } from "../../auth/defaultAuth.guard";
+import { ACLModule } from "../../auth/acl.module";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { map } from "rxjs";
+import { EntertainmentController } from "../entertainment.controller";
+import { EntertainmentService } from "../entertainment.service";
+
+const nonExistingId = "nonExistingId";
+const existingId = "existingId";
+const CREATE_INPUT = {
+ createdAt: new Date(),
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+};
+const CREATE_RESULT = {
+ createdAt: new Date(),
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+};
+const FIND_MANY_RESULT = [
+ {
+ createdAt: new Date(),
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+ },
+];
+const FIND_ONE_RESULT = {
+ createdAt: new Date(),
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+};
+
+const service = {
+ createEntertainment() {
+ return CREATE_RESULT;
+ },
+ entertainments: () => FIND_MANY_RESULT,
+ entertainment: ({ where }: { where: { id: string } }) => {
+ switch (where.id) {
+ case existingId:
+ return FIND_ONE_RESULT;
+ case nonExistingId:
+ return null;
+ }
+ },
+};
+
+const basicAuthGuard = {
+ canActivate: (context: ExecutionContext) => {
+ const argumentHost = context.switchToHttp();
+ const request = argumentHost.getRequest();
+ request.user = {
+ roles: ["user"],
+ };
+ return true;
+ },
+};
+
+const acGuard = {
+ canActivate: () => {
+ return true;
+ },
+};
+
+const aclFilterResponseInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle().pipe(
+ map((data) => {
+ return data;
+ })
+ );
+ },
+};
+const aclValidateRequestInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle();
+ },
+};
+
+describe("Entertainment", () => {
+ let app: INestApplication;
+
+ beforeAll(async () => {
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ {
+ provide: EntertainmentService,
+ useValue: service,
+ },
+ ],
+ controllers: [EntertainmentController],
+ imports: [ACLModule],
+ })
+ .overrideGuard(DefaultAuthGuard)
+ .useValue(basicAuthGuard)
+ .overrideGuard(ACGuard)
+ .useValue(acGuard)
+ .overrideInterceptor(AclFilterResponseInterceptor)
+ .useValue(aclFilterResponseInterceptor)
+ .overrideInterceptor(AclValidateRequestInterceptor)
+ .useValue(aclValidateRequestInterceptor)
+ .compile();
+
+ app = moduleRef.createNestApplication();
+ await app.init();
+ });
+
+ test("POST /entertainments", async () => {
+ await request(app.getHttpServer())
+ .post("/entertainments")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("GET /entertainments", async () => {
+ await request(app.getHttpServer())
+ .get("/entertainments")
+ .expect(HttpStatus.OK)
+ .expect([
+ {
+ ...FIND_MANY_RESULT[0],
+ createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(),
+ updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(),
+ },
+ ]);
+ });
+
+ test("GET /entertainments/:id non existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/entertainments"}/${nonExistingId}`)
+ .expect(HttpStatus.NOT_FOUND)
+ .expect({
+ statusCode: HttpStatus.NOT_FOUND,
+ message: `No resource was found for {"${"id"}":"${nonExistingId}"}`,
+ error: "Not Found",
+ });
+ });
+
+ test("GET /entertainments/:id existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/entertainments"}/${existingId}`)
+ .expect(HttpStatus.OK)
+ .expect({
+ ...FIND_ONE_RESULT,
+ createdAt: FIND_ONE_RESULT.createdAt.toISOString(),
+ updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("POST /entertainments existing resource", async () => {
+ const agent = request(app.getHttpServer());
+ await agent
+ .post("/entertainments")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ })
+ .then(function () {
+ agent
+ .post("/entertainments")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CONFLICT)
+ .expect({
+ statusCode: HttpStatus.CONFLICT,
+ });
+ });
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.controller.base.ts
new file mode 100644
index 0000000..83d22bb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.controller.base.ts
@@ -0,0 +1,201 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import * as nestAccessControl from "nest-access-control";
+import * as defaultAuthGuard from "../../auth/defaultAuth.guard";
+import { EntertainmentService } from "../entertainment.service";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { EntertainmentCreateInput } from "./EntertainmentCreateInput";
+import { Entertainment } from "./Entertainment";
+import { EntertainmentFindManyArgs } from "./EntertainmentFindManyArgs";
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+import { EntertainmentUpdateInput } from "./EntertainmentUpdateInput";
+
+@swagger.ApiBearerAuth()
+@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard)
+export class EntertainmentControllerBase {
+ constructor(
+ protected readonly service: EntertainmentService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Entertainment })
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "create",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async createEntertainment(
+ @common.Body() data: EntertainmentCreateInput
+ ): Promise {
+ return await this.service.createEntertainment({
+ data: data,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Entertainment] })
+ @ApiNestedQuery(EntertainmentFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "read",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async entertainments(
+ @common.Req() request: Request
+ ): Promise {
+ const args = plainToClass(EntertainmentFindManyArgs, request.query);
+ return this.service.entertainments({
+ ...args,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Entertainment })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "read",
+ possession: "own",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async entertainment(
+ @common.Param() params: EntertainmentWhereUniqueInput
+ ): Promise {
+ const result = await this.service.entertainment({
+ where: params,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Entertainment })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "update",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async updateEntertainment(
+ @common.Param() params: EntertainmentWhereUniqueInput,
+ @common.Body() data: EntertainmentUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateEntertainment({
+ where: params,
+ data: data,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Entertainment })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "delete",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async deleteEntertainment(
+ @common.Param() params: EntertainmentWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteEntertainment({
+ where: params,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.grpc.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.grpc.controller.base.ts
new file mode 100644
index 0000000..a87bd24
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.grpc.controller.base.ts
@@ -0,0 +1,155 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import { GrpcMethod } from "@nestjs/microservices";
+import { EntertainmentService } from "../entertainment.service";
+import { EntertainmentCreateInput } from "./EntertainmentCreateInput";
+import { EntertainmentWhereInput } from "./EntertainmentWhereInput";
+import { EntertainmentWhereUniqueInput } from "./EntertainmentWhereUniqueInput";
+import { EntertainmentFindManyArgs } from "./EntertainmentFindManyArgs";
+import { EntertainmentUpdateInput } from "./EntertainmentUpdateInput";
+import { Entertainment } from "./Entertainment";
+
+export class EntertainmentGrpcControllerBase {
+ constructor(protected readonly service: EntertainmentService) {}
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Entertainment })
+ @GrpcMethod("EntertainmentService", "createEntertainment")
+ async createEntertainment(
+ @common.Body() data: EntertainmentCreateInput
+ ): Promise {
+ return await this.service.createEntertainment({
+ data: data,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Entertainment] })
+ @ApiNestedQuery(EntertainmentFindManyArgs)
+ @GrpcMethod("EntertainmentService", "entertainments")
+ async entertainments(
+ @common.Req() request: Request
+ ): Promise {
+ const args = plainToClass(EntertainmentFindManyArgs, request.query);
+ return this.service.entertainments({
+ ...args,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ }
+
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Entertainment })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("EntertainmentService", "entertainment")
+ async entertainment(
+ @common.Param() params: EntertainmentWhereUniqueInput
+ ): Promise {
+ const result = await this.service.entertainment({
+ where: params,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Entertainment })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("EntertainmentService", "updateEntertainment")
+ async updateEntertainment(
+ @common.Param() params: EntertainmentWhereUniqueInput,
+ @common.Body() data: EntertainmentUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateEntertainment({
+ where: params,
+ data: data,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Entertainment })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("EntertainmentService", "deleteEntertainment")
+ async deleteEntertainment(
+ @common.Param() params: EntertainmentWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteEntertainment({
+ where: params,
+ select: {
+ createdAt: true,
+ details: true,
+ id: true,
+ name: true,
+ typeField: true,
+ updatedAt: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.module.base.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.module.base.ts
new file mode 100644
index 0000000..919ea0c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.module.base.ts
@@ -0,0 +1,18 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { Module } from "@nestjs/common";
+import { ACLModule } from "../../auth/acl.module";
+@Module({
+ imports: [ACLModule],
+ exports: [ACLModule],
+})
+export class EntertainmentModuleBase {}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.resolver.base.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.resolver.base.ts
new file mode 100644
index 0000000..8d07691
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.resolver.base.ts
@@ -0,0 +1,144 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as graphql from "@nestjs/graphql";
+import { GraphQLError } from "graphql";
+import { isRecordNotFoundError } from "../../prisma.util";
+import { MetaQueryPayload } from "../../util/MetaQueryPayload";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { Entertainment } from "./Entertainment";
+import { EntertainmentCountArgs } from "./EntertainmentCountArgs";
+import { EntertainmentFindManyArgs } from "./EntertainmentFindManyArgs";
+import { EntertainmentFindUniqueArgs } from "./EntertainmentFindUniqueArgs";
+import { CreateEntertainmentArgs } from "./CreateEntertainmentArgs";
+import { UpdateEntertainmentArgs } from "./UpdateEntertainmentArgs";
+import { DeleteEntertainmentArgs } from "./DeleteEntertainmentArgs";
+import { EntertainmentService } from "../entertainment.service";
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Entertainment)
+export class EntertainmentResolverBase {
+ constructor(
+ protected readonly service: EntertainmentService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+
+ @graphql.Query(() => MetaQueryPayload)
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "read",
+ possession: "any",
+ })
+ async _entertainmentsMeta(
+ @graphql.Args() args: EntertainmentCountArgs
+ ): Promise {
+ const result = await this.service.count(args);
+ return {
+ count: result,
+ };
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => [Entertainment])
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "read",
+ possession: "any",
+ })
+ async entertainments(
+ @graphql.Args() args: EntertainmentFindManyArgs
+ ): Promise {
+ return this.service.entertainments(args);
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => Entertainment, { nullable: true })
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "read",
+ possession: "own",
+ })
+ async entertainment(
+ @graphql.Args() args: EntertainmentFindUniqueArgs
+ ): Promise {
+ const result = await this.service.entertainment(args);
+ if (result === null) {
+ return null;
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Entertainment)
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "create",
+ possession: "any",
+ })
+ async createEntertainment(
+ @graphql.Args() args: CreateEntertainmentArgs
+ ): Promise {
+ return await this.service.createEntertainment({
+ ...args,
+ data: args.data,
+ });
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Entertainment)
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "update",
+ possession: "any",
+ })
+ async updateEntertainment(
+ @graphql.Args() args: UpdateEntertainmentArgs
+ ): Promise {
+ try {
+ return await this.service.updateEntertainment({
+ ...args,
+ data: args.data,
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @graphql.Mutation(() => Entertainment)
+ @nestAccessControl.UseRoles({
+ resource: "Entertainment",
+ action: "delete",
+ possession: "any",
+ })
+ async deleteEntertainment(
+ @graphql.Args() args: DeleteEntertainmentArgs
+ ): Promise {
+ try {
+ return await this.service.deleteEntertainment(args);
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.service.base.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.service.base.ts
new file mode 100644
index 0000000..ef4544d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/base/entertainment.service.base.ts
@@ -0,0 +1,49 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { PrismaService } from "../../prisma/prisma.service";
+import { Prisma, Entertainment as PrismaEntertainment } from "@prisma/client";
+
+export class EntertainmentServiceBase {
+ constructor(protected readonly prisma: PrismaService) {}
+
+ async count(
+ args: Omit
+ ): Promise {
+ return this.prisma.entertainment.count(args);
+ }
+
+ async entertainments(
+ args: Prisma.EntertainmentFindManyArgs
+ ): Promise {
+ return this.prisma.entertainment.findMany(args);
+ }
+ async entertainment(
+ args: Prisma.EntertainmentFindUniqueArgs
+ ): Promise {
+ return this.prisma.entertainment.findUnique(args);
+ }
+ async createEntertainment(
+ args: Prisma.EntertainmentCreateArgs
+ ): Promise {
+ return this.prisma.entertainment.create(args);
+ }
+ async updateEntertainment(
+ args: Prisma.EntertainmentUpdateArgs
+ ): Promise {
+ return this.prisma.entertainment.update(args);
+ }
+ async deleteEntertainment(
+ args: Prisma.EntertainmentDeleteArgs
+ ): Promise {
+ return this.prisma.entertainment.delete(args);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.controller.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.controller.ts
new file mode 100644
index 0000000..6779ec4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.controller.ts
@@ -0,0 +1,17 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import * as nestAccessControl from "nest-access-control";
+import { EntertainmentService } from "./entertainment.service";
+import { EntertainmentControllerBase } from "./base/entertainment.controller.base";
+
+@swagger.ApiTags("entertainments")
+@common.Controller("entertainments")
+export class EntertainmentController extends EntertainmentControllerBase {
+ constructor(
+ protected readonly service: EntertainmentService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.grpc.controller.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.grpc.controller.ts
new file mode 100644
index 0000000..42405bf
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.grpc.controller.ts
@@ -0,0 +1,12 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { EntertainmentService } from "./entertainment.service";
+import { EntertainmentGrpcControllerBase } from "./base/entertainment.grpc.controller.base";
+
+@swagger.ApiTags("entertainments")
+@common.Controller("entertainments")
+export class EntertainmentGrpcController extends EntertainmentGrpcControllerBase {
+ constructor(protected readonly service: EntertainmentService) {
+ super(service);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.module.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.module.ts
new file mode 100644
index 0000000..548929b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.module.ts
@@ -0,0 +1,15 @@
+import { Module, forwardRef } from "@nestjs/common";
+import { AuthModule } from "../auth/auth.module";
+import { EntertainmentModuleBase } from "./base/entertainment.module.base";
+import { EntertainmentService } from "./entertainment.service";
+import { EntertainmentController } from "./entertainment.controller";
+import { EntertainmentGrpcController } from "./entertainment.grpc.controller";
+import { EntertainmentResolver } from "./entertainment.resolver";
+
+@Module({
+ imports: [EntertainmentModuleBase, forwardRef(() => AuthModule)],
+ controllers: [EntertainmentController, EntertainmentGrpcController],
+ providers: [EntertainmentService, EntertainmentResolver],
+ exports: [EntertainmentService],
+})
+export class EntertainmentModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.proto b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.proto
new file mode 100644
index 0000000..bc353ed
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.proto
@@ -0,0 +1,45 @@
+syntax = "proto3";
+
+ package entertainment;
+service EntertainmentService {
+ rpc createEntertainment (EntertainmentCreateInput) returns (Entertainment) {}
+rpc entertainments (findManyParams) returns (stream Entertainment) {}
+rpc entertainment (EntertainmentWhereUniqueInput) returns (Entertainment) {}
+rpc updateEntertainment (EntertainmentUpdateInput) returns (Entertainment) {}
+rpc deleteEntertainment (EntertainmentWhereUniqueInput) returns (Entertainment) {}
+ }
+message EntertainmentCreateInput {
+string createdAt = 1;
+string details = 2;
+string id = 3;
+string name = 4;
+repeated string typeField = 5;
+string updatedAt = 6;
+};
+message Entertainment {
+string createdAt = 1;
+string details = 2;
+string id = 3;
+string name = 4;
+repeated string typeField = 5;
+string updatedAt = 6;
+};
+message EntertainmentWhereUniqueInput {
+string createdAt = 1;
+string details = 2;
+string id = 3;
+string name = 4;
+repeated string typeField = 5;
+string updatedAt = 6;
+};
+message EntertainmentUpdateInput {
+string createdAt = 1;
+string details = 2;
+string id = 3;
+string name = 4;
+repeated string typeField = 5;
+string updatedAt = 6;
+};
+message findManyParams {
+
+};
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.resolver.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.resolver.ts
new file mode 100644
index 0000000..b8fbda6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.resolver.ts
@@ -0,0 +1,20 @@
+import * as graphql from "@nestjs/graphql";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { EntertainmentResolverBase } from "./base/entertainment.resolver.base";
+import { Entertainment } from "./base/Entertainment";
+import { EntertainmentService } from "./entertainment.service";
+
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Entertainment)
+export class EntertainmentResolver extends EntertainmentResolverBase {
+ constructor(
+ protected readonly service: EntertainmentService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.service.ts b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.service.ts
new file mode 100644
index 0000000..8701589
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/entertainment/entertainment.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../prisma/prisma.service";
+import { EntertainmentServiceBase } from "./base/entertainment.service.base";
+
+@Injectable()
+export class EntertainmentService extends EntertainmentServiceBase {
+ constructor(protected readonly prisma: PrismaService) {
+ super(prisma);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/errors.ts b/apps/vesst-discord-bot-backend-server/src/errors.ts
new file mode 100644
index 0000000..bd1aa6d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/errors.ts
@@ -0,0 +1,16 @@
+import * as common from "@nestjs/common";
+import { ApiProperty } from "@nestjs/swagger";
+
+export class ForbiddenException extends common.ForbiddenException {
+ @ApiProperty()
+ statusCode!: number;
+ @ApiProperty()
+ message!: string;
+}
+
+export class NotFoundException extends common.NotFoundException {
+ @ApiProperty()
+ statusCode!: number;
+ @ApiProperty()
+ message!: string;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/filters/HttpExceptions.filter.ts b/apps/vesst-discord-bot-backend-server/src/filters/HttpExceptions.filter.ts
new file mode 100644
index 0000000..f5eda8e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/filters/HttpExceptions.filter.ts
@@ -0,0 +1,89 @@
+import {
+ ArgumentsHost,
+ Catch,
+ HttpException,
+ HttpServer,
+ HttpStatus,
+} from "@nestjs/common";
+import { BaseExceptionFilter } from "@nestjs/core";
+import { Prisma } from "@prisma/client";
+import { Response } from "express";
+
+export type ErrorCodesStatusMapping = {
+ [key: string]: number;
+};
+
+/**
+ * {@link PrismaClientExceptionFilter} handling {@link Prisma.PrismaClientKnownRequestError} exceptions.
+ */
+@Catch(Prisma?.PrismaClientKnownRequestError)
+export class HttpExceptionFilter extends BaseExceptionFilter {
+ /**
+ * default error codes mapping
+ *
+ * Error codes definition for Prisma Client (Query Engine)
+ * @see https://www.prisma.io/docs/reference/api-reference/error-reference#prisma-client-query-engine
+ */
+ private errorCodesStatusMapping: ErrorCodesStatusMapping = {
+ P2000: HttpStatus.BAD_REQUEST,
+ P2002: HttpStatus.CONFLICT,
+ P2025: HttpStatus.NOT_FOUND,
+ };
+
+ /**
+ * @param applicationRef
+ */
+ // eslint-disable-next-line @typescript-eslint/no-useless-constructor
+ constructor(applicationRef?: HttpServer) {
+ super(applicationRef);
+ }
+
+ /**
+ * @param exception
+ * @param host
+ * @returns
+ */
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+ catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
+ const statusCode = this.errorCodesStatusMapping[exception.code];
+ let message;
+ if (host.getType() === "http") {
+ // for http requests (REST)
+ // Todo : Add all other exception types and also add mapping
+ const ctx = host.switchToHttp();
+ const response = ctx.getResponse();
+ if (exception.code === "P2002") {
+ // Handling Unique Key Constraint Violation Error
+ const fields = (exception.meta as { target: string[] }).target;
+ message = `Another record with the requested (${fields.join(
+ ", "
+ )}) already exists`;
+ } else {
+ message =
+ `[${exception.code}]: ` +
+ this.exceptionShortMessage(exception.message);
+ }
+ if (!Object.keys(this.errorCodesStatusMapping).includes(exception.code)) {
+ return super.catch(exception, host);
+ }
+ const errorResponse = {
+ message: message,
+ statusCode: statusCode,
+ };
+ response.status(statusCode).send(errorResponse);
+ }
+ return new HttpException({ statusCode, message }, statusCode);
+ }
+
+ /**
+ * @param exception
+ * @returns short message for the exception
+ */
+ exceptionShortMessage(message: string): string {
+ const shortMessage = message.substring(message.indexOf("→"));
+ return shortMessage
+ .substring(shortMessage.indexOf("\n"))
+ .replace(/\n/g, "")
+ .trim();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/grants.json b/apps/vesst-discord-bot-backend-server/src/grants.json
new file mode 100644
index 0000000..c82f0e4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/grants.json
@@ -0,0 +1,212 @@
+[
+ {
+ "role": "user",
+ "resource": "Slot",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Slot",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Slot",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Slot",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Slot",
+ "action": "read:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Vouch",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Vouch",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Vouch",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Vouch",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Vouch",
+ "action": "read:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Embed",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Embed",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Embed",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Embed",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Embed",
+ "action": "read:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Ticket",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Ticket",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Ticket",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Ticket",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Ticket",
+ "action": "read:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Security",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Security",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Security",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Security",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Security",
+ "action": "read:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Entertainment",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Entertainment",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Entertainment",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Entertainment",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "Entertainment",
+ "action": "read:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "User",
+ "action": "read:own",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "User",
+ "action": "create:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "User",
+ "action": "update:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "User",
+ "action": "delete:any",
+ "attributes": "*"
+ },
+ {
+ "role": "user",
+ "resource": "User",
+ "action": "read:any",
+ "attributes": "*"
+ }
+]
diff --git a/apps/vesst-discord-bot-backend-server/src/grpc.client.options.ts b/apps/vesst-discord-bot-backend-server/src/grpc.client.options.ts
new file mode 100644
index 0000000..d6d063b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/grpc.client.options.ts
@@ -0,0 +1,21 @@
+import { ClientOptions, Transport } from "@nestjs/microservices";
+import { ConfigService } from "@nestjs/config";
+
+const configService: ConfigService = new ConfigService();
+
+export const grpcClientOptions: ClientOptions = {
+ transport: Transport.GRPC,
+ options: {
+ package: ["slot", "vouch", "embed", "ticket", "security", "entertainment", "user"],
+ protoPath: [
+ "src/slot/slot.proto",
+ "src/vouch/vouch.proto",
+ "src/embed/embed.proto",
+ "src/ticket/ticket.proto",
+ "src/security/security.proto",
+ "src/entertainment/entertainment.proto",
+ "src/user/user.proto"
+ ],
+ url: configService.get("GRPC_CLIENT_URL_PATH"),
+ },
+};
diff --git a/apps/vesst-discord-bot-backend-server/src/health/base/health.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/health/base/health.controller.base.ts
new file mode 100644
index 0000000..afd9e0d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/health/base/health.controller.base.ts
@@ -0,0 +1,19 @@
+import { Get, HttpStatus, Res } from "@nestjs/common";
+import { Response } from "express";
+import { HealthService } from "../health.service";
+
+export class HealthControllerBase {
+ constructor(protected readonly healthService: HealthService) {}
+ @Get("live")
+ healthLive(@Res() response: Response): Response {
+ return response.status(HttpStatus.NO_CONTENT).send();
+ }
+ @Get("ready")
+ async healthReady(@Res() response: Response): Promise> {
+ const dbConnection = await this.healthService.isDbReady();
+ if (!dbConnection) {
+ return response.status(HttpStatus.NOT_FOUND).send();
+ }
+ return response.status(HttpStatus.NO_CONTENT).send();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/health/base/health.service.base.ts b/apps/vesst-discord-bot-backend-server/src/health/base/health.service.base.ts
new file mode 100644
index 0000000..e115eff
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/health/base/health.service.base.ts
@@ -0,0 +1,17 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../../prisma/prisma.service";
+
+@Injectable()
+export class HealthServiceBase {
+ constructor(protected readonly prisma: PrismaService) {}
+ async isDbReady(): Promise {
+ try {
+ await this.prisma.$runCommandRaw({
+ select: 1,
+ });
+ return true;
+ } catch (error) {
+ return false;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/health/health.controller.ts b/apps/vesst-discord-bot-backend-server/src/health/health.controller.ts
new file mode 100644
index 0000000..ff484e7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/health/health.controller.ts
@@ -0,0 +1,10 @@
+import { Controller } from "@nestjs/common";
+import { HealthControllerBase } from "./base/health.controller.base";
+import { HealthService } from "./health.service";
+
+@Controller("_health")
+export class HealthController extends HealthControllerBase {
+ constructor(protected readonly healthService: HealthService) {
+ super(healthService);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/health/health.module.ts b/apps/vesst-discord-bot-backend-server/src/health/health.module.ts
new file mode 100644
index 0000000..39eff7f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/health/health.module.ts
@@ -0,0 +1,10 @@
+import { Module } from "@nestjs/common";
+import { HealthController } from "./health.controller";
+import { HealthService } from "./health.service";
+
+@Module({
+ controllers: [HealthController],
+ providers: [HealthService],
+ exports: [HealthService],
+})
+export class HealthModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/health/health.service.ts b/apps/vesst-discord-bot-backend-server/src/health/health.service.ts
new file mode 100644
index 0000000..44d9343
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/health/health.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../prisma/prisma.service";
+import { HealthServiceBase } from "./base/health.service.base";
+
+@Injectable()
+export class HealthService extends HealthServiceBase {
+ constructor(protected readonly prisma: PrismaService) {
+ super(prisma);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/interceptors/aclFilterResponse.interceptor.ts b/apps/vesst-discord-bot-backend-server/src/interceptors/aclFilterResponse.interceptor.ts
new file mode 100644
index 0000000..5eeba18
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/interceptors/aclFilterResponse.interceptor.ts
@@ -0,0 +1,42 @@
+import {
+ CallHandler,
+ ExecutionContext,
+ Injectable,
+ NestInterceptor,
+} from "@nestjs/common";
+import { Observable } from "rxjs";
+import { map } from "rxjs/operators";
+import { InjectRolesBuilder, RolesBuilder } from "nest-access-control";
+import { Reflector } from "@nestjs/core";
+
+@Injectable()
+export class AclFilterResponseInterceptor implements NestInterceptor {
+ constructor(
+ @InjectRolesBuilder() private readonly rolesBuilder: RolesBuilder,
+ private readonly reflector: Reflector
+ ) {}
+
+ intercept(context: ExecutionContext, next: CallHandler): Observable {
+ const [permissionsRoles]: any = this.reflector.getAllAndMerge(
+ "roles",
+ [context.getHandler(), context.getClass()]
+ );
+
+ const permission = this.rolesBuilder.permission({
+ role: permissionsRoles.role,
+ action: permissionsRoles.action,
+ possession: permissionsRoles.possession,
+ resource: permissionsRoles.resource,
+ });
+
+ return next.handle().pipe(
+ map((data) => {
+ if (Array.isArray(data)) {
+ return data.map((results: any) => permission.filter(results));
+ } else {
+ return permission.filter(data);
+ }
+ })
+ );
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/interceptors/aclValidateRequest.interceptor.ts b/apps/vesst-discord-bot-backend-server/src/interceptors/aclValidateRequest.interceptor.ts
new file mode 100644
index 0000000..6d30246
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/interceptors/aclValidateRequest.interceptor.ts
@@ -0,0 +1,53 @@
+import {
+ CallHandler,
+ ExecutionContext,
+ Injectable,
+ NestInterceptor,
+} from "@nestjs/common";
+import { Observable } from "rxjs";
+import { InjectRolesBuilder, RolesBuilder } from "nest-access-control";
+import { Reflector } from "@nestjs/core";
+import * as abacUtil from "../auth/abac.util";
+import { ForbiddenException } from "../errors";
+
+@Injectable()
+export class AclValidateRequestInterceptor implements NestInterceptor {
+ constructor(
+ @InjectRolesBuilder() private readonly rolesBuilder: RolesBuilder,
+ private readonly reflector: Reflector
+ ) {}
+
+ intercept(context: ExecutionContext, next: CallHandler): Observable {
+ const [permissionsRoles]: any = this.reflector.getAllAndMerge(
+ "roles",
+ [context.getHandler(), context.getClass()]
+ );
+
+ const type = context.getType();
+
+ const inputDataToValidate =
+ type === "http"
+ ? context.switchToHttp().getRequest().body
+ : context.getArgByIndex(1).data;
+
+ const permission = this.rolesBuilder.permission({
+ role: permissionsRoles.role,
+ action: permissionsRoles.action,
+ possession: permissionsRoles.possession,
+ resource: permissionsRoles.resource,
+ });
+
+ const invalidAttributes = abacUtil.getInvalidAttributes(
+ permission,
+ inputDataToValidate
+ );
+
+ if (invalidAttributes.length) {
+ throw new ForbiddenException(
+ "Insufficient privileges to complete the operation"
+ );
+ }
+
+ return next.handle();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/kafka/kafka.controller.ts b/apps/vesst-discord-bot-backend-server/src/kafka/kafka.controller.ts
new file mode 100644
index 0000000..38cccf8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/kafka/kafka.controller.ts
@@ -0,0 +1,10 @@
+import {
+ Ctx,
+ EventPattern,
+ KafkaContext,
+ Payload,
+} from "@nestjs/microservices";
+import { Controller } from "@nestjs/common";
+
+@Controller("kafka-controller")
+export class KafkaController {}
diff --git a/apps/vesst-discord-bot-backend-server/src/logger/logger.config.ts b/apps/vesst-discord-bot-backend-server/src/logger/logger.config.ts
new file mode 100644
index 0000000..aca2189
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/logger/logger.config.ts
@@ -0,0 +1,41 @@
+import { ConfigService } from "@nestjs/config";
+import { Params } from "nestjs-pino";
+
+const ADDITIONAL_LOG_PROPERTIES = {};;
+
+export const LoggerConfiguration = (configService: ConfigService): Params => {
+ const logLevel = configService.getOrThrow("LOG_LEVEL");
+ const serviceName = configService.getOrThrow("SERVICE_NAME") ?? "";
+ const sensitiveKeys = configService.get("SENSITIVE_KEYS")?.split(",") ?? [];
+ const logRequest = configService.get("LOG_REQUEST") === "true";
+ const pinoPretty = configService.get("PINO_PRETTY") === "true";
+
+ const allowedLevels = ["fatal", "error", "warn", "info", "debug", "trace"];
+
+ if (!allowedLevels.includes(logLevel)) {
+ throw new Error(
+ `${logLevel} is not a valid log level. Check your LOG_LEVEL env variable.`,
+ );
+ }
+
+ return {
+ pinoHttp: {
+ level: logLevel,
+ transport: pinoPretty
+ ? {
+ target: "pino-pretty",
+ options: {
+ colorize: true,
+ ignore: "pid,hostname",
+ },
+ }
+ : undefined,
+ redact: {
+ paths: logRequest ? sensitiveKeys : ["req", "res"],
+ remove: logRequest ? false : true,
+ censor: "********",
+ },
+ mixin: () => ({ ...ADDITIONAL_LOG_PROPERTIES, serviceName }),
+ },
+ };
+};
diff --git a/apps/vesst-discord-bot-backend-server/src/logger/logger.module.ts b/apps/vesst-discord-bot-backend-server/src/logger/logger.module.ts
new file mode 100644
index 0000000..4288e9f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/logger/logger.module.ts
@@ -0,0 +1,16 @@
+import { Module } from "@nestjs/common";
+import { ConfigService } from "@nestjs/config";
+import { LoggerModule as PinoLoggerModule } from "nestjs-pino";
+import { LoggerConfiguration } from "./logger.config";
+
+@Module({
+ imports: [
+ PinoLoggerModule.forRootAsync({
+ inject: [ConfigService],
+ useFactory: (config: ConfigService) => LoggerConfiguration(config)
+ })
+ ]
+})
+export class LoggerModule {
+
+}
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/main.ts b/apps/vesst-discord-bot-backend-server/src/main.ts
new file mode 100644
index 0000000..279c61e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/main.ts
@@ -0,0 +1,114 @@
+import { Logger, ValidationPipe } from "@nestjs/common";
+import {
+ AbstractHttpAdapter,
+ HttpAdapterHost,
+ NestFactory,
+} from "@nestjs/core";
+import { OpenAPIObject, SwaggerModule } from "@nestjs/swagger";
+import { HttpExceptionFilter } from "./filters/HttpExceptions.filter";
+import { AppModule } from "./app.module";
+import { connectMicroservices } from "./connectMicroservices";
+import {
+ swaggerPath,
+ swaggerDocumentOptions,
+ swaggerSetupOptions,
+} from "./swagger";
+import fs from "fs";
+import { HttpsOptions } from "@nestjs/common/interfaces/external/https-options.interface";
+import https from "https";
+import http from "http";
+import express from "express";
+import { ExpressAdapter } from "@nestjs/platform-express";
+
+const {
+ PORT = 3000,
+ HTTPS_PORT = 443,
+ APP_MODE,
+ SSL_CERT_PATH,
+ SSL_KEY_PATH,
+ SSL_CA_PATH,
+} = process.env;
+
+const httpsOptions: HttpsOptions = {
+ cert: SSL_CERT_PATH && fs.readFileSync(SSL_CERT_PATH),
+ key: SSL_KEY_PATH && fs.readFileSync(SSL_KEY_PATH),
+ ca: SSL_CA_PATH && fs.readFileSync(SSL_CA_PATH),
+};
+
+function getHttpsServer(
+ server: express.Express,
+ httpsOptions: HttpsOptions,
+ APP_MODE: string | undefined
+) {
+ switch (APP_MODE) {
+ case "http":
+ return { cors: true };
+ case "https":
+ return { httpsOptions, cors: true };
+ case "both":
+ return new ExpressAdapter(server);
+ default:
+ throw new Error(`APP_MODE ${APP_MODE} is not supported`);
+ }
+}
+
+async function main() {
+ const server = express();
+ const app = await NestFactory.create(
+ AppModule,
+ getHttpsServer(server, httpsOptions, APP_MODE) as AbstractHttpAdapter
+ );
+
+ app.setGlobalPrefix("api");
+ app.useGlobalPipes(
+ new ValidationPipe({
+ transform: true,
+ forbidUnknownValues: false,
+ })
+ );
+
+ //This fix is based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#use_within_json
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ BigInt.prototype.toJSON = function () {
+ return this.toString();
+ };
+
+ const document = SwaggerModule.createDocument(app, swaggerDocumentOptions);
+
+ /** check if there is Public decorator for each path (action) and its method (findMany / findOne) on each controller */
+ Object.values((document as OpenAPIObject).paths).forEach((path: any) => {
+ Object.values(path).forEach((method: any) => {
+ if (
+ Array.isArray(method.security) &&
+ method.security.includes("isPublic")
+ ) {
+ method.security = [];
+ }
+ });
+ });
+
+ await connectMicroservices(app);
+ await app.startAllMicroservices();
+
+ SwaggerModule.setup(swaggerPath, app, document, swaggerSetupOptions);
+
+ const { httpAdapter } = app.get(HttpAdapterHost);
+ app.useGlobalFilters(new HttpExceptionFilter(httpAdapter));
+
+ await app.init();
+
+ if (APP_MODE === "both") {
+ Logger.log(`🚀 Running both http and https server`, "NestApplication");
+ // create both http and https server
+ http.createServer(server).listen(PORT);
+ https.createServer(httpsOptions, server).listen(HTTPS_PORT);
+ } else {
+ Logger.log(`🚀 Running ${APP_MODE || "http"} server`, "NestApplication");
+ await app.listen(PORT);
+ }
+
+ return app;
+}
+
+module.exports = main();
diff --git a/apps/vesst-discord-bot-backend-server/src/prisma.util.spec.ts b/apps/vesst-discord-bot-backend-server/src/prisma.util.spec.ts
new file mode 100644
index 0000000..0aa308e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/prisma.util.spec.ts
@@ -0,0 +1,23 @@
+import {
+ isRecordNotFoundError,
+ PRISMA_QUERY_INTERPRETATION_ERROR,
+} from "./prisma.util";
+
+describe("isRecordNotFoundError", () => {
+ test("returns true for record not found error", () => {
+ expect(
+ isRecordNotFoundError(
+ Object.assign(
+ new Error(`Error occurred during query execution:
+ InterpretationError("Error for binding '0': RecordNotFound("Record to update not found.")")`),
+ {
+ code: PRISMA_QUERY_INTERPRETATION_ERROR,
+ }
+ )
+ )
+ ).toBe(true);
+ });
+ test("returns false for any other error", () => {
+ expect(isRecordNotFoundError(new Error())).toBe(false);
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/prisma.util.ts b/apps/vesst-discord-bot-backend-server/src/prisma.util.ts
new file mode 100644
index 0000000..029b98a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/prisma.util.ts
@@ -0,0 +1,29 @@
+export const PRISMA_QUERY_INTERPRETATION_ERROR = "P2016";
+export const PRISMA_RECORD_NOT_FOUND = "RecordNotFound";
+
+export function isRecordNotFoundError(error: any): boolean {
+ return (
+ error instanceof Error &&
+ "code" in error &&
+ error.code === PRISMA_QUERY_INTERPRETATION_ERROR &&
+ error.message.includes(PRISMA_RECORD_NOT_FOUND)
+ );
+}
+
+export async function transformStringFieldUpdateInput<
+ T extends undefined | string | { set?: string }
+>(input: T, transform: (input: string) => Promise): Promise {
+ if (typeof input === "object" && typeof input?.set === "string") {
+ return { set: await transform(input.set) } as T;
+ }
+ if (typeof input === "object") {
+ if (typeof input.set === "string") {
+ return { set: await transform(input.set) } as T;
+ }
+ return input;
+ }
+ if (typeof input === "string") {
+ return (await transform(input)) as T;
+ }
+ return input;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/prisma/prisma.module.ts b/apps/vesst-discord-bot-backend-server/src/prisma/prisma.module.ts
new file mode 100644
index 0000000..1edbf95
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/prisma/prisma.module.ts
@@ -0,0 +1,9 @@
+import { Global, Module } from "@nestjs/common";
+import { PrismaService } from "./prisma.service";
+
+@Global()
+@Module({
+ providers: [PrismaService],
+ exports: [PrismaService],
+})
+export class PrismaModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/prisma/prisma.service.ts b/apps/vesst-discord-bot-backend-server/src/prisma/prisma.service.ts
new file mode 100644
index 0000000..79ea4fa
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/prisma/prisma.service.ts
@@ -0,0 +1,9 @@
+import { Injectable, OnModuleInit, INestApplication } from "@nestjs/common";
+import { PrismaClient } from "@prisma/client";
+
+@Injectable()
+export class PrismaService extends PrismaClient implements OnModuleInit {
+ async onModuleInit() {
+ await this.$connect();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/openai/openai.module.ts b/apps/vesst-discord-bot-backend-server/src/providers/openai/openai.module.ts
new file mode 100644
index 0000000..8b1721c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/openai/openai.module.ts
@@ -0,0 +1,8 @@
+import { Module } from "@nestjs/common";
+import { OpenaiService } from "./openai.service";
+
+@Module({
+ providers: [OpenaiService],
+ exports: [OpenaiService],
+})
+export class OpenAIModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/openai/openai.service.ts b/apps/vesst-discord-bot-backend-server/src/providers/openai/openai.service.ts
new file mode 100644
index 0000000..b730394
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/openai/openai.service.ts
@@ -0,0 +1,58 @@
+import { Injectable } from "@nestjs/common";
+import OpenAI from "openai";
+
+export type CreateChatCompletionRequestSettings = Omit<
+ OpenAI.Chat.ChatCompletionCreateParamsNonStreaming,
+ "model" | "messages"
+>;
+
+export type ChatCompletionMessageParam = OpenAI.Chat.ChatCompletionMessageParam;
+
+const CREATE_CHAT_COMPLETION_DEFAULT_SETTINGS: CreateChatCompletionRequestSettings =
+ {
+ temperature: 1,
+ max_tokens: 2048,
+ top_p: 1,
+ frequency_penalty: 0,
+ presence_penalty: 0,
+ };
+
+@Injectable()
+export class OpenaiService {
+ constructor() {}
+
+ async createChatCompletion(
+ model: string,
+ messages: OpenAI.Chat.ChatCompletionMessageParam[],
+ requestSettings?: CreateChatCompletionRequestSettings
+ ): Promise {
+ const openai = new OpenAI({
+ apiKey: process.env.OPENAI_API_KEY,
+ });
+
+ const settings = {
+ ...CREATE_CHAT_COMPLETION_DEFAULT_SETTINGS,
+ ...requestSettings,
+ };
+
+ const response = await openai.chat.completions.create({
+ ...settings,
+ model: model,
+ messages: messages,
+ });
+
+ try{
+
+
+ const results = response.choices[0].message?.content || "";
+
+ return results;
+
+ } catch (error) {
+ if (error instanceof OpenAI.APIError) {
+ // Add custom error handling here. Check codes: https://github.com/openai/openai-node?tab=readme-ov-file#handling-errors
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/secrets/base/secretsManager.service.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/providers/secrets/base/secretsManager.service.base.spec.ts
new file mode 100644
index 0000000..f161172
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/secrets/base/secretsManager.service.base.spec.ts
@@ -0,0 +1,41 @@
+import { ConfigService } from "@nestjs/config";
+import { mock } from "jest-mock-extended";
+import { SecretsManagerServiceBase } from "./secretsManager.service.base";
+import { EnumSecretsNameKey } from "../secretsNameKey.enum";
+
+describe("Testing the secrets manager base class", () => {
+ const SECRET_KEY = "SECRET_KEY";
+ const SECRET_VALUE = "SECRET_VALUE";
+ const configService = mock();
+ const secretsManagerServiceBase = new SecretsManagerServiceBase(
+ configService
+ );
+ beforeEach(() => {
+ configService.get.mockClear();
+ });
+ it("should return value from env", async () => {
+ //ARRANGE
+ configService.get.mockReturnValue(SECRET_VALUE);
+ //ACT
+ const result = await secretsManagerServiceBase.getSecret(
+ SECRET_KEY as unknown as EnumSecretsNameKey
+ );
+ //ASSERT
+ expect(result).toBe(SECRET_VALUE);
+ });
+ it("should return null for unknown keys", async () => {
+ //ARRANGE
+ configService.get.mockReturnValue(undefined);
+ //ACT
+ const result = await secretsManagerServiceBase.getSecret(
+ SECRET_KEY as unknown as EnumSecretsNameKey
+ );
+ //ASSERT
+ expect(result).toBeNull();
+ });
+ it("should throw an exception if getting null key", () => {
+ return expect(
+ secretsManagerServiceBase.getSecret(null as unknown as EnumSecretsNameKey)
+ ).rejects.toThrow();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/secrets/base/secretsManager.service.base.ts b/apps/vesst-discord-bot-backend-server/src/providers/secrets/base/secretsManager.service.base.ts
new file mode 100644
index 0000000..340818c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/secrets/base/secretsManager.service.base.ts
@@ -0,0 +1,17 @@
+import { ConfigService } from "@nestjs/config";
+import { EnumSecretsNameKey } from "../secretsNameKey.enum";
+
+export interface ISecretsManager {
+ getSecret: (key: EnumSecretsNameKey) => Promise;
+}
+
+export class SecretsManagerServiceBase implements ISecretsManager {
+ constructor(protected readonly configService: ConfigService) {}
+ async getSecret(key: EnumSecretsNameKey): Promise {
+ const value = this.configService.get(key.toString());
+ if (value) {
+ return value;
+ }
+ return null;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsManager.module.ts b/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsManager.module.ts
new file mode 100644
index 0000000..3a621e4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsManager.module.ts
@@ -0,0 +1,8 @@
+import { Module } from "@nestjs/common";
+import { SecretsManagerService } from "./secretsManager.service";
+
+@Module({
+ providers: [SecretsManagerService],
+ exports: [SecretsManagerService],
+})
+export class SecretsManagerModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsManager.service.ts b/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsManager.service.ts
new file mode 100644
index 0000000..89907c3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsManager.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { ConfigService } from "@nestjs/config";
+import { SecretsManagerServiceBase } from "./base/secretsManager.service.base";
+
+@Injectable()
+export class SecretsManagerService extends SecretsManagerServiceBase {
+ constructor(protected readonly configService: ConfigService) {
+ super(configService);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsNameKey.enum.ts b/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsNameKey.enum.ts
new file mode 100644
index 0000000..52c18af
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/providers/secrets/secretsNameKey.enum.ts
@@ -0,0 +1,3 @@
+export enum EnumSecretsNameKey {
+ JwtSecretKey = "JWT_SECRET_KEY"
+}
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/constants.ts b/apps/vesst-discord-bot-backend-server/src/redis/constants.ts
new file mode 100644
index 0000000..f86f612
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/constants.ts
@@ -0,0 +1,6 @@
+export const REDIS_BROKER_CLIENT = "REDIS_BROKER_CLIENT";
+export const REDIS_BROKER_ENABLE_TLS = "REDIS_BROKER_ENABLE_TLS";
+export const REDIS_BROKER_HOST = "REDIS_BROKER_HOST";
+export const REDIS_BROKER_PORT = "REDIS_BROKER_PORT";
+export const REDIS_BROKER_RETRY_DELAY = "REDIS_BROKER_RETRY_DELAY";
+export const REDIS_BROKER_RETRY_ATTEMPTS = "REDIS_BROKER_RETRY_ATTEMPTS";
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/generateRedisClientOptions.ts b/apps/vesst-discord-bot-backend-server/src/redis/generateRedisClientOptions.ts
new file mode 100644
index 0000000..f612d15
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/generateRedisClientOptions.ts
@@ -0,0 +1,55 @@
+import { ConfigService } from "@nestjs/config";
+import {
+ REDIS_BROKER_ENABLE_TLS,
+ REDIS_BROKER_HOST,
+ REDIS_BROKER_PORT,
+ REDIS_BROKER_RETRY_ATTEMPTS,
+ REDIS_BROKER_RETRY_DELAY,
+} from "./constants";
+import { RedisOptions, Transport } from "@nestjs/microservices";
+
+export const generateRedisClientOptions = (
+ configService: ConfigService
+): RedisOptions => {
+ const redisEnableTLS = configService.get(REDIS_BROKER_ENABLE_TLS) === "true";
+ const redisHost = configService.get(REDIS_BROKER_HOST);
+ const redisPort = configService.get(REDIS_BROKER_PORT);
+ const redisRetryAttempts = configService.get(REDIS_BROKER_RETRY_ATTEMPTS);
+ const redisRetryDelay = configService.get(REDIS_BROKER_RETRY_DELAY);
+
+ if (!redisHost) {
+ throw new Error("REDIS_BROKER_HOST environment variable must be defined");
+ }
+
+ if (!redisPort) {
+ throw new Error("REDIS_BROKER_PORT environment variable must be defined");
+ }
+
+ if (!redisRetryDelay) {
+ throw new Error(
+ "REDIS_BROKER_RETRY_DELAY environment variable must be defined"
+ );
+ }
+
+ if (!redisRetryAttempts) {
+ throw new Error(
+ "REDIS_BROKER_RETRY_ATTEMPTS environment variable must be defined"
+ );
+ }
+
+ const redisOptions: RedisOptions = {
+ transport: Transport.REDIS,
+ options: {
+ host: redisHost,
+ port: redisPort,
+ retryAttempts: redisRetryAttempts,
+ retryDelay: redisRetryDelay,
+ },
+ };
+
+ if (redisEnableTLS && redisOptions.options) {
+ redisOptions.options.tls = {};
+ }
+
+ return redisOptions;
+};
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/redis.controller.ts b/apps/vesst-discord-bot-backend-server/src/redis/redis.controller.ts
new file mode 100644
index 0000000..f0526d4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/redis.controller.ts
@@ -0,0 +1,6 @@
+import { EventPattern, Payload } from "@nestjs/microservices";
+import { Controller } from "@nestjs/common";
+import { RedisMessage } from "./redisMessage";
+
+@Controller("redis-controller")
+export class RedisController {}
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/redis.module.ts b/apps/vesst-discord-bot-backend-server/src/redis/redis.module.ts
new file mode 100644
index 0000000..cfd7dd8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/redis.module.ts
@@ -0,0 +1,26 @@
+import { Module } from "@nestjs/common";
+import { ClientProxyFactory } from "@nestjs/microservices";
+import { ConfigService } from "@nestjs/config";
+import { generateRedisClientOptions } from "./generateRedisClientOptions";
+import { RedisProducerService } from "./redis.producer.service";
+import { RedisController } from "./redis.controller";
+import { REDIS_BROKER_CLIENT } from "./constants";
+
+@Module({
+ imports: [],
+ providers: [
+ {
+ provide: REDIS_BROKER_CLIENT,
+ useFactory: (configService: ConfigService) => {
+ return ClientProxyFactory.create(
+ generateRedisClientOptions(configService)
+ );
+ },
+ inject: [ConfigService],
+ },
+ RedisProducerService,
+ ],
+ controllers: [RedisController],
+ exports: [RedisProducerService],
+})
+export class RedisModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/redis.producer.service.ts b/apps/vesst-discord-bot-backend-server/src/redis/redis.producer.service.ts
new file mode 100644
index 0000000..9e767fc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/redis.producer.service.ts
@@ -0,0 +1,30 @@
+import { Inject, Injectable } from "@nestjs/common";
+import { ClientRedis } from "@nestjs/microservices";
+import { REDIS_BROKER_CLIENT } from "./constants";
+import { RedisMessage } from "./redisMessage";
+import { AllMessageBrokerTopics } from "./topics";
+
+@Injectable()
+export class RedisProducerService {
+ constructor(@Inject(REDIS_BROKER_CLIENT) private redisClient: ClientRedis) {}
+
+ async onModuleInit() {
+ await this.redisClient.connect();
+ }
+
+ async emitMessage(
+ topic: AllMessageBrokerTopics,
+ message: RedisMessage
+ ): Promise {
+ return await new Promise((resolve, reject) => {
+ this.redisClient.emit(topic, message).subscribe({
+ error: (err: Error) => {
+ reject(err);
+ },
+ next: () => {
+ resolve();
+ },
+ });
+ });
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/redisMessage.ts b/apps/vesst-discord-bot-backend-server/src/redis/redisMessage.ts
new file mode 100644
index 0000000..aa97510
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/redisMessage.ts
@@ -0,0 +1 @@
+export type RedisMessage = any;
diff --git a/apps/vesst-discord-bot-backend-server/src/redis/topics.ts b/apps/vesst-discord-bot-backend-server/src/redis/topics.ts
new file mode 100644
index 0000000..7ef01a5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/redis/topics.ts
@@ -0,0 +1,2 @@
+export enum KafkaTopics {}
+export type AllMessageBrokerTopics = KafkaTopics;
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/CreateSecurityArgs.ts b/apps/vesst-discord-bot-backend-server/src/security/base/CreateSecurityArgs.ts
new file mode 100644
index 0000000..57984ae
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/CreateSecurityArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityCreateInput } from "./SecurityCreateInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class CreateSecurityArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SecurityCreateInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityCreateInput)
+ @Field(() => SecurityCreateInput, { nullable: false })
+ data!: SecurityCreateInput;
+}
+
+export { CreateSecurityArgs as CreateSecurityArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/DeleteSecurityArgs.ts b/apps/vesst-discord-bot-backend-server/src/security/base/DeleteSecurityArgs.ts
new file mode 100644
index 0000000..3431202
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/DeleteSecurityArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class DeleteSecurityArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SecurityWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityWhereUniqueInput)
+ @Field(() => SecurityWhereUniqueInput, { nullable: false })
+ where!: SecurityWhereUniqueInput;
+}
+
+export { DeleteSecurityArgs as DeleteSecurityArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/EnumSecurityStatus.ts b/apps/vesst-discord-bot-backend-server/src/security/base/EnumSecurityStatus.ts
new file mode 100644
index 0000000..c324151
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/EnumSecurityStatus.ts
@@ -0,0 +1,20 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { registerEnumType } from "@nestjs/graphql";
+
+export enum EnumSecurityStatus {
+ Option_1 = "Option1",
+}
+
+registerEnumType(EnumSecurityStatus, {
+ name: "EnumSecurityStatus",
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/Security.ts b/apps/vesst-discord-bot-backend-server/src/security/base/Security.ts
new file mode 100644
index 0000000..a20e40b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/Security.ts
@@ -0,0 +1,96 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsString,
+ MaxLength,
+ IsOptional,
+ IsDate,
+ IsEnum,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { EnumSecurityStatus } from "./EnumSecurityStatus";
+import { User } from "../../user/base/User";
+
+@ObjectType()
+class Security {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ action!: string | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ createdAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ date!: Date | null;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumSecurityStatus,
+ })
+ @IsEnum(EnumSecurityStatus)
+ @IsOptional()
+ @Field(() => EnumSecurityStatus, {
+ nullable: true,
+ })
+ status?: "Option1" | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ updatedAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ type: () => User,
+ })
+ @ValidateNested()
+ @Type(() => User)
+ @IsOptional()
+ user?: User | null;
+}
+
+export { Security as Security };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityCountArgs.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityCountArgs.ts
new file mode 100644
index 0000000..becce68
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityCountArgs.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityWhereInput } from "./SecurityWhereInput";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class SecurityCountArgs {
+ @ApiProperty({
+ required: false,
+ type: () => SecurityWhereInput,
+ })
+ @Field(() => SecurityWhereInput, { nullable: true })
+ @Type(() => SecurityWhereInput)
+ where?: SecurityWhereInput;
+}
+
+export { SecurityCountArgs as SecurityCountArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityCreateInput.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityCreateInput.ts
new file mode 100644
index 0000000..8b2b619
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityCreateInput.ts
@@ -0,0 +1,75 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsString,
+ MaxLength,
+ IsOptional,
+ IsDate,
+ IsEnum,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { EnumSecurityStatus } from "./EnumSecurityStatus";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class SecurityCreateInput {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ action?: string | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ date?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumSecurityStatus,
+ })
+ @IsEnum(EnumSecurityStatus)
+ @IsOptional()
+ @Field(() => EnumSecurityStatus, {
+ nullable: true,
+ })
+ status?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput | null;
+}
+
+export { SecurityCreateInput as SecurityCreateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityFindManyArgs.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityFindManyArgs.ts
new file mode 100644
index 0000000..b03d9df
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityFindManyArgs.ts
@@ -0,0 +1,62 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityWhereInput } from "./SecurityWhereInput";
+import { IsOptional, ValidateNested, IsInt } from "class-validator";
+import { Type } from "class-transformer";
+import { SecurityOrderByInput } from "./SecurityOrderByInput";
+
+@ArgsType()
+class SecurityFindManyArgs {
+ @ApiProperty({
+ required: false,
+ type: () => SecurityWhereInput,
+ })
+ @IsOptional()
+ @ValidateNested()
+ @Field(() => SecurityWhereInput, { nullable: true })
+ @Type(() => SecurityWhereInput)
+ where?: SecurityWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: [SecurityOrderByInput],
+ })
+ @IsOptional()
+ @ValidateNested({ each: true })
+ @Field(() => [SecurityOrderByInput], { nullable: true })
+ @Type(() => SecurityOrderByInput)
+ orderBy?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ skip?: number;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ take?: number;
+}
+
+export { SecurityFindManyArgs as SecurityFindManyArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityFindUniqueArgs.ts
new file mode 100644
index 0000000..438069e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityFindUniqueArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class SecurityFindUniqueArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SecurityWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityWhereUniqueInput)
+ @Field(() => SecurityWhereUniqueInput, { nullable: false })
+ where!: SecurityWhereUniqueInput;
+}
+
+export { SecurityFindUniqueArgs as SecurityFindUniqueArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityListRelationFilter.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityListRelationFilter.ts
new file mode 100644
index 0000000..d58f15d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityListRelationFilter.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityWhereInput } from "./SecurityWhereInput";
+import { ValidateNested, IsOptional } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class SecurityListRelationFilter {
+ @ApiProperty({
+ required: false,
+ type: () => SecurityWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityWhereInput)
+ @IsOptional()
+ @Field(() => SecurityWhereInput, {
+ nullable: true,
+ })
+ every?: SecurityWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => SecurityWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityWhereInput)
+ @IsOptional()
+ @Field(() => SecurityWhereInput, {
+ nullable: true,
+ })
+ some?: SecurityWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => SecurityWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityWhereInput)
+ @IsOptional()
+ @Field(() => SecurityWhereInput, {
+ nullable: true,
+ })
+ none?: SecurityWhereInput;
+}
+export { SecurityListRelationFilter as SecurityListRelationFilter };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityOrderByInput.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityOrderByInput.ts
new file mode 100644
index 0000000..ef988d5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityOrderByInput.ts
@@ -0,0 +1,100 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsOptional, IsEnum } from "class-validator";
+import { SortOrder } from "../../util/SortOrder";
+
+@InputType({
+ isAbstract: true,
+ description: undefined,
+})
+class SecurityOrderByInput {
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ action?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ createdAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ date?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ id?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ status?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ updatedAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ userId?: SortOrder;
+}
+
+export { SecurityOrderByInput as SecurityOrderByInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityUpdateInput.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityUpdateInput.ts
new file mode 100644
index 0000000..48b0cc4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityUpdateInput.ts
@@ -0,0 +1,75 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsString,
+ MaxLength,
+ IsOptional,
+ IsDate,
+ IsEnum,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { EnumSecurityStatus } from "./EnumSecurityStatus";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class SecurityUpdateInput {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ action?: string | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ date?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumSecurityStatus,
+ })
+ @IsEnum(EnumSecurityStatus)
+ @IsOptional()
+ @Field(() => EnumSecurityStatus, {
+ nullable: true,
+ })
+ status?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput | null;
+}
+
+export { SecurityUpdateInput as SecurityUpdateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityWhereInput.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityWhereInput.ts
new file mode 100644
index 0000000..999b92a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityWhereInput.ts
@@ -0,0 +1,81 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { Type } from "class-transformer";
+import { IsOptional, IsEnum, ValidateNested } from "class-validator";
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { EnumSecurityStatus } from "./EnumSecurityStatus";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class SecurityWhereInput {
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ action?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: DateTimeNullableFilter,
+ })
+ @Type(() => DateTimeNullableFilter)
+ @IsOptional()
+ @Field(() => DateTimeNullableFilter, {
+ nullable: true,
+ })
+ date?: DateTimeNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ id?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumSecurityStatus,
+ })
+ @IsEnum(EnumSecurityStatus)
+ @IsOptional()
+ @Field(() => EnumSecurityStatus, {
+ nullable: true,
+ })
+ status?: "Option1";
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput;
+}
+
+export { SecurityWhereInput as SecurityWhereInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/SecurityWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityWhereUniqueInput.ts
new file mode 100644
index 0000000..80a45c7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/SecurityWhereUniqueInput.ts
@@ -0,0 +1,27 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString } from "class-validator";
+
+@InputType()
+class SecurityWhereUniqueInput {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+}
+
+export { SecurityWhereUniqueInput as SecurityWhereUniqueInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/UpdateSecurityArgs.ts b/apps/vesst-discord-bot-backend-server/src/security/base/UpdateSecurityArgs.ts
new file mode 100644
index 0000000..7e2e66f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/UpdateSecurityArgs.ts
@@ -0,0 +1,40 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { SecurityUpdateInput } from "./SecurityUpdateInput";
+
+@ArgsType()
+class UpdateSecurityArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SecurityWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityWhereUniqueInput)
+ @Field(() => SecurityWhereUniqueInput, { nullable: false })
+ where!: SecurityWhereUniqueInput;
+
+ @ApiProperty({
+ required: true,
+ type: () => SecurityUpdateInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityUpdateInput)
+ @Field(() => SecurityUpdateInput, { nullable: false })
+ data!: SecurityUpdateInput;
+}
+
+export { UpdateSecurityArgs as UpdateSecurityArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/security.controller.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/security/base/security.controller.base.spec.ts
new file mode 100644
index 0000000..493deae
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/security.controller.base.spec.ts
@@ -0,0 +1,202 @@
+import { Test } from "@nestjs/testing";
+import {
+ INestApplication,
+ HttpStatus,
+ ExecutionContext,
+ CallHandler,
+} from "@nestjs/common";
+import request from "supertest";
+import { ACGuard } from "nest-access-control";
+import { DefaultAuthGuard } from "../../auth/defaultAuth.guard";
+import { ACLModule } from "../../auth/acl.module";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { map } from "rxjs";
+import { SecurityController } from "../security.controller";
+import { SecurityService } from "../security.service";
+
+const nonExistingId = "nonExistingId";
+const existingId = "existingId";
+const CREATE_INPUT = {
+ action: "exampleAction",
+ createdAt: new Date(),
+ date: new Date(),
+ id: "exampleId",
+ updatedAt: new Date(),
+};
+const CREATE_RESULT = {
+ action: "exampleAction",
+ createdAt: new Date(),
+ date: new Date(),
+ id: "exampleId",
+ updatedAt: new Date(),
+};
+const FIND_MANY_RESULT = [
+ {
+ action: "exampleAction",
+ createdAt: new Date(),
+ date: new Date(),
+ id: "exampleId",
+ updatedAt: new Date(),
+ },
+];
+const FIND_ONE_RESULT = {
+ action: "exampleAction",
+ createdAt: new Date(),
+ date: new Date(),
+ id: "exampleId",
+ updatedAt: new Date(),
+};
+
+const service = {
+ createSecurity() {
+ return CREATE_RESULT;
+ },
+ securities: () => FIND_MANY_RESULT,
+ security: ({ where }: { where: { id: string } }) => {
+ switch (where.id) {
+ case existingId:
+ return FIND_ONE_RESULT;
+ case nonExistingId:
+ return null;
+ }
+ },
+};
+
+const basicAuthGuard = {
+ canActivate: (context: ExecutionContext) => {
+ const argumentHost = context.switchToHttp();
+ const request = argumentHost.getRequest();
+ request.user = {
+ roles: ["user"],
+ };
+ return true;
+ },
+};
+
+const acGuard = {
+ canActivate: () => {
+ return true;
+ },
+};
+
+const aclFilterResponseInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle().pipe(
+ map((data) => {
+ return data;
+ })
+ );
+ },
+};
+const aclValidateRequestInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle();
+ },
+};
+
+describe("Security", () => {
+ let app: INestApplication;
+
+ beforeAll(async () => {
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ {
+ provide: SecurityService,
+ useValue: service,
+ },
+ ],
+ controllers: [SecurityController],
+ imports: [ACLModule],
+ })
+ .overrideGuard(DefaultAuthGuard)
+ .useValue(basicAuthGuard)
+ .overrideGuard(ACGuard)
+ .useValue(acGuard)
+ .overrideInterceptor(AclFilterResponseInterceptor)
+ .useValue(aclFilterResponseInterceptor)
+ .overrideInterceptor(AclValidateRequestInterceptor)
+ .useValue(aclValidateRequestInterceptor)
+ .compile();
+
+ app = moduleRef.createNestApplication();
+ await app.init();
+ });
+
+ test("POST /securities", async () => {
+ await request(app.getHttpServer())
+ .post("/securities")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ date: CREATE_RESULT.date.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("GET /securities", async () => {
+ await request(app.getHttpServer())
+ .get("/securities")
+ .expect(HttpStatus.OK)
+ .expect([
+ {
+ ...FIND_MANY_RESULT[0],
+ createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(),
+ date: FIND_MANY_RESULT[0].date.toISOString(),
+ updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(),
+ },
+ ]);
+ });
+
+ test("GET /securities/:id non existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/securities"}/${nonExistingId}`)
+ .expect(HttpStatus.NOT_FOUND)
+ .expect({
+ statusCode: HttpStatus.NOT_FOUND,
+ message: `No resource was found for {"${"id"}":"${nonExistingId}"}`,
+ error: "Not Found",
+ });
+ });
+
+ test("GET /securities/:id existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/securities"}/${existingId}`)
+ .expect(HttpStatus.OK)
+ .expect({
+ ...FIND_ONE_RESULT,
+ createdAt: FIND_ONE_RESULT.createdAt.toISOString(),
+ date: FIND_ONE_RESULT.date.toISOString(),
+ updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("POST /securities existing resource", async () => {
+ const agent = request(app.getHttpServer());
+ await agent
+ .post("/securities")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ date: CREATE_RESULT.date.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ })
+ .then(function () {
+ agent
+ .post("/securities")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CONFLICT)
+ .expect({
+ statusCode: HttpStatus.CONFLICT,
+ });
+ });
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/security.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/security/base/security.controller.base.ts
new file mode 100644
index 0000000..ba23c01
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/security.controller.base.ts
@@ -0,0 +1,245 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import * as nestAccessControl from "nest-access-control";
+import * as defaultAuthGuard from "../../auth/defaultAuth.guard";
+import { SecurityService } from "../security.service";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { SecurityCreateInput } from "./SecurityCreateInput";
+import { Security } from "./Security";
+import { SecurityFindManyArgs } from "./SecurityFindManyArgs";
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+import { SecurityUpdateInput } from "./SecurityUpdateInput";
+
+@swagger.ApiBearerAuth()
+@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard)
+export class SecurityControllerBase {
+ constructor(
+ protected readonly service: SecurityService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Security })
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "create",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async createSecurity(
+ @common.Body() data: SecurityCreateInput
+ ): Promise {
+ return await this.service.createSecurity({
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Security] })
+ @ApiNestedQuery(SecurityFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "read",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async securities(@common.Req() request: Request): Promise {
+ const args = plainToClass(SecurityFindManyArgs, request.query);
+ return this.service.securities({
+ ...args,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Security })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "read",
+ possession: "own",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async security(
+ @common.Param() params: SecurityWhereUniqueInput
+ ): Promise {
+ const result = await this.service.security({
+ where: params,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Security })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "update",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async updateSecurity(
+ @common.Param() params: SecurityWhereUniqueInput,
+ @common.Body() data: SecurityUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateSecurity({
+ where: params,
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Security })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "delete",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async deleteSecurity(
+ @common.Param() params: SecurityWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteSecurity({
+ where: params,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/security.grpc.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/security/base/security.grpc.controller.base.ts
new file mode 100644
index 0000000..851fb18
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/security.grpc.controller.base.ts
@@ -0,0 +1,199 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import { GrpcMethod } from "@nestjs/microservices";
+import { SecurityService } from "../security.service";
+import { SecurityCreateInput } from "./SecurityCreateInput";
+import { SecurityWhereInput } from "./SecurityWhereInput";
+import { SecurityWhereUniqueInput } from "./SecurityWhereUniqueInput";
+import { SecurityFindManyArgs } from "./SecurityFindManyArgs";
+import { SecurityUpdateInput } from "./SecurityUpdateInput";
+import { Security } from "./Security";
+
+export class SecurityGrpcControllerBase {
+ constructor(protected readonly service: SecurityService) {}
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Security })
+ @GrpcMethod("SecurityService", "createSecurity")
+ async createSecurity(
+ @common.Body() data: SecurityCreateInput
+ ): Promise {
+ return await this.service.createSecurity({
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Security] })
+ @ApiNestedQuery(SecurityFindManyArgs)
+ @GrpcMethod("SecurityService", "securities")
+ async securities(@common.Req() request: Request): Promise {
+ const args = plainToClass(SecurityFindManyArgs, request.query);
+ return this.service.securities({
+ ...args,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Security })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("SecurityService", "security")
+ async security(
+ @common.Param() params: SecurityWhereUniqueInput
+ ): Promise {
+ const result = await this.service.security({
+ where: params,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Security })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("SecurityService", "updateSecurity")
+ async updateSecurity(
+ @common.Param() params: SecurityWhereUniqueInput,
+ @common.Body() data: SecurityUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateSecurity({
+ where: params,
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Security })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("SecurityService", "deleteSecurity")
+ async deleteSecurity(
+ @common.Param() params: SecurityWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteSecurity({
+ where: params,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/security.module.base.ts b/apps/vesst-discord-bot-backend-server/src/security/base/security.module.base.ts
new file mode 100644
index 0000000..ce3f1a1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/security.module.base.ts
@@ -0,0 +1,18 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { Module } from "@nestjs/common";
+import { ACLModule } from "../../auth/acl.module";
+@Module({
+ imports: [ACLModule],
+ exports: [ACLModule],
+})
+export class SecurityModuleBase {}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/security.resolver.base.ts b/apps/vesst-discord-bot-backend-server/src/security/base/security.resolver.base.ts
new file mode 100644
index 0000000..1138941
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/security.resolver.base.ts
@@ -0,0 +1,180 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as graphql from "@nestjs/graphql";
+import { GraphQLError } from "graphql";
+import { isRecordNotFoundError } from "../../prisma.util";
+import { MetaQueryPayload } from "../../util/MetaQueryPayload";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { Security } from "./Security";
+import { SecurityCountArgs } from "./SecurityCountArgs";
+import { SecurityFindManyArgs } from "./SecurityFindManyArgs";
+import { SecurityFindUniqueArgs } from "./SecurityFindUniqueArgs";
+import { CreateSecurityArgs } from "./CreateSecurityArgs";
+import { UpdateSecurityArgs } from "./UpdateSecurityArgs";
+import { DeleteSecurityArgs } from "./DeleteSecurityArgs";
+import { User } from "../../user/base/User";
+import { SecurityService } from "../security.service";
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Security)
+export class SecurityResolverBase {
+ constructor(
+ protected readonly service: SecurityService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+
+ @graphql.Query(() => MetaQueryPayload)
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "read",
+ possession: "any",
+ })
+ async _securitiesMeta(
+ @graphql.Args() args: SecurityCountArgs
+ ): Promise {
+ const result = await this.service.count(args);
+ return {
+ count: result,
+ };
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => [Security])
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "read",
+ possession: "any",
+ })
+ async securities(
+ @graphql.Args() args: SecurityFindManyArgs
+ ): Promise {
+ return this.service.securities(args);
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => Security, { nullable: true })
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "read",
+ possession: "own",
+ })
+ async security(
+ @graphql.Args() args: SecurityFindUniqueArgs
+ ): Promise {
+ const result = await this.service.security(args);
+ if (result === null) {
+ return null;
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Security)
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "create",
+ possession: "any",
+ })
+ async createSecurity(
+ @graphql.Args() args: CreateSecurityArgs
+ ): Promise {
+ return await this.service.createSecurity({
+ ...args,
+ data: {
+ ...args.data,
+
+ user: args.data.user
+ ? {
+ connect: args.data.user,
+ }
+ : undefined,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Security)
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "update",
+ possession: "any",
+ })
+ async updateSecurity(
+ @graphql.Args() args: UpdateSecurityArgs
+ ): Promise {
+ try {
+ return await this.service.updateSecurity({
+ ...args,
+ data: {
+ ...args.data,
+
+ user: args.data.user
+ ? {
+ connect: args.data.user,
+ }
+ : undefined,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @graphql.Mutation(() => Security)
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "delete",
+ possession: "any",
+ })
+ async deleteSecurity(
+ @graphql.Args() args: DeleteSecurityArgs
+ ): Promise {
+ try {
+ return await this.service.deleteSecurity(args);
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.ResolveField(() => User, {
+ nullable: true,
+ name: "user",
+ })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "read",
+ possession: "any",
+ })
+ async getUser(@graphql.Parent() parent: Security): Promise {
+ const result = await this.service.getUser(parent.id);
+
+ if (!result) {
+ return null;
+ }
+ return result;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/base/security.service.base.ts b/apps/vesst-discord-bot-backend-server/src/security/base/security.service.base.ts
new file mode 100644
index 0000000..92200b9
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/base/security.service.base.ts
@@ -0,0 +1,59 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { PrismaService } from "../../prisma/prisma.service";
+import {
+ Prisma,
+ Security as PrismaSecurity,
+ User as PrismaUser,
+} from "@prisma/client";
+
+export class SecurityServiceBase {
+ constructor(protected readonly prisma: PrismaService) {}
+
+ async count(args: Omit): Promise {
+ return this.prisma.security.count(args);
+ }
+
+ async securities(
+ args: Prisma.SecurityFindManyArgs
+ ): Promise {
+ return this.prisma.security.findMany(args);
+ }
+ async security(
+ args: Prisma.SecurityFindUniqueArgs
+ ): Promise {
+ return this.prisma.security.findUnique(args);
+ }
+ async createSecurity(
+ args: Prisma.SecurityCreateArgs
+ ): Promise {
+ return this.prisma.security.create(args);
+ }
+ async updateSecurity(
+ args: Prisma.SecurityUpdateArgs
+ ): Promise {
+ return this.prisma.security.update(args);
+ }
+ async deleteSecurity(
+ args: Prisma.SecurityDeleteArgs
+ ): Promise {
+ return this.prisma.security.delete(args);
+ }
+
+ async getUser(parentId: string): Promise {
+ return this.prisma.security
+ .findUnique({
+ where: { id: parentId },
+ })
+ .user();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/security.controller.ts b/apps/vesst-discord-bot-backend-server/src/security/security.controller.ts
new file mode 100644
index 0000000..3ac9b00
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/security.controller.ts
@@ -0,0 +1,17 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import * as nestAccessControl from "nest-access-control";
+import { SecurityService } from "./security.service";
+import { SecurityControllerBase } from "./base/security.controller.base";
+
+@swagger.ApiTags("securities")
+@common.Controller("securities")
+export class SecurityController extends SecurityControllerBase {
+ constructor(
+ protected readonly service: SecurityService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/security.grpc.controller.ts b/apps/vesst-discord-bot-backend-server/src/security/security.grpc.controller.ts
new file mode 100644
index 0000000..48be885
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/security.grpc.controller.ts
@@ -0,0 +1,12 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { SecurityService } from "./security.service";
+import { SecurityGrpcControllerBase } from "./base/security.grpc.controller.base";
+
+@swagger.ApiTags("securities")
+@common.Controller("securities")
+export class SecurityGrpcController extends SecurityGrpcControllerBase {
+ constructor(protected readonly service: SecurityService) {
+ super(service);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/security.module.ts b/apps/vesst-discord-bot-backend-server/src/security/security.module.ts
new file mode 100644
index 0000000..b686ee6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/security.module.ts
@@ -0,0 +1,15 @@
+import { Module, forwardRef } from "@nestjs/common";
+import { AuthModule } from "../auth/auth.module";
+import { SecurityModuleBase } from "./base/security.module.base";
+import { SecurityService } from "./security.service";
+import { SecurityController } from "./security.controller";
+import { SecurityGrpcController } from "./security.grpc.controller";
+import { SecurityResolver } from "./security.resolver";
+
+@Module({
+ imports: [SecurityModuleBase, forwardRef(() => AuthModule)],
+ controllers: [SecurityController, SecurityGrpcController],
+ providers: [SecurityService, SecurityResolver],
+ exports: [SecurityService],
+})
+export class SecurityModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/security.proto b/apps/vesst-discord-bot-backend-server/src/security/security.proto
new file mode 100644
index 0000000..576ef97
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/security.proto
@@ -0,0 +1,45 @@
+syntax = "proto3";
+
+ package security;
+service SecurityService {
+ rpc createSecurity (SecurityCreateInput) returns (Security) {}
+rpc securities (findManyParams) returns (stream Security) {}
+rpc security (SecurityWhereUniqueInput) returns (Security) {}
+rpc updateSecurity (SecurityUpdateInput) returns (Security) {}
+rpc deleteSecurity (SecurityWhereUniqueInput) returns (Security) {}
+ }
+message SecurityCreateInput {
+string action = 1;
+string createdAt = 2;
+string date = 3;
+string id = 4;
+repeated string status = 5;
+string updatedAt = 6;
+};
+message Security {
+string action = 1;
+string createdAt = 2;
+string date = 3;
+string id = 4;
+repeated string status = 5;
+string updatedAt = 6;
+};
+message SecurityWhereUniqueInput {
+string action = 1;
+string createdAt = 2;
+string date = 3;
+string id = 4;
+repeated string status = 5;
+string updatedAt = 6;
+};
+message SecurityUpdateInput {
+string action = 1;
+string createdAt = 2;
+string date = 3;
+string id = 4;
+repeated string status = 5;
+string updatedAt = 6;
+};
+message findManyParams {
+
+};
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/security/security.resolver.ts b/apps/vesst-discord-bot-backend-server/src/security/security.resolver.ts
new file mode 100644
index 0000000..f7f1368
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/security.resolver.ts
@@ -0,0 +1,20 @@
+import * as graphql from "@nestjs/graphql";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { SecurityResolverBase } from "./base/security.resolver.base";
+import { Security } from "./base/Security";
+import { SecurityService } from "./security.service";
+
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Security)
+export class SecurityResolver extends SecurityResolverBase {
+ constructor(
+ protected readonly service: SecurityService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/security/security.service.ts b/apps/vesst-discord-bot-backend-server/src/security/security.service.ts
new file mode 100644
index 0000000..6077d5b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/security/security.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../prisma/prisma.service";
+import { SecurityServiceBase } from "./base/security.service.base";
+
+@Injectable()
+export class SecurityService extends SecurityServiceBase {
+ constructor(protected readonly prisma: PrismaService) {
+ super(prisma);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/serveStaticOptions.service.ts b/apps/vesst-discord-bot-backend-server/src/serveStaticOptions.service.ts
new file mode 100644
index 0000000..390248b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/serveStaticOptions.service.ts
@@ -0,0 +1,39 @@
+import * as path from "path";
+import { Injectable, Logger } from "@nestjs/common";
+import { ConfigService } from "@nestjs/config";
+import {
+ ServeStaticModuleOptions,
+ ServeStaticModuleOptionsFactory,
+} from "@nestjs/serve-static";
+
+const SERVE_STATIC_ROOT_PATH_VAR = "SERVE_STATIC_ROOT_PATH";
+const DEFAULT_STATIC_MODULE_OPTIONS_LIST: ServeStaticModuleOptions[] = [
+ {
+ serveRoot: "/swagger",
+ rootPath: path.join(__dirname, "swagger"),
+ },
+];
+
+@Injectable()
+export class ServeStaticOptionsService
+ implements ServeStaticModuleOptionsFactory
+{
+ private readonly logger = new Logger(ServeStaticOptionsService.name);
+
+ constructor(private readonly configService: ConfigService) {}
+
+ createLoggerOptions(): ServeStaticModuleOptions[] {
+ const serveStaticRootPath = this.configService.get(
+ SERVE_STATIC_ROOT_PATH_VAR
+ );
+ if (serveStaticRootPath) {
+ const resolvedPath = path.resolve(serveStaticRootPath);
+ this.logger.log(`Serving static files from ${resolvedPath}`);
+ return [
+ ...DEFAULT_STATIC_MODULE_OPTIONS_LIST,
+ { rootPath: resolvedPath, exclude: ["/api*", "/graphql"] },
+ ];
+ }
+ return DEFAULT_STATIC_MODULE_OPTIONS_LIST;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/CreateSlotArgs.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/CreateSlotArgs.ts
new file mode 100644
index 0000000..eed3742
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/CreateSlotArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotCreateInput } from "./SlotCreateInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class CreateSlotArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SlotCreateInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotCreateInput)
+ @Field(() => SlotCreateInput, { nullable: false })
+ data!: SlotCreateInput;
+}
+
+export { CreateSlotArgs as CreateSlotArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/DeleteSlotArgs.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/DeleteSlotArgs.ts
new file mode 100644
index 0000000..3d5f129
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/DeleteSlotArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class DeleteSlotArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SlotWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotWhereUniqueInput)
+ @Field(() => SlotWhereUniqueInput, { nullable: false })
+ where!: SlotWhereUniqueInput;
+}
+
+export { DeleteSlotArgs as DeleteSlotArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/Slot.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/Slot.ts
new file mode 100644
index 0000000..be930ee
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/Slot.ts
@@ -0,0 +1,115 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+
+import {
+ IsNumber,
+ Min,
+ Max,
+ IsOptional,
+ IsDate,
+ IsString,
+ MaxLength,
+ ValidateNested,
+} from "class-validator";
+
+import { Type } from "class-transformer";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { JsonValue } from "type-fest";
+import { User } from "../../user/base/User";
+
+@ObjectType()
+class Slot {
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsNumber()
+ @Min(-999999999)
+ @Max(999999999)
+ @IsOptional()
+ @Field(() => Number, {
+ nullable: true,
+ })
+ bid!: number | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ createdAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ description!: string | null;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ metrics!: JsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ name!: string | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ updatedAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ type: () => User,
+ })
+ @ValidateNested()
+ @Type(() => User)
+ @IsOptional()
+ user?: User | null;
+}
+
+export { Slot as Slot };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotCountArgs.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotCountArgs.ts
new file mode 100644
index 0000000..b31587b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotCountArgs.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotWhereInput } from "./SlotWhereInput";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class SlotCountArgs {
+ @ApiProperty({
+ required: false,
+ type: () => SlotWhereInput,
+ })
+ @Field(() => SlotWhereInput, { nullable: true })
+ @Type(() => SlotWhereInput)
+ where?: SlotWhereInput;
+}
+
+export { SlotCountArgs as SlotCountArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotCreateInput.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotCreateInput.ts
new file mode 100644
index 0000000..553c50c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotCreateInput.ts
@@ -0,0 +1,91 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsNumber,
+ Min,
+ Max,
+ IsOptional,
+ IsString,
+ MaxLength,
+ ValidateNested,
+} from "class-validator";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { InputJsonValue } from "../../types";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+import { Type } from "class-transformer";
+
+@InputType()
+class SlotCreateInput {
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsNumber()
+ @Min(-999999999)
+ @Max(999999999)
+ @IsOptional()
+ @Field(() => Number, {
+ nullable: true,
+ })
+ bid?: number | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ description?: string | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ metrics?: InputJsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ name?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput | null;
+}
+
+export { SlotCreateInput as SlotCreateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotFindManyArgs.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotFindManyArgs.ts
new file mode 100644
index 0000000..9b96667
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotFindManyArgs.ts
@@ -0,0 +1,62 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotWhereInput } from "./SlotWhereInput";
+import { IsOptional, ValidateNested, IsInt } from "class-validator";
+import { Type } from "class-transformer";
+import { SlotOrderByInput } from "./SlotOrderByInput";
+
+@ArgsType()
+class SlotFindManyArgs {
+ @ApiProperty({
+ required: false,
+ type: () => SlotWhereInput,
+ })
+ @IsOptional()
+ @ValidateNested()
+ @Field(() => SlotWhereInput, { nullable: true })
+ @Type(() => SlotWhereInput)
+ where?: SlotWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: [SlotOrderByInput],
+ })
+ @IsOptional()
+ @ValidateNested({ each: true })
+ @Field(() => [SlotOrderByInput], { nullable: true })
+ @Type(() => SlotOrderByInput)
+ orderBy?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ skip?: number;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ take?: number;
+}
+
+export { SlotFindManyArgs as SlotFindManyArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotFindUniqueArgs.ts
new file mode 100644
index 0000000..d519e72
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotFindUniqueArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class SlotFindUniqueArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SlotWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotWhereUniqueInput)
+ @Field(() => SlotWhereUniqueInput, { nullable: false })
+ where!: SlotWhereUniqueInput;
+}
+
+export { SlotFindUniqueArgs as SlotFindUniqueArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotListRelationFilter.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotListRelationFilter.ts
new file mode 100644
index 0000000..51a1299
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotListRelationFilter.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotWhereInput } from "./SlotWhereInput";
+import { ValidateNested, IsOptional } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class SlotListRelationFilter {
+ @ApiProperty({
+ required: false,
+ type: () => SlotWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotWhereInput)
+ @IsOptional()
+ @Field(() => SlotWhereInput, {
+ nullable: true,
+ })
+ every?: SlotWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => SlotWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotWhereInput)
+ @IsOptional()
+ @Field(() => SlotWhereInput, {
+ nullable: true,
+ })
+ some?: SlotWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => SlotWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotWhereInput)
+ @IsOptional()
+ @Field(() => SlotWhereInput, {
+ nullable: true,
+ })
+ none?: SlotWhereInput;
+}
+export { SlotListRelationFilter as SlotListRelationFilter };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotOrderByInput.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotOrderByInput.ts
new file mode 100644
index 0000000..0273978
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotOrderByInput.ts
@@ -0,0 +1,111 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsOptional, IsEnum } from "class-validator";
+import { SortOrder } from "../../util/SortOrder";
+
+@InputType({
+ isAbstract: true,
+ description: undefined,
+})
+class SlotOrderByInput {
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ bid?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ createdAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ description?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ id?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ metrics?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ name?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ updatedAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ userId?: SortOrder;
+}
+
+export { SlotOrderByInput as SlotOrderByInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotUpdateInput.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotUpdateInput.ts
new file mode 100644
index 0000000..e74b9fd
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotUpdateInput.ts
@@ -0,0 +1,91 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsNumber,
+ Min,
+ Max,
+ IsOptional,
+ IsString,
+ MaxLength,
+ ValidateNested,
+} from "class-validator";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { InputJsonValue } from "../../types";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+import { Type } from "class-transformer";
+
+@InputType()
+class SlotUpdateInput {
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsNumber()
+ @Min(-999999999)
+ @Max(999999999)
+ @IsOptional()
+ @Field(() => Number, {
+ nullable: true,
+ })
+ bid?: number | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ description?: string | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ metrics?: InputJsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ name?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput | null;
+}
+
+export { SlotUpdateInput as SlotUpdateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotWhereInput.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotWhereInput.ts
new file mode 100644
index 0000000..edd033b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotWhereInput.ts
@@ -0,0 +1,92 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { FloatNullableFilter } from "../../util/FloatNullableFilter";
+import { Type } from "class-transformer";
+import { IsOptional, ValidateNested } from "class-validator";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { StringFilter } from "../../util/StringFilter";
+import { JsonFilter } from "../../util/JsonFilter";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class SlotWhereInput {
+ @ApiProperty({
+ required: false,
+ type: FloatNullableFilter,
+ })
+ @Type(() => FloatNullableFilter)
+ @IsOptional()
+ @Field(() => FloatNullableFilter, {
+ nullable: true,
+ })
+ bid?: FloatNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ description?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ id?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ type: JsonFilter,
+ })
+ @Type(() => JsonFilter)
+ @IsOptional()
+ @Field(() => JsonFilter, {
+ nullable: true,
+ })
+ metrics?: JsonFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ name?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput;
+}
+
+export { SlotWhereInput as SlotWhereInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/SlotWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotWhereUniqueInput.ts
new file mode 100644
index 0000000..71072d5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/SlotWhereUniqueInput.ts
@@ -0,0 +1,27 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString } from "class-validator";
+
+@InputType()
+class SlotWhereUniqueInput {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+}
+
+export { SlotWhereUniqueInput as SlotWhereUniqueInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/UpdateSlotArgs.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/UpdateSlotArgs.ts
new file mode 100644
index 0000000..87ac015
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/UpdateSlotArgs.ts
@@ -0,0 +1,40 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { SlotUpdateInput } from "./SlotUpdateInput";
+
+@ArgsType()
+class UpdateSlotArgs {
+ @ApiProperty({
+ required: true,
+ type: () => SlotWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotWhereUniqueInput)
+ @Field(() => SlotWhereUniqueInput, { nullable: false })
+ where!: SlotWhereUniqueInput;
+
+ @ApiProperty({
+ required: true,
+ type: () => SlotUpdateInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotUpdateInput)
+ @Field(() => SlotUpdateInput, { nullable: false })
+ data!: SlotUpdateInput;
+}
+
+export { UpdateSlotArgs as UpdateSlotArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/slot.controller.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.controller.base.spec.ts
new file mode 100644
index 0000000..51ad1f4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.controller.base.spec.ts
@@ -0,0 +1,202 @@
+import { Test } from "@nestjs/testing";
+import {
+ INestApplication,
+ HttpStatus,
+ ExecutionContext,
+ CallHandler,
+} from "@nestjs/common";
+import request from "supertest";
+import { ACGuard } from "nest-access-control";
+import { DefaultAuthGuard } from "../../auth/defaultAuth.guard";
+import { ACLModule } from "../../auth/acl.module";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { map } from "rxjs";
+import { SlotController } from "../slot.controller";
+import { SlotService } from "../slot.service";
+
+const nonExistingId = "nonExistingId";
+const existingId = "existingId";
+const CREATE_INPUT = {
+ bid: 42.42,
+ createdAt: new Date(),
+ description: "exampleDescription",
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+};
+const CREATE_RESULT = {
+ bid: 42.42,
+ createdAt: new Date(),
+ description: "exampleDescription",
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+};
+const FIND_MANY_RESULT = [
+ {
+ bid: 42.42,
+ createdAt: new Date(),
+ description: "exampleDescription",
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+ },
+];
+const FIND_ONE_RESULT = {
+ bid: 42.42,
+ createdAt: new Date(),
+ description: "exampleDescription",
+ id: "exampleId",
+ name: "exampleName",
+ updatedAt: new Date(),
+};
+
+const service = {
+ createSlot() {
+ return CREATE_RESULT;
+ },
+ slots: () => FIND_MANY_RESULT,
+ slot: ({ where }: { where: { id: string } }) => {
+ switch (where.id) {
+ case existingId:
+ return FIND_ONE_RESULT;
+ case nonExistingId:
+ return null;
+ }
+ },
+};
+
+const basicAuthGuard = {
+ canActivate: (context: ExecutionContext) => {
+ const argumentHost = context.switchToHttp();
+ const request = argumentHost.getRequest();
+ request.user = {
+ roles: ["user"],
+ };
+ return true;
+ },
+};
+
+const acGuard = {
+ canActivate: () => {
+ return true;
+ },
+};
+
+const aclFilterResponseInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle().pipe(
+ map((data) => {
+ return data;
+ })
+ );
+ },
+};
+const aclValidateRequestInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle();
+ },
+};
+
+describe("Slot", () => {
+ let app: INestApplication;
+
+ beforeAll(async () => {
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ {
+ provide: SlotService,
+ useValue: service,
+ },
+ ],
+ controllers: [SlotController],
+ imports: [ACLModule],
+ })
+ .overrideGuard(DefaultAuthGuard)
+ .useValue(basicAuthGuard)
+ .overrideGuard(ACGuard)
+ .useValue(acGuard)
+ .overrideInterceptor(AclFilterResponseInterceptor)
+ .useValue(aclFilterResponseInterceptor)
+ .overrideInterceptor(AclValidateRequestInterceptor)
+ .useValue(aclValidateRequestInterceptor)
+ .compile();
+
+ app = moduleRef.createNestApplication();
+ await app.init();
+ });
+
+ test("POST /slots", async () => {
+ await request(app.getHttpServer())
+ .post("/slots")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("GET /slots", async () => {
+ await request(app.getHttpServer())
+ .get("/slots")
+ .expect(HttpStatus.OK)
+ .expect([
+ {
+ ...FIND_MANY_RESULT[0],
+ createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(),
+ updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(),
+ },
+ ]);
+ });
+
+ test("GET /slots/:id non existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/slots"}/${nonExistingId}`)
+ .expect(HttpStatus.NOT_FOUND)
+ .expect({
+ statusCode: HttpStatus.NOT_FOUND,
+ message: `No resource was found for {"${"id"}":"${nonExistingId}"}`,
+ error: "Not Found",
+ });
+ });
+
+ test("GET /slots/:id existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/slots"}/${existingId}`)
+ .expect(HttpStatus.OK)
+ .expect({
+ ...FIND_ONE_RESULT,
+ createdAt: FIND_ONE_RESULT.createdAt.toISOString(),
+ updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("POST /slots existing resource", async () => {
+ const agent = request(app.getHttpServer());
+ await agent
+ .post("/slots")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ })
+ .then(function () {
+ agent
+ .post("/slots")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CONFLICT)
+ .expect({
+ statusCode: HttpStatus.CONFLICT,
+ });
+ });
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/slot.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.controller.base.ts
new file mode 100644
index 0000000..5cbbda1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.controller.base.ts
@@ -0,0 +1,248 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import * as nestAccessControl from "nest-access-control";
+import * as defaultAuthGuard from "../../auth/defaultAuth.guard";
+import { SlotService } from "../slot.service";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { SlotCreateInput } from "./SlotCreateInput";
+import { Slot } from "./Slot";
+import { SlotFindManyArgs } from "./SlotFindManyArgs";
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+import { SlotUpdateInput } from "./SlotUpdateInput";
+
+@swagger.ApiBearerAuth()
+@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard)
+export class SlotControllerBase {
+ constructor(
+ protected readonly service: SlotService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Slot })
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "create",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async createSlot(@common.Body() data: SlotCreateInput): Promise {
+ return await this.service.createSlot({
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Slot] })
+ @ApiNestedQuery(SlotFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "read",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async slots(@common.Req() request: Request): Promise {
+ const args = plainToClass(SlotFindManyArgs, request.query);
+ return this.service.slots({
+ ...args,
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Slot })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "read",
+ possession: "own",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async slot(
+ @common.Param() params: SlotWhereUniqueInput
+ ): Promise {
+ const result = await this.service.slot({
+ where: params,
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Slot })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "update",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async updateSlot(
+ @common.Param() params: SlotWhereUniqueInput,
+ @common.Body() data: SlotUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateSlot({
+ where: params,
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Slot })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "delete",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async deleteSlot(
+ @common.Param() params: SlotWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteSlot({
+ where: params,
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/slot.grpc.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.grpc.controller.base.ts
new file mode 100644
index 0000000..02104b7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.grpc.controller.base.ts
@@ -0,0 +1,202 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import { GrpcMethod } from "@nestjs/microservices";
+import { SlotService } from "../slot.service";
+import { SlotCreateInput } from "./SlotCreateInput";
+import { SlotWhereInput } from "./SlotWhereInput";
+import { SlotWhereUniqueInput } from "./SlotWhereUniqueInput";
+import { SlotFindManyArgs } from "./SlotFindManyArgs";
+import { SlotUpdateInput } from "./SlotUpdateInput";
+import { Slot } from "./Slot";
+
+export class SlotGrpcControllerBase {
+ constructor(protected readonly service: SlotService) {}
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Slot })
+ @GrpcMethod("SlotService", "createSlot")
+ async createSlot(@common.Body() data: SlotCreateInput): Promise {
+ return await this.service.createSlot({
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Slot] })
+ @ApiNestedQuery(SlotFindManyArgs)
+ @GrpcMethod("SlotService", "slots")
+ async slots(@common.Req() request: Request): Promise {
+ const args = plainToClass(SlotFindManyArgs, request.query);
+ return this.service.slots({
+ ...args,
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Slot })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("SlotService", "slot")
+ async slot(
+ @common.Param() params: SlotWhereUniqueInput
+ ): Promise {
+ const result = await this.service.slot({
+ where: params,
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Slot })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("SlotService", "updateSlot")
+ async updateSlot(
+ @common.Param() params: SlotWhereUniqueInput,
+ @common.Body() data: SlotUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateSlot({
+ where: params,
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Slot })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("SlotService", "deleteSlot")
+ async deleteSlot(
+ @common.Param() params: SlotWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteSlot({
+ where: params,
+ select: {
+ bid: true,
+ createdAt: true,
+ description: true,
+ id: true,
+ metrics: true,
+ name: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/slot.module.base.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.module.base.ts
new file mode 100644
index 0000000..45e77f9
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.module.base.ts
@@ -0,0 +1,18 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { Module } from "@nestjs/common";
+import { ACLModule } from "../../auth/acl.module";
+@Module({
+ imports: [ACLModule],
+ exports: [ACLModule],
+})
+export class SlotModuleBase {}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/slot.resolver.base.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.resolver.base.ts
new file mode 100644
index 0000000..8b27626
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.resolver.base.ts
@@ -0,0 +1,170 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as graphql from "@nestjs/graphql";
+import { GraphQLError } from "graphql";
+import { isRecordNotFoundError } from "../../prisma.util";
+import { MetaQueryPayload } from "../../util/MetaQueryPayload";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { Slot } from "./Slot";
+import { SlotCountArgs } from "./SlotCountArgs";
+import { SlotFindManyArgs } from "./SlotFindManyArgs";
+import { SlotFindUniqueArgs } from "./SlotFindUniqueArgs";
+import { CreateSlotArgs } from "./CreateSlotArgs";
+import { UpdateSlotArgs } from "./UpdateSlotArgs";
+import { DeleteSlotArgs } from "./DeleteSlotArgs";
+import { User } from "../../user/base/User";
+import { SlotService } from "../slot.service";
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Slot)
+export class SlotResolverBase {
+ constructor(
+ protected readonly service: SlotService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+
+ @graphql.Query(() => MetaQueryPayload)
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "read",
+ possession: "any",
+ })
+ async _slotsMeta(
+ @graphql.Args() args: SlotCountArgs
+ ): Promise {
+ const result = await this.service.count(args);
+ return {
+ count: result,
+ };
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => [Slot])
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "read",
+ possession: "any",
+ })
+ async slots(@graphql.Args() args: SlotFindManyArgs): Promise {
+ return this.service.slots(args);
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => Slot, { nullable: true })
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "read",
+ possession: "own",
+ })
+ async slot(@graphql.Args() args: SlotFindUniqueArgs): Promise {
+ const result = await this.service.slot(args);
+ if (result === null) {
+ return null;
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Slot)
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "create",
+ possession: "any",
+ })
+ async createSlot(@graphql.Args() args: CreateSlotArgs): Promise {
+ return await this.service.createSlot({
+ ...args,
+ data: {
+ ...args.data,
+
+ user: args.data.user
+ ? {
+ connect: args.data.user,
+ }
+ : undefined,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Slot)
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "update",
+ possession: "any",
+ })
+ async updateSlot(@graphql.Args() args: UpdateSlotArgs): Promise {
+ try {
+ return await this.service.updateSlot({
+ ...args,
+ data: {
+ ...args.data,
+
+ user: args.data.user
+ ? {
+ connect: args.data.user,
+ }
+ : undefined,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @graphql.Mutation(() => Slot)
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "delete",
+ possession: "any",
+ })
+ async deleteSlot(@graphql.Args() args: DeleteSlotArgs): Promise {
+ try {
+ return await this.service.deleteSlot(args);
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.ResolveField(() => User, {
+ nullable: true,
+ name: "user",
+ })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "read",
+ possession: "any",
+ })
+ async getUser(@graphql.Parent() parent: Slot): Promise {
+ const result = await this.service.getUser(parent.id);
+
+ if (!result) {
+ return null;
+ }
+ return result;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/base/slot.service.base.ts b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.service.base.ts
new file mode 100644
index 0000000..77126be
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/base/slot.service.base.ts
@@ -0,0 +1,45 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { PrismaService } from "../../prisma/prisma.service";
+import { Prisma, Slot as PrismaSlot, User as PrismaUser } from "@prisma/client";
+
+export class SlotServiceBase {
+ constructor(protected readonly prisma: PrismaService) {}
+
+ async count(args: Omit): Promise {
+ return this.prisma.slot.count(args);
+ }
+
+ async slots(args: Prisma.SlotFindManyArgs): Promise {
+ return this.prisma.slot.findMany(args);
+ }
+ async slot(args: Prisma.SlotFindUniqueArgs): Promise {
+ return this.prisma.slot.findUnique(args);
+ }
+ async createSlot(args: Prisma.SlotCreateArgs): Promise {
+ return this.prisma.slot.create(args);
+ }
+ async updateSlot(args: Prisma.SlotUpdateArgs): Promise {
+ return this.prisma.slot.update(args);
+ }
+ async deleteSlot(args: Prisma.SlotDeleteArgs): Promise {
+ return this.prisma.slot.delete(args);
+ }
+
+ async getUser(parentId: string): Promise {
+ return this.prisma.slot
+ .findUnique({
+ where: { id: parentId },
+ })
+ .user();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/slot.controller.ts b/apps/vesst-discord-bot-backend-server/src/slot/slot.controller.ts
new file mode 100644
index 0000000..c859417
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/slot.controller.ts
@@ -0,0 +1,17 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import * as nestAccessControl from "nest-access-control";
+import { SlotService } from "./slot.service";
+import { SlotControllerBase } from "./base/slot.controller.base";
+
+@swagger.ApiTags("slots")
+@common.Controller("slots")
+export class SlotController extends SlotControllerBase {
+ constructor(
+ protected readonly service: SlotService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/slot.grpc.controller.ts b/apps/vesst-discord-bot-backend-server/src/slot/slot.grpc.controller.ts
new file mode 100644
index 0000000..63e6504
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/slot.grpc.controller.ts
@@ -0,0 +1,12 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { SlotService } from "./slot.service";
+import { SlotGrpcControllerBase } from "./base/slot.grpc.controller.base";
+
+@swagger.ApiTags("slots")
+@common.Controller("slots")
+export class SlotGrpcController extends SlotGrpcControllerBase {
+ constructor(protected readonly service: SlotService) {
+ super(service);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/slot.module.ts b/apps/vesst-discord-bot-backend-server/src/slot/slot.module.ts
new file mode 100644
index 0000000..db640e8
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/slot.module.ts
@@ -0,0 +1,15 @@
+import { Module, forwardRef } from "@nestjs/common";
+import { AuthModule } from "../auth/auth.module";
+import { SlotModuleBase } from "./base/slot.module.base";
+import { SlotService } from "./slot.service";
+import { SlotController } from "./slot.controller";
+import { SlotGrpcController } from "./slot.grpc.controller";
+import { SlotResolver } from "./slot.resolver";
+
+@Module({
+ imports: [SlotModuleBase, forwardRef(() => AuthModule)],
+ controllers: [SlotController, SlotGrpcController],
+ providers: [SlotService, SlotResolver],
+ exports: [SlotService],
+})
+export class SlotModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/slot.proto b/apps/vesst-discord-bot-backend-server/src/slot/slot.proto
new file mode 100644
index 0000000..4aa7222
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/slot.proto
@@ -0,0 +1,49 @@
+syntax = "proto3";
+
+ package slot;
+service SlotService {
+ rpc createSlot (SlotCreateInput) returns (Slot) {}
+rpc slots (findManyParams) returns (stream Slot) {}
+rpc slot (SlotWhereUniqueInput) returns (Slot) {}
+rpc updateSlot (SlotUpdateInput) returns (Slot) {}
+rpc deleteSlot (SlotWhereUniqueInput) returns (Slot) {}
+ }
+message SlotCreateInput {
+int32 bid = 1;
+string createdAt = 2;
+string description = 3;
+string id = 4;
+string metrics = 5;
+string name = 6;
+string updatedAt = 7;
+};
+message Slot {
+int32 bid = 1;
+string createdAt = 2;
+string description = 3;
+string id = 4;
+string metrics = 5;
+string name = 6;
+string updatedAt = 7;
+};
+message SlotWhereUniqueInput {
+int32 bid = 1;
+string createdAt = 2;
+string description = 3;
+string id = 4;
+string metrics = 5;
+string name = 6;
+string updatedAt = 7;
+};
+message SlotUpdateInput {
+int32 bid = 1;
+string createdAt = 2;
+string description = 3;
+string id = 4;
+string metrics = 5;
+string name = 6;
+string updatedAt = 7;
+};
+message findManyParams {
+
+};
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/slot.resolver.ts b/apps/vesst-discord-bot-backend-server/src/slot/slot.resolver.ts
new file mode 100644
index 0000000..87e7c5e
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/slot.resolver.ts
@@ -0,0 +1,20 @@
+import * as graphql from "@nestjs/graphql";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { SlotResolverBase } from "./base/slot.resolver.base";
+import { Slot } from "./base/Slot";
+import { SlotService } from "./slot.service";
+
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Slot)
+export class SlotResolver extends SlotResolverBase {
+ constructor(
+ protected readonly service: SlotService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/slot/slot.service.ts b/apps/vesst-discord-bot-backend-server/src/slot/slot.service.ts
new file mode 100644
index 0000000..85a2516
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/slot/slot.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../prisma/prisma.service";
+import { SlotServiceBase } from "./base/slot.service.base";
+
+@Injectable()
+export class SlotService extends SlotServiceBase {
+ constructor(protected readonly prisma: PrismaService) {
+ super(prisma);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/swagger.ts b/apps/vesst-discord-bot-backend-server/src/swagger.ts
new file mode 100644
index 0000000..a7f5a90
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/swagger.ts
@@ -0,0 +1,20 @@
+import { DocumentBuilder, SwaggerCustomOptions } from "@nestjs/swagger";
+
+export const swaggerPath = "api";
+
+export const swaggerDocumentOptions = new DocumentBuilder()
+ .setTitle("VESSTDiscordBotBackend")
+ .setDescription(
+ 'Backend service for managing VESST Discord Bot features\n\n## Congratulations! Your service resource is ready.\n \nPlease note that all endpoints are secured with JWT Bearer authentication.\nBy default, your service resource comes with one user with the username "admin" and password "admin".\nLearn more in [our docs](https://docs.amplication.com)'
+ )
+ .addBearerAuth()
+ .build();
+
+export const swaggerSetupOptions: SwaggerCustomOptions = {
+ swaggerOptions: {
+ persistAuthorization: true,
+ },
+ customCssUrl: "../swagger/swagger.css",
+ customfavIcon: "../swagger/favicon.png",
+ customSiteTitle: "VESSTDiscordBotBackend",
+};
diff --git a/apps/vesst-discord-bot-backend-server/src/swagger/favicon.png b/apps/vesst-discord-bot-backend-server/src/swagger/favicon.png
new file mode 100644
index 0000000..a79882d
Binary files /dev/null and b/apps/vesst-discord-bot-backend-server/src/swagger/favicon.png differ
diff --git a/apps/vesst-discord-bot-backend-server/src/swagger/logo-amplication-white.svg b/apps/vesst-discord-bot-backend-server/src/swagger/logo-amplication-white.svg
new file mode 100644
index 0000000..0054cd4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/swagger/logo-amplication-white.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/vesst-discord-bot-backend-server/src/swagger/swagger.css b/apps/vesst-discord-bot-backend-server/src/swagger/swagger.css
new file mode 100644
index 0000000..b7c4037
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/swagger/swagger.css
@@ -0,0 +1,321 @@
+html,
+body {
+ background-color: #f4f4f7;
+}
+
+body {
+ margin: auto;
+ line-height: 1.6;
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ color: #121242;
+}
+
+.swagger-ui {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+}
+
+.swagger-ui button,
+.swagger-ui input,
+.swagger-ui optgroup,
+.swagger-ui select,
+.swagger-ui textarea,
+.swagger-ui .parameter__name,
+.swagger-ui .parameters-col_name > *,
+.swagger-ui label {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ font-weight: normal;
+ font-size: 12px;
+ outline: none;
+}
+
+.swagger-ui textarea {
+ border: 1px solid #d0d0d9;
+ min-height: 100px;
+}
+
+.swagger-ui input[type="email"],
+.swagger-ui input[type="file"],
+.swagger-ui input[type="password"],
+.swagger-ui input[type="search"],
+.swagger-ui input[type="text"],
+.swagger-ui textarea {
+ border-radius: 3px;
+}
+
+.swagger-ui input[disabled],
+.swagger-ui select[disabled],
+.swagger-ui textarea[disabled] {
+ background: #f4f4f7;
+ color: #b8b8c6;
+}
+
+.swagger-ui .btn {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ font-weight: 500;
+ box-shadow: none;
+ border: 1px solid #d0d0d9;
+ height: 28px;
+ border-radius: 14px;
+ background-color: #fff;
+ color: #7950ed;
+}
+
+.swagger-ui .btn:hover {
+ box-shadow: none;
+}
+
+/* topbar */
+
+.swagger-ui .topbar {
+ background-color: #7950ed;
+ height: 80px;
+ padding: 0;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+}
+
+.swagger-ui .topbar-wrapper a {
+ display: block;
+ width: 206px;
+ height: 35px;
+ background-image: url("logo-amplication-white.svg");
+ background-repeat: no-repeat;
+ background-size: contain;
+}
+
+.swagger-ui .topbar-wrapper svg,
+.swagger-ui .topbar-wrapper img {
+ display: none;
+}
+
+/* title */
+.swagger-ui .info {
+ margin: 0;
+}
+
+.swagger-ui .info .title {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ font-size: 32px;
+ font-weight: 600;
+}
+
+.swagger-ui .information-container {
+ padding-top: 50px;
+ padding-bottom: 20px;
+ position: relative;
+}
+
+.swagger-ui .info .title small.version-stamp {
+ display: none;
+}
+
+.swagger-ui .info .title small {
+ background-color: #a787ff;
+}
+
+.swagger-ui .info .description p {
+ max-width: 1000px;
+ margin: 0;
+}
+
+.swagger-ui .info .description p,
+.swagger-ui .info .description a {
+ font-size: 1rem;
+}
+
+.swagger-ui .information-container section {
+ position: relative;
+}
+
+.swagger-ui .scheme-container {
+ box-shadow: none;
+ background-color: transparent;
+ position: relative;
+ margin: 0;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ padding: 0;
+}
+
+.swagger-ui .scheme-container .auth-wrapper {
+ justify-content: flex-start;
+}
+
+.swagger-ui .btn.authorize {
+ box-shadow: none;
+ border: 1px solid #d0d0d9;
+ height: 40px;
+ border-radius: 20px;
+ background-color: #fff;
+ color: #7950ed;
+}
+
+.swagger-ui .btn.authorize svg {
+ fill: #7950ed;
+}
+
+/* content */
+
+.swagger-ui .opblock-tag {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ font-size: 28px;
+ font-weight: 600;
+}
+
+.swagger-ui .opblock.is-open .opblock-summary {
+ border-color: #e7e7ec !important;
+ border-bottom: none;
+}
+
+.swagger-ui .opblock .opblock-section-header {
+ background-color: #fff;
+ border: none;
+ border-top: 1px solid #e7e7ec;
+ border-bottom: 1px solid #e7e7ec;
+ box-shadow: none;
+}
+
+.swagger-ui .opblock .tab-header .tab-item.active h4 span:after {
+ display: none;
+}
+
+.swagger-ui .opblock.opblock-post {
+ border: 1px solid #e7e7ec;
+ background: #f9f9fa;
+ box-shadow: none;
+ color: #fff;
+}
+
+.swagger-ui .opblock.opblock-post:hover,
+.swagger-ui .opblock.opblock-post.is-open {
+ border-color: #31c587;
+}
+
+.swagger-ui .opblock.opblock-post .opblock-summary-method {
+ background-color: #31c587;
+}
+
+.swagger-ui .opblock.opblock-get {
+ border: 1px solid #e7e7ec;
+ background: #f9f9fa;
+ box-shadow: none;
+}
+.swagger-ui .opblock.opblock-get:hover,
+.swagger-ui .opblock.opblock-get.is-open {
+ border-color: #20a4f3;
+}
+.swagger-ui .opblock.opblock-get .opblock-summary-method {
+ background-color: #20a4f3;
+}
+
+.swagger-ui .opblock.opblock-delete {
+ border: 1px solid #e7e7ec;
+ background: #f9f9fa;
+ box-shadow: none;
+}
+.swagger-ui .opblock.opblock-delete:hover,
+.swagger-ui .opblock.opblock-delete.is-open {
+ border-color: #e93c51;
+}
+.swagger-ui .opblock.opblock-delete .opblock-summary-method {
+ background-color: #e93c51;
+}
+
+.swagger-ui .opblock.opblock-patch {
+ border: 1px solid #e7e7ec;
+ background: #f9f9fa;
+ box-shadow: none;
+}
+.swagger-ui .opblock.opblock-patch:hover,
+.swagger-ui .opblock.opblock-patch.is-open {
+ border-color: #41cadd;
+}
+.swagger-ui .opblock.opblock-patch .opblock-summary-method {
+ background-color: #41cadd;
+}
+
+.swagger-ui .opblock-body pre {
+ background-color: #121242 !important;
+}
+
+.swagger-ui select,
+.swagger-ui .response-control-media-type--accept-controller select {
+ border: 1px solid #d0d0d9;
+ box-shadow: none;
+ outline: none;
+}
+
+/* models */
+
+.swagger-ui section.models {
+ background-color: #fff;
+ border: 1px solid #e7e7ec;
+}
+
+.swagger-ui section.models.is-open h4 {
+ border-bottom: 1px solid #e7e7ec;
+}
+
+.swagger-ui section.models .model-container,
+.swagger-ui section.models .model-container:hover {
+ background-color: #f4f4f7;
+ color: #121242;
+}
+
+.swagger-ui .model-title {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ font-weight: normal;
+ font-size: 15px;
+ color: #121242;
+}
+
+/* modal */
+
+.swagger-ui .dialog-ux .modal-ux-header h3,
+.swagger-ui .dialog-ux .modal-ux-content h4,
+.swagger-ui .dialog-ux .modal-ux-content h4 code {
+ font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif;
+ font-weight: normal;
+ font-size: 15px;
+ color: #121242;
+}
+
+.swagger-ui .dialog-ux .modal-ux-content .btn.authorize {
+ height: 28px;
+ border-radius: 14px;
+}
+
+.swagger-ui .auth-btn-wrapper {
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ justify-content: flex-start;
+}
+
+.swagger-ui .auth-btn-wrapper .btn-done {
+ border: none;
+ color: #121242;
+ margin-right: 0;
+}
+
+.swagger-ui .authorization__btn {
+ fill: #414168;
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/tests/auth/constants.ts b/apps/vesst-discord-bot-backend-server/src/tests/auth/constants.ts
new file mode 100644
index 0000000..98e4887
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/tests/auth/constants.ts
@@ -0,0 +1,19 @@
+import { Credentials } from "../../auth/Credentials";
+import { UserInfo } from "../../auth/UserInfo";
+
+export const VALID_ID = "1";
+
+export const TEST_USER: UserInfo = {
+ id: "cl7qmjh4h0000tothyjqapgj5",
+ roles: ["User"],
+ username: "ofek",
+};
+export const SIGN_TOKEN = "SIGN_TOKEN";
+export const VALID_CREDENTIALS: Credentials = {
+ username: "Valid User",
+ password: "Valid User Password",
+};
+export const INVALID_CREDENTIALS: Credentials = {
+ username: "Invalid User",
+ password: "Invalid User Password",
+};
diff --git a/apps/vesst-discord-bot-backend-server/src/tests/auth/jwt/jwt.strategy.spec.ts b/apps/vesst-discord-bot-backend-server/src/tests/auth/jwt/jwt.strategy.spec.ts
new file mode 100644
index 0000000..36bbb24
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/tests/auth/jwt/jwt.strategy.spec.ts
@@ -0,0 +1,28 @@
+import { UnauthorizedException } from "@nestjs/common";
+import { mock } from "jest-mock-extended";
+import { JwtStrategyBase } from "../../../auth/jwt/base/jwt.strategy.base";
+import { TEST_USER } from "../constants";
+import { UserService } from "../../../user/user.service";
+describe("Testing the jwtStrategyBase.validate()", () => {
+ const userService = mock();
+ const jwtStrategy = new JwtStrategyBase("Secrete", userService);
+ beforeEach(() => {
+ userService.user.mockClear();
+ });
+ it("should throw UnauthorizedException where there is no user", async () => {
+ //ARRANGE
+ userService.user
+ .calledWith({
+ where: { username: TEST_USER.username },
+ })
+ .mockReturnValue(Promise.resolve(null));
+ //ACT
+ const result = jwtStrategy.validate({
+ id: TEST_USER.id,
+ username: TEST_USER.username,
+ roles: TEST_USER.roles,
+ });
+ //ASSERT
+ return expect(result).rejects.toThrowError(UnauthorizedException);
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/tests/auth/token.service.spec.ts b/apps/vesst-discord-bot-backend-server/src/tests/auth/token.service.spec.ts
new file mode 100644
index 0000000..83b5a51
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/tests/auth/token.service.spec.ts
@@ -0,0 +1,47 @@
+import { JwtService } from "@nestjs/jwt";
+import { mock } from "jest-mock-extended";
+import { TokenServiceBase } from "../../auth/base/token.service.base";
+import {
+ INVALID_PASSWORD_ERROR,
+ INVALID_USERNAME_ERROR,
+} from "../../auth/constants";
+import { SIGN_TOKEN, VALID_CREDENTIALS, VALID_ID } from "./constants";
+
+describe("Testing the TokenServiceBase", () => {
+ let tokenServiceBase: TokenServiceBase;
+ const jwtService = mock();
+ beforeEach(() => {
+ tokenServiceBase = new TokenServiceBase(jwtService);
+ jwtService.signAsync.mockClear();
+ });
+ describe("Testing the BasicTokenService.createToken()", () => {
+ it("should create valid token for valid username and password", async () => {
+ jwtService.signAsync.mockReturnValue(Promise.resolve(SIGN_TOKEN));
+ expect(
+ await tokenServiceBase.createToken({
+ id: VALID_ID,
+ username: VALID_CREDENTIALS.username,
+ password: VALID_CREDENTIALS.password,
+ })
+ ).toBe(SIGN_TOKEN);
+ });
+ it("should reject when username missing", () => {
+ const result = tokenServiceBase.createToken({
+ id: VALID_ID,
+ //@ts-ignore
+ username: null,
+ password: VALID_CREDENTIALS.password,
+ });
+ return expect(result).rejects.toBe(INVALID_USERNAME_ERROR);
+ });
+ it("should reject when password missing", () => {
+ const result = tokenServiceBase.createToken({
+ id: VALID_ID,
+ username: VALID_CREDENTIALS.username,
+ //@ts-ignore
+ password: null,
+ });
+ return expect(result).rejects.toBe(INVALID_PASSWORD_ERROR);
+ });
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/tests/health/health.service.spec.ts b/apps/vesst-discord-bot-backend-server/src/tests/health/health.service.spec.ts
new file mode 100644
index 0000000..07cf0f4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/tests/health/health.service.spec.ts
@@ -0,0 +1,36 @@
+import { mock } from "jest-mock-extended";
+import { PrismaService } from "nestjs-prisma";
+import { HealthServiceBase } from "../../health/base/health.service.base";
+
+describe("Testing the HealthServiceBase", () => {
+ //ARRANGE
+ let prismaService: PrismaService;
+ let healthServiceBase: HealthServiceBase;
+
+ describe("Testing the isDbReady function in HealthServiceBase class", () => {
+ beforeEach(() => {
+ prismaService = mock();
+ healthServiceBase = new HealthServiceBase(prismaService);
+ });
+ it("should return true if allow connection to db", async () => {
+ //ARRANGE
+ prismaService.$runCommandRaw
+ //@ts-ignore
+ .mockReturnValue(Promise.resolve(true));
+ //ACT
+ const response = await healthServiceBase.isDbReady();
+ //ASSERT
+ expect(response).toBe(true);
+ });
+ it("should return false if db is not available", async () => {
+ //ARRANGE
+ prismaService.$runCommandRaw
+ //@ts-ignore
+ .mockReturnValue(Promise.reject(false));
+ //ACT
+ const response = await healthServiceBase.isDbReady();
+ //ASSERT
+ expect(response).toBe(false);
+ });
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/CreateTicketArgs.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/CreateTicketArgs.ts
new file mode 100644
index 0000000..97fa81a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/CreateTicketArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketCreateInput } from "./TicketCreateInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class CreateTicketArgs {
+ @ApiProperty({
+ required: true,
+ type: () => TicketCreateInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketCreateInput)
+ @Field(() => TicketCreateInput, { nullable: false })
+ data!: TicketCreateInput;
+}
+
+export { CreateTicketArgs as CreateTicketArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/DeleteTicketArgs.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/DeleteTicketArgs.ts
new file mode 100644
index 0000000..5626059
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/DeleteTicketArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class DeleteTicketArgs {
+ @ApiProperty({
+ required: true,
+ type: () => TicketWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketWhereUniqueInput)
+ @Field(() => TicketWhereUniqueInput, { nullable: false })
+ where!: TicketWhereUniqueInput;
+}
+
+export { DeleteTicketArgs as DeleteTicketArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/EnumTicketPriority.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/EnumTicketPriority.ts
new file mode 100644
index 0000000..947104a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/EnumTicketPriority.ts
@@ -0,0 +1,20 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { registerEnumType } from "@nestjs/graphql";
+
+export enum EnumTicketPriority {
+ Option_1 = "Option1",
+}
+
+registerEnumType(EnumTicketPriority, {
+ name: "EnumTicketPriority",
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/EnumTicketStatus.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/EnumTicketStatus.ts
new file mode 100644
index 0000000..31a9661
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/EnumTicketStatus.ts
@@ -0,0 +1,20 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { registerEnumType } from "@nestjs/graphql";
+
+export enum EnumTicketStatus {
+ Option_1 = "Option1",
+}
+
+registerEnumType(EnumTicketStatus, {
+ name: "EnumTicketStatus",
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/Ticket.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/Ticket.ts
new file mode 100644
index 0000000..92c4372
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/Ticket.ts
@@ -0,0 +1,119 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsDate,
+ IsOptional,
+ IsString,
+ MaxLength,
+ IsEnum,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { EnumTicketPriority } from "./EnumTicketPriority";
+import { EnumTicketStatus } from "./EnumTicketStatus";
+import { User } from "../../user/base/User";
+
+@ObjectType()
+class Ticket {
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ createdAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateClosed!: Date | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateCreated!: Date | null;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ issue!: string | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketPriority,
+ })
+ @IsEnum(EnumTicketPriority)
+ @IsOptional()
+ @Field(() => EnumTicketPriority, {
+ nullable: true,
+ })
+ priority?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketStatus,
+ })
+ @IsEnum(EnumTicketStatus)
+ @IsOptional()
+ @Field(() => EnumTicketStatus, {
+ nullable: true,
+ })
+ status?: "Option1" | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ updatedAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ type: () => User,
+ })
+ @ValidateNested()
+ @Type(() => User)
+ @IsOptional()
+ user?: User | null;
+}
+
+export { Ticket as Ticket };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketCountArgs.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketCountArgs.ts
new file mode 100644
index 0000000..374bbe2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketCountArgs.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketWhereInput } from "./TicketWhereInput";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class TicketCountArgs {
+ @ApiProperty({
+ required: false,
+ type: () => TicketWhereInput,
+ })
+ @Field(() => TicketWhereInput, { nullable: true })
+ @Type(() => TicketWhereInput)
+ where?: TicketWhereInput;
+}
+
+export { TicketCountArgs as TicketCountArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketCreateInput.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketCreateInput.ts
new file mode 100644
index 0000000..bbdddb7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketCreateInput.ts
@@ -0,0 +1,98 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsDate,
+ IsOptional,
+ IsString,
+ MaxLength,
+ IsEnum,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { EnumTicketPriority } from "./EnumTicketPriority";
+import { EnumTicketStatus } from "./EnumTicketStatus";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class TicketCreateInput {
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateClosed?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateCreated?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ issue?: string | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketPriority,
+ })
+ @IsEnum(EnumTicketPriority)
+ @IsOptional()
+ @Field(() => EnumTicketPriority, {
+ nullable: true,
+ })
+ priority?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketStatus,
+ })
+ @IsEnum(EnumTicketStatus)
+ @IsOptional()
+ @Field(() => EnumTicketStatus, {
+ nullable: true,
+ })
+ status?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput | null;
+}
+
+export { TicketCreateInput as TicketCreateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketFindManyArgs.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketFindManyArgs.ts
new file mode 100644
index 0000000..60d9bc5
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketFindManyArgs.ts
@@ -0,0 +1,62 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketWhereInput } from "./TicketWhereInput";
+import { IsOptional, ValidateNested, IsInt } from "class-validator";
+import { Type } from "class-transformer";
+import { TicketOrderByInput } from "./TicketOrderByInput";
+
+@ArgsType()
+class TicketFindManyArgs {
+ @ApiProperty({
+ required: false,
+ type: () => TicketWhereInput,
+ })
+ @IsOptional()
+ @ValidateNested()
+ @Field(() => TicketWhereInput, { nullable: true })
+ @Type(() => TicketWhereInput)
+ where?: TicketWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: [TicketOrderByInput],
+ })
+ @IsOptional()
+ @ValidateNested({ each: true })
+ @Field(() => [TicketOrderByInput], { nullable: true })
+ @Type(() => TicketOrderByInput)
+ orderBy?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ skip?: number;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ take?: number;
+}
+
+export { TicketFindManyArgs as TicketFindManyArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketFindUniqueArgs.ts
new file mode 100644
index 0000000..d88e7b7
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketFindUniqueArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class TicketFindUniqueArgs {
+ @ApiProperty({
+ required: true,
+ type: () => TicketWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketWhereUniqueInput)
+ @Field(() => TicketWhereUniqueInput, { nullable: false })
+ where!: TicketWhereUniqueInput;
+}
+
+export { TicketFindUniqueArgs as TicketFindUniqueArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketListRelationFilter.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketListRelationFilter.ts
new file mode 100644
index 0000000..5383c26
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketListRelationFilter.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketWhereInput } from "./TicketWhereInput";
+import { ValidateNested, IsOptional } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class TicketListRelationFilter {
+ @ApiProperty({
+ required: false,
+ type: () => TicketWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketWhereInput)
+ @IsOptional()
+ @Field(() => TicketWhereInput, {
+ nullable: true,
+ })
+ every?: TicketWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => TicketWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketWhereInput)
+ @IsOptional()
+ @Field(() => TicketWhereInput, {
+ nullable: true,
+ })
+ some?: TicketWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => TicketWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketWhereInput)
+ @IsOptional()
+ @Field(() => TicketWhereInput, {
+ nullable: true,
+ })
+ none?: TicketWhereInput;
+}
+export { TicketListRelationFilter as TicketListRelationFilter };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketOrderByInput.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketOrderByInput.ts
new file mode 100644
index 0000000..3385a68
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketOrderByInput.ts
@@ -0,0 +1,122 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsOptional, IsEnum } from "class-validator";
+import { SortOrder } from "../../util/SortOrder";
+
+@InputType({
+ isAbstract: true,
+ description: undefined,
+})
+class TicketOrderByInput {
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ createdAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ dateClosed?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ dateCreated?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ id?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ issue?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ priority?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ status?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ updatedAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ userId?: SortOrder;
+}
+
+export { TicketOrderByInput as TicketOrderByInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketUpdateInput.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketUpdateInput.ts
new file mode 100644
index 0000000..2541a66
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketUpdateInput.ts
@@ -0,0 +1,98 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsDate,
+ IsOptional,
+ IsString,
+ MaxLength,
+ IsEnum,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { EnumTicketPriority } from "./EnumTicketPriority";
+import { EnumTicketStatus } from "./EnumTicketStatus";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class TicketUpdateInput {
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateClosed?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @IsOptional()
+ @Field(() => Date, {
+ nullable: true,
+ })
+ dateCreated?: Date | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ issue?: string | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketPriority,
+ })
+ @IsEnum(EnumTicketPriority)
+ @IsOptional()
+ @Field(() => EnumTicketPriority, {
+ nullable: true,
+ })
+ priority?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketStatus,
+ })
+ @IsEnum(EnumTicketStatus)
+ @IsOptional()
+ @Field(() => EnumTicketStatus, {
+ nullable: true,
+ })
+ status?: "Option1" | null;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput | null;
+}
+
+export { TicketUpdateInput as TicketUpdateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketWhereInput.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketWhereInput.ts
new file mode 100644
index 0000000..2a1514f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketWhereInput.ts
@@ -0,0 +1,104 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { DateTimeNullableFilter } from "../../util/DateTimeNullableFilter";
+import { Type } from "class-transformer";
+import { IsOptional, IsEnum, ValidateNested } from "class-validator";
+import { StringFilter } from "../../util/StringFilter";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { EnumTicketPriority } from "./EnumTicketPriority";
+import { EnumTicketStatus } from "./EnumTicketStatus";
+import { UserWhereUniqueInput } from "../../user/base/UserWhereUniqueInput";
+
+@InputType()
+class TicketWhereInput {
+ @ApiProperty({
+ required: false,
+ type: DateTimeNullableFilter,
+ })
+ @Type(() => DateTimeNullableFilter)
+ @IsOptional()
+ @Field(() => DateTimeNullableFilter, {
+ nullable: true,
+ })
+ dateClosed?: DateTimeNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: DateTimeNullableFilter,
+ })
+ @Type(() => DateTimeNullableFilter)
+ @IsOptional()
+ @Field(() => DateTimeNullableFilter, {
+ nullable: true,
+ })
+ dateCreated?: DateTimeNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ id?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ issue?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketPriority,
+ })
+ @IsEnum(EnumTicketPriority)
+ @IsOptional()
+ @Field(() => EnumTicketPriority, {
+ nullable: true,
+ })
+ priority?: "Option1";
+
+ @ApiProperty({
+ required: false,
+ enum: EnumTicketStatus,
+ })
+ @IsEnum(EnumTicketStatus)
+ @IsOptional()
+ @Field(() => EnumTicketStatus, {
+ nullable: true,
+ })
+ status?: "Option1";
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @IsOptional()
+ @Field(() => UserWhereUniqueInput, {
+ nullable: true,
+ })
+ user?: UserWhereUniqueInput;
+}
+
+export { TicketWhereInput as TicketWhereInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketWhereUniqueInput.ts
new file mode 100644
index 0000000..1c432a0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/TicketWhereUniqueInput.ts
@@ -0,0 +1,27 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString } from "class-validator";
+
+@InputType()
+class TicketWhereUniqueInput {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+}
+
+export { TicketWhereUniqueInput as TicketWhereUniqueInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/UpdateTicketArgs.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/UpdateTicketArgs.ts
new file mode 100644
index 0000000..fc95f3b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/UpdateTicketArgs.ts
@@ -0,0 +1,40 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { TicketUpdateInput } from "./TicketUpdateInput";
+
+@ArgsType()
+class UpdateTicketArgs {
+ @ApiProperty({
+ required: true,
+ type: () => TicketWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketWhereUniqueInput)
+ @Field(() => TicketWhereUniqueInput, { nullable: false })
+ where!: TicketWhereUniqueInput;
+
+ @ApiProperty({
+ required: true,
+ type: () => TicketUpdateInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketUpdateInput)
+ @Field(() => TicketUpdateInput, { nullable: false })
+ data!: TicketUpdateInput;
+}
+
+export { UpdateTicketArgs as UpdateTicketArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.controller.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.controller.base.spec.ts
new file mode 100644
index 0000000..179197b
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.controller.base.spec.ts
@@ -0,0 +1,210 @@
+import { Test } from "@nestjs/testing";
+import {
+ INestApplication,
+ HttpStatus,
+ ExecutionContext,
+ CallHandler,
+} from "@nestjs/common";
+import request from "supertest";
+import { ACGuard } from "nest-access-control";
+import { DefaultAuthGuard } from "../../auth/defaultAuth.guard";
+import { ACLModule } from "../../auth/acl.module";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { map } from "rxjs";
+import { TicketController } from "../ticket.controller";
+import { TicketService } from "../ticket.service";
+
+const nonExistingId = "nonExistingId";
+const existingId = "existingId";
+const CREATE_INPUT = {
+ createdAt: new Date(),
+ dateClosed: new Date(),
+ dateCreated: new Date(),
+ id: "exampleId",
+ issue: "exampleIssue",
+ updatedAt: new Date(),
+};
+const CREATE_RESULT = {
+ createdAt: new Date(),
+ dateClosed: new Date(),
+ dateCreated: new Date(),
+ id: "exampleId",
+ issue: "exampleIssue",
+ updatedAt: new Date(),
+};
+const FIND_MANY_RESULT = [
+ {
+ createdAt: new Date(),
+ dateClosed: new Date(),
+ dateCreated: new Date(),
+ id: "exampleId",
+ issue: "exampleIssue",
+ updatedAt: new Date(),
+ },
+];
+const FIND_ONE_RESULT = {
+ createdAt: new Date(),
+ dateClosed: new Date(),
+ dateCreated: new Date(),
+ id: "exampleId",
+ issue: "exampleIssue",
+ updatedAt: new Date(),
+};
+
+const service = {
+ createTicket() {
+ return CREATE_RESULT;
+ },
+ tickets: () => FIND_MANY_RESULT,
+ ticket: ({ where }: { where: { id: string } }) => {
+ switch (where.id) {
+ case existingId:
+ return FIND_ONE_RESULT;
+ case nonExistingId:
+ return null;
+ }
+ },
+};
+
+const basicAuthGuard = {
+ canActivate: (context: ExecutionContext) => {
+ const argumentHost = context.switchToHttp();
+ const request = argumentHost.getRequest();
+ request.user = {
+ roles: ["user"],
+ };
+ return true;
+ },
+};
+
+const acGuard = {
+ canActivate: () => {
+ return true;
+ },
+};
+
+const aclFilterResponseInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle().pipe(
+ map((data) => {
+ return data;
+ })
+ );
+ },
+};
+const aclValidateRequestInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle();
+ },
+};
+
+describe("Ticket", () => {
+ let app: INestApplication;
+
+ beforeAll(async () => {
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ {
+ provide: TicketService,
+ useValue: service,
+ },
+ ],
+ controllers: [TicketController],
+ imports: [ACLModule],
+ })
+ .overrideGuard(DefaultAuthGuard)
+ .useValue(basicAuthGuard)
+ .overrideGuard(ACGuard)
+ .useValue(acGuard)
+ .overrideInterceptor(AclFilterResponseInterceptor)
+ .useValue(aclFilterResponseInterceptor)
+ .overrideInterceptor(AclValidateRequestInterceptor)
+ .useValue(aclValidateRequestInterceptor)
+ .compile();
+
+ app = moduleRef.createNestApplication();
+ await app.init();
+ });
+
+ test("POST /tickets", async () => {
+ await request(app.getHttpServer())
+ .post("/tickets")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ dateClosed: CREATE_RESULT.dateClosed.toISOString(),
+ dateCreated: CREATE_RESULT.dateCreated.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("GET /tickets", async () => {
+ await request(app.getHttpServer())
+ .get("/tickets")
+ .expect(HttpStatus.OK)
+ .expect([
+ {
+ ...FIND_MANY_RESULT[0],
+ createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(),
+ dateClosed: FIND_MANY_RESULT[0].dateClosed.toISOString(),
+ dateCreated: FIND_MANY_RESULT[0].dateCreated.toISOString(),
+ updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(),
+ },
+ ]);
+ });
+
+ test("GET /tickets/:id non existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/tickets"}/${nonExistingId}`)
+ .expect(HttpStatus.NOT_FOUND)
+ .expect({
+ statusCode: HttpStatus.NOT_FOUND,
+ message: `No resource was found for {"${"id"}":"${nonExistingId}"}`,
+ error: "Not Found",
+ });
+ });
+
+ test("GET /tickets/:id existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/tickets"}/${existingId}`)
+ .expect(HttpStatus.OK)
+ .expect({
+ ...FIND_ONE_RESULT,
+ createdAt: FIND_ONE_RESULT.createdAt.toISOString(),
+ dateClosed: FIND_ONE_RESULT.dateClosed.toISOString(),
+ dateCreated: FIND_ONE_RESULT.dateCreated.toISOString(),
+ updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("POST /tickets existing resource", async () => {
+ const agent = request(app.getHttpServer());
+ await agent
+ .post("/tickets")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ dateClosed: CREATE_RESULT.dateClosed.toISOString(),
+ dateCreated: CREATE_RESULT.dateCreated.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ })
+ .then(function () {
+ agent
+ .post("/tickets")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CONFLICT)
+ .expect({
+ statusCode: HttpStatus.CONFLICT,
+ });
+ });
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.controller.base.ts
new file mode 100644
index 0000000..33696bc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.controller.base.ts
@@ -0,0 +1,253 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import * as nestAccessControl from "nest-access-control";
+import * as defaultAuthGuard from "../../auth/defaultAuth.guard";
+import { TicketService } from "../ticket.service";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { TicketCreateInput } from "./TicketCreateInput";
+import { Ticket } from "./Ticket";
+import { TicketFindManyArgs } from "./TicketFindManyArgs";
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+import { TicketUpdateInput } from "./TicketUpdateInput";
+
+@swagger.ApiBearerAuth()
+@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard)
+export class TicketControllerBase {
+ constructor(
+ protected readonly service: TicketService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Ticket })
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "create",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async createTicket(@common.Body() data: TicketCreateInput): Promise {
+ return await this.service.createTicket({
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Ticket] })
+ @ApiNestedQuery(TicketFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "read",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async tickets(@common.Req() request: Request): Promise {
+ const args = plainToClass(TicketFindManyArgs, request.query);
+ return this.service.tickets({
+ ...args,
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Ticket })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "read",
+ possession: "own",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async ticket(
+ @common.Param() params: TicketWhereUniqueInput
+ ): Promise {
+ const result = await this.service.ticket({
+ where: params,
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Ticket })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "update",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async updateTicket(
+ @common.Param() params: TicketWhereUniqueInput,
+ @common.Body() data: TicketUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateTicket({
+ where: params,
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Ticket })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "delete",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async deleteTicket(
+ @common.Param() params: TicketWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteTicket({
+ where: params,
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.grpc.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.grpc.controller.base.ts
new file mode 100644
index 0000000..ad176c6
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.grpc.controller.base.ts
@@ -0,0 +1,207 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import { GrpcMethod } from "@nestjs/microservices";
+import { TicketService } from "../ticket.service";
+import { TicketCreateInput } from "./TicketCreateInput";
+import { TicketWhereInput } from "./TicketWhereInput";
+import { TicketWhereUniqueInput } from "./TicketWhereUniqueInput";
+import { TicketFindManyArgs } from "./TicketFindManyArgs";
+import { TicketUpdateInput } from "./TicketUpdateInput";
+import { Ticket } from "./Ticket";
+
+export class TicketGrpcControllerBase {
+ constructor(protected readonly service: TicketService) {}
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: Ticket })
+ @GrpcMethod("TicketService", "createTicket")
+ async createTicket(@common.Body() data: TicketCreateInput): Promise {
+ return await this.service.createTicket({
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [Ticket] })
+ @ApiNestedQuery(TicketFindManyArgs)
+ @GrpcMethod("TicketService", "tickets")
+ async tickets(@common.Req() request: Request): Promise {
+ const args = plainToClass(TicketFindManyArgs, request.query);
+ return this.service.tickets({
+ ...args,
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ }
+
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: Ticket })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("TicketService", "ticket")
+ async ticket(
+ @common.Param() params: TicketWhereUniqueInput
+ ): Promise {
+ const result = await this.service.ticket({
+ where: params,
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: Ticket })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("TicketService", "updateTicket")
+ async updateTicket(
+ @common.Param() params: TicketWhereUniqueInput,
+ @common.Body() data: TicketUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateTicket({
+ where: params,
+ data: {
+ ...data,
+
+ user: data.user
+ ? {
+ connect: data.user,
+ }
+ : undefined,
+ },
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: Ticket })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @GrpcMethod("TicketService", "deleteTicket")
+ async deleteTicket(
+ @common.Param() params: TicketWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteTicket({
+ where: params,
+ select: {
+ createdAt: true,
+ dateClosed: true,
+ dateCreated: true,
+ id: true,
+ issue: true,
+ priority: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.module.base.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.module.base.ts
new file mode 100644
index 0000000..f62bfb4
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.module.base.ts
@@ -0,0 +1,18 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { Module } from "@nestjs/common";
+import { ACLModule } from "../../auth/acl.module";
+@Module({
+ imports: [ACLModule],
+ exports: [ACLModule],
+})
+export class TicketModuleBase {}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.resolver.base.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.resolver.base.ts
new file mode 100644
index 0000000..8b36055
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.resolver.base.ts
@@ -0,0 +1,176 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as graphql from "@nestjs/graphql";
+import { GraphQLError } from "graphql";
+import { isRecordNotFoundError } from "../../prisma.util";
+import { MetaQueryPayload } from "../../util/MetaQueryPayload";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { Ticket } from "./Ticket";
+import { TicketCountArgs } from "./TicketCountArgs";
+import { TicketFindManyArgs } from "./TicketFindManyArgs";
+import { TicketFindUniqueArgs } from "./TicketFindUniqueArgs";
+import { CreateTicketArgs } from "./CreateTicketArgs";
+import { UpdateTicketArgs } from "./UpdateTicketArgs";
+import { DeleteTicketArgs } from "./DeleteTicketArgs";
+import { User } from "../../user/base/User";
+import { TicketService } from "../ticket.service";
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Ticket)
+export class TicketResolverBase {
+ constructor(
+ protected readonly service: TicketService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+
+ @graphql.Query(() => MetaQueryPayload)
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "read",
+ possession: "any",
+ })
+ async _ticketsMeta(
+ @graphql.Args() args: TicketCountArgs
+ ): Promise {
+ const result = await this.service.count(args);
+ return {
+ count: result,
+ };
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => [Ticket])
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "read",
+ possession: "any",
+ })
+ async tickets(@graphql.Args() args: TicketFindManyArgs): Promise {
+ return this.service.tickets(args);
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.Query(() => Ticket, { nullable: true })
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "read",
+ possession: "own",
+ })
+ async ticket(
+ @graphql.Args() args: TicketFindUniqueArgs
+ ): Promise {
+ const result = await this.service.ticket(args);
+ if (result === null) {
+ return null;
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Ticket)
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "create",
+ possession: "any",
+ })
+ async createTicket(@graphql.Args() args: CreateTicketArgs): Promise {
+ return await this.service.createTicket({
+ ...args,
+ data: {
+ ...args.data,
+
+ user: args.data.user
+ ? {
+ connect: args.data.user,
+ }
+ : undefined,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @graphql.Mutation(() => Ticket)
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "update",
+ possession: "any",
+ })
+ async updateTicket(
+ @graphql.Args() args: UpdateTicketArgs
+ ): Promise {
+ try {
+ return await this.service.updateTicket({
+ ...args,
+ data: {
+ ...args.data,
+
+ user: args.data.user
+ ? {
+ connect: args.data.user,
+ }
+ : undefined,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @graphql.Mutation(() => Ticket)
+ @nestAccessControl.UseRoles({
+ resource: "Ticket",
+ action: "delete",
+ possession: "any",
+ })
+ async deleteTicket(
+ @graphql.Args() args: DeleteTicketArgs
+ ): Promise {
+ try {
+ return await this.service.deleteTicket(args);
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new GraphQLError(
+ `No resource was found for ${JSON.stringify(args.where)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @graphql.ResolveField(() => User, {
+ nullable: true,
+ name: "user",
+ })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "read",
+ possession: "any",
+ })
+ async getUser(@graphql.Parent() parent: Ticket): Promise {
+ const result = await this.service.getUser(parent.id);
+
+ if (!result) {
+ return null;
+ }
+ return result;
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.service.base.ts b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.service.base.ts
new file mode 100644
index 0000000..e88e0b0
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/base/ticket.service.base.ts
@@ -0,0 +1,51 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { PrismaService } from "../../prisma/prisma.service";
+import {
+ Prisma,
+ Ticket as PrismaTicket,
+ User as PrismaUser,
+} from "@prisma/client";
+
+export class TicketServiceBase {
+ constructor(protected readonly prisma: PrismaService) {}
+
+ async count(args: Omit): Promise {
+ return this.prisma.ticket.count(args);
+ }
+
+ async tickets(args: Prisma.TicketFindManyArgs): Promise {
+ return this.prisma.ticket.findMany(args);
+ }
+ async ticket(
+ args: Prisma.TicketFindUniqueArgs
+ ): Promise {
+ return this.prisma.ticket.findUnique(args);
+ }
+ async createTicket(args: Prisma.TicketCreateArgs): Promise {
+ return this.prisma.ticket.create(args);
+ }
+ async updateTicket(args: Prisma.TicketUpdateArgs): Promise {
+ return this.prisma.ticket.update(args);
+ }
+ async deleteTicket(args: Prisma.TicketDeleteArgs): Promise {
+ return this.prisma.ticket.delete(args);
+ }
+
+ async getUser(parentId: string): Promise {
+ return this.prisma.ticket
+ .findUnique({
+ where: { id: parentId },
+ })
+ .user();
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/ticket.controller.ts b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.controller.ts
new file mode 100644
index 0000000..f066d60
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.controller.ts
@@ -0,0 +1,17 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import * as nestAccessControl from "nest-access-control";
+import { TicketService } from "./ticket.service";
+import { TicketControllerBase } from "./base/ticket.controller.base";
+
+@swagger.ApiTags("tickets")
+@common.Controller("tickets")
+export class TicketController extends TicketControllerBase {
+ constructor(
+ protected readonly service: TicketService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/ticket.grpc.controller.ts b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.grpc.controller.ts
new file mode 100644
index 0000000..bd49344
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.grpc.controller.ts
@@ -0,0 +1,12 @@
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { TicketService } from "./ticket.service";
+import { TicketGrpcControllerBase } from "./base/ticket.grpc.controller.base";
+
+@swagger.ApiTags("tickets")
+@common.Controller("tickets")
+export class TicketGrpcController extends TicketGrpcControllerBase {
+ constructor(protected readonly service: TicketService) {
+ super(service);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/ticket.module.ts b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.module.ts
new file mode 100644
index 0000000..161d917
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.module.ts
@@ -0,0 +1,15 @@
+import { Module, forwardRef } from "@nestjs/common";
+import { AuthModule } from "../auth/auth.module";
+import { TicketModuleBase } from "./base/ticket.module.base";
+import { TicketService } from "./ticket.service";
+import { TicketController } from "./ticket.controller";
+import { TicketGrpcController } from "./ticket.grpc.controller";
+import { TicketResolver } from "./ticket.resolver";
+
+@Module({
+ imports: [TicketModuleBase, forwardRef(() => AuthModule)],
+ controllers: [TicketController, TicketGrpcController],
+ providers: [TicketService, TicketResolver],
+ exports: [TicketService],
+})
+export class TicketModule {}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/ticket.proto b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.proto
new file mode 100644
index 0000000..ee709ef
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+ package ticket;
+service TicketService {
+ rpc createTicket (TicketCreateInput) returns (Ticket) {}
+rpc tickets (findManyParams) returns (stream Ticket) {}
+rpc ticket (TicketWhereUniqueInput) returns (Ticket) {}
+rpc updateTicket (TicketUpdateInput) returns (Ticket) {}
+rpc deleteTicket (TicketWhereUniqueInput) returns (Ticket) {}
+ }
+message TicketCreateInput {
+string createdAt = 1;
+string dateClosed = 2;
+string dateCreated = 3;
+string id = 4;
+string issue = 5;
+repeated string priority = 6;
+repeated string status = 7;
+string updatedAt = 8;
+};
+message Ticket {
+string createdAt = 1;
+string dateClosed = 2;
+string dateCreated = 3;
+string id = 4;
+string issue = 5;
+repeated string priority = 6;
+repeated string status = 7;
+string updatedAt = 8;
+};
+message TicketWhereUniqueInput {
+string createdAt = 1;
+string dateClosed = 2;
+string dateCreated = 3;
+string id = 4;
+string issue = 5;
+repeated string priority = 6;
+repeated string status = 7;
+string updatedAt = 8;
+};
+message TicketUpdateInput {
+string createdAt = 1;
+string dateClosed = 2;
+string dateCreated = 3;
+string id = 4;
+string issue = 5;
+repeated string priority = 6;
+repeated string status = 7;
+string updatedAt = 8;
+};
+message findManyParams {
+
+};
\ No newline at end of file
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/ticket.resolver.ts b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.resolver.ts
new file mode 100644
index 0000000..242dc54
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.resolver.ts
@@ -0,0 +1,20 @@
+import * as graphql from "@nestjs/graphql";
+import * as nestAccessControl from "nest-access-control";
+import * as gqlACGuard from "../auth/gqlAC.guard";
+import { GqlDefaultAuthGuard } from "../auth/gqlDefaultAuth.guard";
+import * as common from "@nestjs/common";
+import { TicketResolverBase } from "./base/ticket.resolver.base";
+import { Ticket } from "./base/Ticket";
+import { TicketService } from "./ticket.service";
+
+@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard)
+@graphql.Resolver(() => Ticket)
+export class TicketResolver extends TicketResolverBase {
+ constructor(
+ protected readonly service: TicketService,
+ @nestAccessControl.InjectRolesBuilder()
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {
+ super(service, rolesBuilder);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/ticket/ticket.service.ts b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.service.ts
new file mode 100644
index 0000000..64f7085
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/ticket/ticket.service.ts
@@ -0,0 +1,10 @@
+import { Injectable } from "@nestjs/common";
+import { PrismaService } from "../prisma/prisma.service";
+import { TicketServiceBase } from "./base/ticket.service.base";
+
+@Injectable()
+export class TicketService extends TicketServiceBase {
+ constructor(protected readonly prisma: PrismaService) {
+ super(prisma);
+ }
+}
diff --git a/apps/vesst-discord-bot-backend-server/src/types.ts b/apps/vesst-discord-bot-backend-server/src/types.ts
new file mode 100644
index 0000000..f762a5d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/types.ts
@@ -0,0 +1,3 @@
+import type { JsonValue } from "type-fest";
+
+export type InputJsonValue = Omit;
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/CreateUserArgs.ts b/apps/vesst-discord-bot-backend-server/src/user/base/CreateUserArgs.ts
new file mode 100644
index 0000000..092a504
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/CreateUserArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserCreateInput } from "./UserCreateInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class CreateUserArgs {
+ @ApiProperty({
+ required: true,
+ type: () => UserCreateInput,
+ })
+ @ValidateNested()
+ @Type(() => UserCreateInput)
+ @Field(() => UserCreateInput, { nullable: false })
+ data!: UserCreateInput;
+}
+
+export { CreateUserArgs as CreateUserArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/DeleteUserArgs.ts b/apps/vesst-discord-bot-backend-server/src/user/base/DeleteUserArgs.ts
new file mode 100644
index 0000000..042ed5f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/DeleteUserArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class DeleteUserArgs {
+ @ApiProperty({
+ required: true,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @Field(() => UserWhereUniqueInput, { nullable: false })
+ where!: UserWhereUniqueInput;
+}
+
+export { DeleteUserArgs as DeleteUserArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/SecurityCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/SecurityCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..fb5c350
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/SecurityCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { SecurityWhereUniqueInput } from "../../security/base/SecurityWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class SecurityCreateNestedManyWithoutUsersInput {
+ @Field(() => [SecurityWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SecurityWhereUniqueInput],
+ })
+ connect?: Array;
+}
+
+export { SecurityCreateNestedManyWithoutUsersInput as SecurityCreateNestedManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/SecurityUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/SecurityUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..50490a1
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/SecurityUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,46 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { SecurityWhereUniqueInput } from "../../security/base/SecurityWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class SecurityUpdateManyWithoutUsersInput {
+ @Field(() => [SecurityWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SecurityWhereUniqueInput],
+ })
+ connect?: Array;
+
+ @Field(() => [SecurityWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SecurityWhereUniqueInput],
+ })
+ disconnect?: Array;
+
+ @Field(() => [SecurityWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SecurityWhereUniqueInput],
+ })
+ set?: Array;
+}
+
+export { SecurityUpdateManyWithoutUsersInput as SecurityUpdateManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/SlotCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/SlotCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..a685eb3
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/SlotCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { SlotWhereUniqueInput } from "../../slot/base/SlotWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class SlotCreateNestedManyWithoutUsersInput {
+ @Field(() => [SlotWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SlotWhereUniqueInput],
+ })
+ connect?: Array;
+}
+
+export { SlotCreateNestedManyWithoutUsersInput as SlotCreateNestedManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/SlotUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/SlotUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..e9f375a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/SlotUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,46 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { SlotWhereUniqueInput } from "../../slot/base/SlotWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class SlotUpdateManyWithoutUsersInput {
+ @Field(() => [SlotWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SlotWhereUniqueInput],
+ })
+ connect?: Array;
+
+ @Field(() => [SlotWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SlotWhereUniqueInput],
+ })
+ disconnect?: Array;
+
+ @Field(() => [SlotWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [SlotWhereUniqueInput],
+ })
+ set?: Array;
+}
+
+export { SlotUpdateManyWithoutUsersInput as SlotUpdateManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/TicketCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/TicketCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..6f2d93f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/TicketCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { TicketWhereUniqueInput } from "../../ticket/base/TicketWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class TicketCreateNestedManyWithoutUsersInput {
+ @Field(() => [TicketWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [TicketWhereUniqueInput],
+ })
+ connect?: Array;
+}
+
+export { TicketCreateNestedManyWithoutUsersInput as TicketCreateNestedManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/TicketUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/TicketUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..6c2f99d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/TicketUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,46 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { TicketWhereUniqueInput } from "../../ticket/base/TicketWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class TicketUpdateManyWithoutUsersInput {
+ @Field(() => [TicketWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [TicketWhereUniqueInput],
+ })
+ connect?: Array;
+
+ @Field(() => [TicketWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [TicketWhereUniqueInput],
+ })
+ disconnect?: Array;
+
+ @Field(() => [TicketWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [TicketWhereUniqueInput],
+ })
+ set?: Array;
+}
+
+export { TicketUpdateManyWithoutUsersInput as TicketUpdateManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UpdateUserArgs.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UpdateUserArgs.ts
new file mode 100644
index 0000000..1f13420
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UpdateUserArgs.ts
@@ -0,0 +1,40 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+import { UserUpdateInput } from "./UserUpdateInput";
+
+@ArgsType()
+class UpdateUserArgs {
+ @ApiProperty({
+ required: true,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @Field(() => UserWhereUniqueInput, { nullable: false })
+ where!: UserWhereUniqueInput;
+
+ @ApiProperty({
+ required: true,
+ type: () => UserUpdateInput,
+ })
+ @ValidateNested()
+ @Type(() => UserUpdateInput)
+ @Field(() => UserUpdateInput, { nullable: false })
+ data!: UserUpdateInput;
+}
+
+export { UpdateUserArgs as UpdateUserArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/User.ts b/apps/vesst-discord-bot-backend-server/src/user/base/User.ts
new file mode 100644
index 0000000..205ed2a
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/User.ts
@@ -0,0 +1,171 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ObjectType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsDate,
+ IsString,
+ MaxLength,
+ IsOptional,
+ IsInt,
+ Min,
+ Max,
+ ValidateNested,
+} from "class-validator";
+import { Type } from "class-transformer";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { JsonValue } from "type-fest";
+import { Security } from "../../security/base/Security";
+import { Slot } from "../../slot/base/Slot";
+import { Ticket } from "../../ticket/base/Ticket";
+import { Vouch } from "../../vouch/base/Vouch";
+
+@ObjectType()
+class User {
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ createdAt!: Date;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ discordId!: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ email!: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(256)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ firstName!: string | null;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(256)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ lastName!: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsInt()
+ @Min(-999999999)
+ @Max(999999999)
+ @IsOptional()
+ @Field(() => Number, {
+ nullable: true,
+ })
+ reputation!: number | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsJSONValue()
+ @Field(() => GraphQLJSON)
+ roles!: JsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: () => [Security],
+ })
+ @ValidateNested()
+ @Type(() => Security)
+ @IsOptional()
+ securities?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: () => [Slot],
+ })
+ @ValidateNested()
+ @Type(() => Slot)
+ @IsOptional()
+ slots?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: () => [Ticket],
+ })
+ @ValidateNested()
+ @Type(() => Ticket)
+ @IsOptional()
+ tickets?: Array;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsDate()
+ @Type(() => Date)
+ @Field(() => Date)
+ updatedAt!: Date;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ username!: string;
+
+ @ApiProperty({
+ required: false,
+ type: () => [Vouch],
+ })
+ @ValidateNested()
+ @Type(() => Vouch)
+ @IsOptional()
+ vouches?: Array;
+}
+
+export { User as User };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserCountArgs.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserCountArgs.ts
new file mode 100644
index 0000000..f4a14ac
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserCountArgs.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserWhereInput } from "./UserWhereInput";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class UserCountArgs {
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereInput,
+ })
+ @Field(() => UserWhereInput, { nullable: true })
+ @Type(() => UserWhereInput)
+ where?: UserWhereInput;
+}
+
+export { UserCountArgs as UserCountArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserCreateInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserCreateInput.ts
new file mode 100644
index 0000000..3d7b775
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserCreateInput.ts
@@ -0,0 +1,166 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsString,
+ MaxLength,
+ IsOptional,
+ IsInt,
+ Min,
+ Max,
+ ValidateNested,
+} from "class-validator";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { InputJsonValue } from "../../types";
+import { SecurityCreateNestedManyWithoutUsersInput } from "./SecurityCreateNestedManyWithoutUsersInput";
+import { Type } from "class-transformer";
+import { SlotCreateNestedManyWithoutUsersInput } from "./SlotCreateNestedManyWithoutUsersInput";
+import { TicketCreateNestedManyWithoutUsersInput } from "./TicketCreateNestedManyWithoutUsersInput";
+import { VouchCreateNestedManyWithoutUsersInput } from "./VouchCreateNestedManyWithoutUsersInput";
+
+@InputType()
+class UserCreateInput {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ discordId?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ email?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(256)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ firstName?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(256)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ lastName?: string | null;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ password!: string;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsInt()
+ @Min(-999999999)
+ @Max(999999999)
+ @IsOptional()
+ @Field(() => Number, {
+ nullable: true,
+ })
+ reputation?: number | null;
+
+ @ApiProperty({
+ required: true,
+ })
+ @IsJSONValue()
+ @Field(() => GraphQLJSON)
+ roles!: InputJsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: () => SecurityCreateNestedManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityCreateNestedManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => SecurityCreateNestedManyWithoutUsersInput, {
+ nullable: true,
+ })
+ securities?: SecurityCreateNestedManyWithoutUsersInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => SlotCreateNestedManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotCreateNestedManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => SlotCreateNestedManyWithoutUsersInput, {
+ nullable: true,
+ })
+ slots?: SlotCreateNestedManyWithoutUsersInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => TicketCreateNestedManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketCreateNestedManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => TicketCreateNestedManyWithoutUsersInput, {
+ nullable: true,
+ })
+ tickets?: TicketCreateNestedManyWithoutUsersInput;
+
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ username!: string;
+
+ @ApiProperty({
+ required: false,
+ type: () => VouchCreateNestedManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => VouchCreateNestedManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => VouchCreateNestedManyWithoutUsersInput, {
+ nullable: true,
+ })
+ vouches?: VouchCreateNestedManyWithoutUsersInput;
+}
+
+export { UserCreateInput as UserCreateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserFindManyArgs.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserFindManyArgs.ts
new file mode 100644
index 0000000..8ba369c
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserFindManyArgs.ts
@@ -0,0 +1,62 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserWhereInput } from "./UserWhereInput";
+import { IsOptional, ValidateNested, IsInt } from "class-validator";
+import { Type } from "class-transformer";
+import { UserOrderByInput } from "./UserOrderByInput";
+
+@ArgsType()
+class UserFindManyArgs {
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereInput,
+ })
+ @IsOptional()
+ @ValidateNested()
+ @Field(() => UserWhereInput, { nullable: true })
+ @Type(() => UserWhereInput)
+ where?: UserWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: [UserOrderByInput],
+ })
+ @IsOptional()
+ @ValidateNested({ each: true })
+ @Field(() => [UserOrderByInput], { nullable: true })
+ @Type(() => UserOrderByInput)
+ orderBy?: Array;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ skip?: number;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsOptional()
+ @IsInt()
+ @Field(() => Number, { nullable: true })
+ @Type(() => Number)
+ take?: number;
+}
+
+export { UserFindManyArgs as UserFindManyArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserFindUniqueArgs.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserFindUniqueArgs.ts
new file mode 100644
index 0000000..c64506f
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserFindUniqueArgs.ts
@@ -0,0 +1,30 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { ArgsType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+import { ValidateNested } from "class-validator";
+import { Type } from "class-transformer";
+
+@ArgsType()
+class UserFindUniqueArgs {
+ @ApiProperty({
+ required: true,
+ type: () => UserWhereUniqueInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereUniqueInput)
+ @Field(() => UserWhereUniqueInput, { nullable: false })
+ where!: UserWhereUniqueInput;
+}
+
+export { UserFindUniqueArgs as UserFindUniqueArgs };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserListRelationFilter.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserListRelationFilter.ts
new file mode 100644
index 0000000..0ff7d94
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserListRelationFilter.ts
@@ -0,0 +1,56 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { UserWhereInput } from "./UserWhereInput";
+import { ValidateNested, IsOptional } from "class-validator";
+import { Type } from "class-transformer";
+
+@InputType()
+class UserListRelationFilter {
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereInput)
+ @IsOptional()
+ @Field(() => UserWhereInput, {
+ nullable: true,
+ })
+ every?: UserWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereInput)
+ @IsOptional()
+ @Field(() => UserWhereInput, {
+ nullable: true,
+ })
+ some?: UserWhereInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => UserWhereInput,
+ })
+ @ValidateNested()
+ @Type(() => UserWhereInput)
+ @IsOptional()
+ @Field(() => UserWhereInput, {
+ nullable: true,
+ })
+ none?: UserWhereInput;
+}
+export { UserListRelationFilter as UserListRelationFilter };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserOrderByInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserOrderByInput.ts
new file mode 100644
index 0000000..e0acccc
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserOrderByInput.ts
@@ -0,0 +1,144 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsOptional, IsEnum } from "class-validator";
+import { SortOrder } from "../../util/SortOrder";
+
+@InputType({
+ isAbstract: true,
+ description: undefined,
+})
+class UserOrderByInput {
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ createdAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ discordId?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ email?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ firstName?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ id?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ lastName?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ password?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ reputation?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ roles?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ updatedAt?: SortOrder;
+
+ @ApiProperty({
+ required: false,
+ enum: ["asc", "desc"],
+ })
+ @IsOptional()
+ @IsEnum(SortOrder)
+ @Field(() => SortOrder, {
+ nullable: true,
+ })
+ username?: SortOrder;
+}
+
+export { UserOrderByInput as UserOrderByInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserUpdateInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserUpdateInput.ts
new file mode 100644
index 0000000..69191c2
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserUpdateInput.ts
@@ -0,0 +1,175 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import {
+ IsString,
+ MaxLength,
+ IsOptional,
+ IsInt,
+ Min,
+ Max,
+ ValidateNested,
+} from "class-validator";
+import { IsJSONValue } from "../../validators";
+import { GraphQLJSON } from "graphql-type-json";
+import { InputJsonValue } from "../../types";
+import { SecurityUpdateManyWithoutUsersInput } from "./SecurityUpdateManyWithoutUsersInput";
+import { Type } from "class-transformer";
+import { SlotUpdateManyWithoutUsersInput } from "./SlotUpdateManyWithoutUsersInput";
+import { TicketUpdateManyWithoutUsersInput } from "./TicketUpdateManyWithoutUsersInput";
+import { VouchUpdateManyWithoutUsersInput } from "./VouchUpdateManyWithoutUsersInput";
+
+@InputType()
+class UserUpdateInput {
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(1000)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ discordId?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ email?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(256)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ firstName?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @MaxLength(256)
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ lastName?: string | null;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ password?: string;
+
+ @ApiProperty({
+ required: false,
+ type: Number,
+ })
+ @IsInt()
+ @Min(-999999999)
+ @Max(999999999)
+ @IsOptional()
+ @Field(() => Number, {
+ nullable: true,
+ })
+ reputation?: number | null;
+
+ @ApiProperty({
+ required: false,
+ })
+ @IsJSONValue()
+ @IsOptional()
+ @Field(() => GraphQLJSON, {
+ nullable: true,
+ })
+ roles?: InputJsonValue;
+
+ @ApiProperty({
+ required: false,
+ type: () => SecurityUpdateManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => SecurityUpdateManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => SecurityUpdateManyWithoutUsersInput, {
+ nullable: true,
+ })
+ securities?: SecurityUpdateManyWithoutUsersInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => SlotUpdateManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => SlotUpdateManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => SlotUpdateManyWithoutUsersInput, {
+ nullable: true,
+ })
+ slots?: SlotUpdateManyWithoutUsersInput;
+
+ @ApiProperty({
+ required: false,
+ type: () => TicketUpdateManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => TicketUpdateManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => TicketUpdateManyWithoutUsersInput, {
+ nullable: true,
+ })
+ tickets?: TicketUpdateManyWithoutUsersInput;
+
+ @ApiProperty({
+ required: false,
+ type: String,
+ })
+ @IsString()
+ @IsOptional()
+ @Field(() => String, {
+ nullable: true,
+ })
+ username?: string;
+
+ @ApiProperty({
+ required: false,
+ type: () => VouchUpdateManyWithoutUsersInput,
+ })
+ @ValidateNested()
+ @Type(() => VouchUpdateManyWithoutUsersInput)
+ @IsOptional()
+ @Field(() => VouchUpdateManyWithoutUsersInput, {
+ nullable: true,
+ })
+ vouches?: VouchUpdateManyWithoutUsersInput;
+}
+
+export { UserUpdateInput as UserUpdateInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserWhereInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserWhereInput.ts
new file mode 100644
index 0000000..402f5cf
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserWhereInput.ts
@@ -0,0 +1,152 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { StringNullableFilter } from "../../util/StringNullableFilter";
+import { Type } from "class-transformer";
+import { IsOptional, ValidateNested } from "class-validator";
+import { StringFilter } from "../../util/StringFilter";
+import { IntNullableFilter } from "../../util/IntNullableFilter";
+import { SecurityListRelationFilter } from "../../security/base/SecurityListRelationFilter";
+import { SlotListRelationFilter } from "../../slot/base/SlotListRelationFilter";
+import { TicketListRelationFilter } from "../../ticket/base/TicketListRelationFilter";
+import { VouchListRelationFilter } from "../../vouch/base/VouchListRelationFilter";
+
+@InputType()
+class UserWhereInput {
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ discordId?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ email?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ firstName?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ id?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringNullableFilter,
+ })
+ @Type(() => StringNullableFilter)
+ @IsOptional()
+ @Field(() => StringNullableFilter, {
+ nullable: true,
+ })
+ lastName?: StringNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: IntNullableFilter,
+ })
+ @Type(() => IntNullableFilter)
+ @IsOptional()
+ @Field(() => IntNullableFilter, {
+ nullable: true,
+ })
+ reputation?: IntNullableFilter;
+
+ @ApiProperty({
+ required: false,
+ type: () => SecurityListRelationFilter,
+ })
+ @ValidateNested()
+ @Type(() => SecurityListRelationFilter)
+ @IsOptional()
+ @Field(() => SecurityListRelationFilter, {
+ nullable: true,
+ })
+ securities?: SecurityListRelationFilter;
+
+ @ApiProperty({
+ required: false,
+ type: () => SlotListRelationFilter,
+ })
+ @ValidateNested()
+ @Type(() => SlotListRelationFilter)
+ @IsOptional()
+ @Field(() => SlotListRelationFilter, {
+ nullable: true,
+ })
+ slots?: SlotListRelationFilter;
+
+ @ApiProperty({
+ required: false,
+ type: () => TicketListRelationFilter,
+ })
+ @ValidateNested()
+ @Type(() => TicketListRelationFilter)
+ @IsOptional()
+ @Field(() => TicketListRelationFilter, {
+ nullable: true,
+ })
+ tickets?: TicketListRelationFilter;
+
+ @ApiProperty({
+ required: false,
+ type: StringFilter,
+ })
+ @Type(() => StringFilter)
+ @IsOptional()
+ @Field(() => StringFilter, {
+ nullable: true,
+ })
+ username?: StringFilter;
+
+ @ApiProperty({
+ required: false,
+ type: () => VouchListRelationFilter,
+ })
+ @ValidateNested()
+ @Type(() => VouchListRelationFilter)
+ @IsOptional()
+ @Field(() => VouchListRelationFilter, {
+ nullable: true,
+ })
+ vouches?: VouchListRelationFilter;
+}
+
+export { UserWhereInput as UserWhereInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/UserWhereUniqueInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/UserWhereUniqueInput.ts
new file mode 100644
index 0000000..0bcea12
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/UserWhereUniqueInput.ts
@@ -0,0 +1,27 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { ApiProperty } from "@nestjs/swagger";
+import { IsString } from "class-validator";
+
+@InputType()
+class UserWhereUniqueInput {
+ @ApiProperty({
+ required: true,
+ type: String,
+ })
+ @IsString()
+ @Field(() => String)
+ id!: string;
+}
+
+export { UserWhereUniqueInput as UserWhereUniqueInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/VouchCreateNestedManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/VouchCreateNestedManyWithoutUsersInput.ts
new file mode 100644
index 0000000..baebc87
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/VouchCreateNestedManyWithoutUsersInput.ts
@@ -0,0 +1,28 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { VouchWhereUniqueInput } from "../../vouch/base/VouchWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class VouchCreateNestedManyWithoutUsersInput {
+ @Field(() => [VouchWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [VouchWhereUniqueInput],
+ })
+ connect?: Array;
+}
+
+export { VouchCreateNestedManyWithoutUsersInput as VouchCreateNestedManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/VouchUpdateManyWithoutUsersInput.ts b/apps/vesst-discord-bot-backend-server/src/user/base/VouchUpdateManyWithoutUsersInput.ts
new file mode 100644
index 0000000..5b9c02d
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/VouchUpdateManyWithoutUsersInput.ts
@@ -0,0 +1,46 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import { InputType, Field } from "@nestjs/graphql";
+import { VouchWhereUniqueInput } from "../../vouch/base/VouchWhereUniqueInput";
+import { ApiProperty } from "@nestjs/swagger";
+
+@InputType()
+class VouchUpdateManyWithoutUsersInput {
+ @Field(() => [VouchWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [VouchWhereUniqueInput],
+ })
+ connect?: Array;
+
+ @Field(() => [VouchWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [VouchWhereUniqueInput],
+ })
+ disconnect?: Array;
+
+ @Field(() => [VouchWhereUniqueInput], {
+ nullable: true,
+ })
+ @ApiProperty({
+ required: false,
+ type: () => [VouchWhereUniqueInput],
+ })
+ set?: Array;
+}
+
+export { VouchUpdateManyWithoutUsersInput as VouchUpdateManyWithoutUsersInput };
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/user.controller.base.spec.ts b/apps/vesst-discord-bot-backend-server/src/user/base/user.controller.base.spec.ts
new file mode 100644
index 0000000..a799bad
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/user.controller.base.spec.ts
@@ -0,0 +1,218 @@
+import { Test } from "@nestjs/testing";
+import {
+ INestApplication,
+ HttpStatus,
+ ExecutionContext,
+ CallHandler,
+} from "@nestjs/common";
+import request from "supertest";
+import { ACGuard } from "nest-access-control";
+import { DefaultAuthGuard } from "../../auth/defaultAuth.guard";
+import { ACLModule } from "../../auth/acl.module";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { map } from "rxjs";
+import { UserController } from "../user.controller";
+import { UserService } from "../user.service";
+
+const nonExistingId = "nonExistingId";
+const existingId = "existingId";
+const CREATE_INPUT = {
+ createdAt: new Date(),
+ discordId: "exampleDiscordId",
+ email: "exampleEmail",
+ firstName: "exampleFirstName",
+ id: "exampleId",
+ lastName: "exampleLastName",
+ password: "examplePassword",
+ reputation: 42,
+ updatedAt: new Date(),
+ username: "exampleUsername",
+};
+const CREATE_RESULT = {
+ createdAt: new Date(),
+ discordId: "exampleDiscordId",
+ email: "exampleEmail",
+ firstName: "exampleFirstName",
+ id: "exampleId",
+ lastName: "exampleLastName",
+ password: "examplePassword",
+ reputation: 42,
+ updatedAt: new Date(),
+ username: "exampleUsername",
+};
+const FIND_MANY_RESULT = [
+ {
+ createdAt: new Date(),
+ discordId: "exampleDiscordId",
+ email: "exampleEmail",
+ firstName: "exampleFirstName",
+ id: "exampleId",
+ lastName: "exampleLastName",
+ password: "examplePassword",
+ reputation: 42,
+ updatedAt: new Date(),
+ username: "exampleUsername",
+ },
+];
+const FIND_ONE_RESULT = {
+ createdAt: new Date(),
+ discordId: "exampleDiscordId",
+ email: "exampleEmail",
+ firstName: "exampleFirstName",
+ id: "exampleId",
+ lastName: "exampleLastName",
+ password: "examplePassword",
+ reputation: 42,
+ updatedAt: new Date(),
+ username: "exampleUsername",
+};
+
+const service = {
+ createUser() {
+ return CREATE_RESULT;
+ },
+ users: () => FIND_MANY_RESULT,
+ user: ({ where }: { where: { id: string } }) => {
+ switch (where.id) {
+ case existingId:
+ return FIND_ONE_RESULT;
+ case nonExistingId:
+ return null;
+ }
+ },
+};
+
+const basicAuthGuard = {
+ canActivate: (context: ExecutionContext) => {
+ const argumentHost = context.switchToHttp();
+ const request = argumentHost.getRequest();
+ request.user = {
+ roles: ["user"],
+ };
+ return true;
+ },
+};
+
+const acGuard = {
+ canActivate: () => {
+ return true;
+ },
+};
+
+const aclFilterResponseInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle().pipe(
+ map((data) => {
+ return data;
+ })
+ );
+ },
+};
+const aclValidateRequestInterceptor = {
+ intercept: (context: ExecutionContext, next: CallHandler) => {
+ return next.handle();
+ },
+};
+
+describe("User", () => {
+ let app: INestApplication;
+
+ beforeAll(async () => {
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ {
+ provide: UserService,
+ useValue: service,
+ },
+ ],
+ controllers: [UserController],
+ imports: [ACLModule],
+ })
+ .overrideGuard(DefaultAuthGuard)
+ .useValue(basicAuthGuard)
+ .overrideGuard(ACGuard)
+ .useValue(acGuard)
+ .overrideInterceptor(AclFilterResponseInterceptor)
+ .useValue(aclFilterResponseInterceptor)
+ .overrideInterceptor(AclValidateRequestInterceptor)
+ .useValue(aclValidateRequestInterceptor)
+ .compile();
+
+ app = moduleRef.createNestApplication();
+ await app.init();
+ });
+
+ test("POST /users", async () => {
+ await request(app.getHttpServer())
+ .post("/users")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("GET /users", async () => {
+ await request(app.getHttpServer())
+ .get("/users")
+ .expect(HttpStatus.OK)
+ .expect([
+ {
+ ...FIND_MANY_RESULT[0],
+ createdAt: FIND_MANY_RESULT[0].createdAt.toISOString(),
+ updatedAt: FIND_MANY_RESULT[0].updatedAt.toISOString(),
+ },
+ ]);
+ });
+
+ test("GET /users/:id non existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/users"}/${nonExistingId}`)
+ .expect(HttpStatus.NOT_FOUND)
+ .expect({
+ statusCode: HttpStatus.NOT_FOUND,
+ message: `No resource was found for {"${"id"}":"${nonExistingId}"}`,
+ error: "Not Found",
+ });
+ });
+
+ test("GET /users/:id existing", async () => {
+ await request(app.getHttpServer())
+ .get(`${"/users"}/${existingId}`)
+ .expect(HttpStatus.OK)
+ .expect({
+ ...FIND_ONE_RESULT,
+ createdAt: FIND_ONE_RESULT.createdAt.toISOString(),
+ updatedAt: FIND_ONE_RESULT.updatedAt.toISOString(),
+ });
+ });
+
+ test("POST /users existing resource", async () => {
+ const agent = request(app.getHttpServer());
+ await agent
+ .post("/users")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CREATED)
+ .expect({
+ ...CREATE_RESULT,
+ createdAt: CREATE_RESULT.createdAt.toISOString(),
+ updatedAt: CREATE_RESULT.updatedAt.toISOString(),
+ })
+ .then(function () {
+ agent
+ .post("/users")
+ .send(CREATE_INPUT)
+ .expect(HttpStatus.CONFLICT)
+ .expect({
+ statusCode: HttpStatus.CONFLICT,
+ });
+ });
+ });
+
+ afterAll(async () => {
+ await app.close();
+ });
+});
diff --git a/apps/vesst-discord-bot-backend-server/src/user/base/user.controller.base.ts b/apps/vesst-discord-bot-backend-server/src/user/base/user.controller.base.ts
new file mode 100644
index 0000000..89c9fcb
--- /dev/null
+++ b/apps/vesst-discord-bot-backend-server/src/user/base/user.controller.base.ts
@@ -0,0 +1,651 @@
+/*
+------------------------------------------------------------------------------
+This code was generated by Amplication.
+
+Changes to this file will be lost if the code is regenerated.
+
+There are other ways to to customize your code, see this doc to learn more
+https://docs.amplication.com/how-to/custom-code
+
+------------------------------------------------------------------------------
+ */
+import * as common from "@nestjs/common";
+import * as swagger from "@nestjs/swagger";
+import { isRecordNotFoundError } from "../../prisma.util";
+import * as errors from "../../errors";
+import { Request } from "express";
+import { plainToClass } from "class-transformer";
+import { ApiNestedQuery } from "../../decorators/api-nested-query.decorator";
+import * as nestAccessControl from "nest-access-control";
+import * as defaultAuthGuard from "../../auth/defaultAuth.guard";
+import { UserService } from "../user.service";
+import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor";
+import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor";
+import { UserCreateInput } from "./UserCreateInput";
+import { User } from "./User";
+import { UserFindManyArgs } from "./UserFindManyArgs";
+import { UserWhereUniqueInput } from "./UserWhereUniqueInput";
+import { UserUpdateInput } from "./UserUpdateInput";
+import { SecurityFindManyArgs } from "../../security/base/SecurityFindManyArgs";
+import { Security } from "../../security/base/Security";
+import { SecurityWhereUniqueInput } from "../../security/base/SecurityWhereUniqueInput";
+import { SlotFindManyArgs } from "../../slot/base/SlotFindManyArgs";
+import { Slot } from "../../slot/base/Slot";
+import { SlotWhereUniqueInput } from "../../slot/base/SlotWhereUniqueInput";
+import { TicketFindManyArgs } from "../../ticket/base/TicketFindManyArgs";
+import { Ticket } from "../../ticket/base/Ticket";
+import { TicketWhereUniqueInput } from "../../ticket/base/TicketWhereUniqueInput";
+import { VouchFindManyArgs } from "../../vouch/base/VouchFindManyArgs";
+import { Vouch } from "../../vouch/base/Vouch";
+import { VouchWhereUniqueInput } from "../../vouch/base/VouchWhereUniqueInput";
+
+@swagger.ApiBearerAuth()
+@common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard)
+export class UserControllerBase {
+ constructor(
+ protected readonly service: UserService,
+ protected readonly rolesBuilder: nestAccessControl.RolesBuilder
+ ) {}
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Post()
+ @swagger.ApiCreatedResponse({ type: User })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "create",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async createUser(@common.Body() data: UserCreateInput): Promise {
+ return await this.service.createUser({
+ data: data,
+ select: {
+ createdAt: true,
+ discordId: true,
+ email: true,
+ firstName: true,
+ id: true,
+ lastName: true,
+ reputation: true,
+ roles: true,
+ updatedAt: true,
+ username: true,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get()
+ @swagger.ApiOkResponse({ type: [User] })
+ @ApiNestedQuery(UserFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "read",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async users(@common.Req() request: Request): Promise {
+ const args = plainToClass(UserFindManyArgs, request.query);
+ return this.service.users({
+ ...args,
+ select: {
+ createdAt: true,
+ discordId: true,
+ email: true,
+ firstName: true,
+ id: true,
+ lastName: true,
+ reputation: true,
+ roles: true,
+ updatedAt: true,
+ username: true,
+ },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id")
+ @swagger.ApiOkResponse({ type: User })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "read",
+ possession: "own",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async user(
+ @common.Param() params: UserWhereUniqueInput
+ ): Promise {
+ const result = await this.service.user({
+ where: params,
+ select: {
+ createdAt: true,
+ discordId: true,
+ email: true,
+ firstName: true,
+ id: true,
+ lastName: true,
+ reputation: true,
+ roles: true,
+ updatedAt: true,
+ username: true,
+ },
+ });
+ if (result === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return result;
+ }
+
+ @common.UseInterceptors(AclValidateRequestInterceptor)
+ @common.Patch("/:id")
+ @swagger.ApiOkResponse({ type: User })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "update",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async updateUser(
+ @common.Param() params: UserWhereUniqueInput,
+ @common.Body() data: UserUpdateInput
+ ): Promise {
+ try {
+ return await this.service.updateUser({
+ where: params,
+ data: data,
+ select: {
+ createdAt: true,
+ discordId: true,
+ email: true,
+ firstName: true,
+ id: true,
+ lastName: true,
+ reputation: true,
+ roles: true,
+ updatedAt: true,
+ username: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.Delete("/:id")
+ @swagger.ApiOkResponse({ type: User })
+ @swagger.ApiNotFoundResponse({ type: errors.NotFoundException })
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "delete",
+ possession: "any",
+ })
+ @swagger.ApiForbiddenResponse({
+ type: errors.ForbiddenException,
+ })
+ async deleteUser(
+ @common.Param() params: UserWhereUniqueInput
+ ): Promise {
+ try {
+ return await this.service.deleteUser({
+ where: params,
+ select: {
+ createdAt: true,
+ discordId: true,
+ email: true,
+ firstName: true,
+ id: true,
+ lastName: true,
+ reputation: true,
+ roles: true,
+ updatedAt: true,
+ username: true,
+ },
+ });
+ } catch (error) {
+ if (isRecordNotFoundError(error)) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ throw error;
+ }
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id/securities")
+ @ApiNestedQuery(SecurityFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Security",
+ action: "read",
+ possession: "any",
+ })
+ async findSecurities(
+ @common.Req() request: Request,
+ @common.Param() params: UserWhereUniqueInput
+ ): Promise {
+ const query = plainToClass(SecurityFindManyArgs, request.query);
+ const results = await this.service.findSecurities(params.id, {
+ ...query,
+ select: {
+ action: true,
+ createdAt: true,
+ date: true,
+ id: true,
+ status: true,
+ updatedAt: true,
+
+ user: {
+ select: {
+ id: true,
+ },
+ },
+ },
+ });
+ if (results === null) {
+ throw new errors.NotFoundException(
+ `No resource was found for ${JSON.stringify(params)}`
+ );
+ }
+ return results;
+ }
+
+ @common.Post("/:id/securities")
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "update",
+ possession: "any",
+ })
+ async connectSecurities(
+ @common.Param() params: UserWhereUniqueInput,
+ @common.Body() body: SecurityWhereUniqueInput[]
+ ): Promise {
+ const data = {
+ securities: {
+ connect: body,
+ },
+ };
+ await this.service.updateUser({
+ where: params,
+ data,
+ select: { id: true },
+ });
+ }
+
+ @common.Patch("/:id/securities")
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "update",
+ possession: "any",
+ })
+ async updateSecurities(
+ @common.Param() params: UserWhereUniqueInput,
+ @common.Body() body: SecurityWhereUniqueInput[]
+ ): Promise {
+ const data = {
+ securities: {
+ set: body,
+ },
+ };
+ await this.service.updateUser({
+ where: params,
+ data,
+ select: { id: true },
+ });
+ }
+
+ @common.Delete("/:id/securities")
+ @nestAccessControl.UseRoles({
+ resource: "User",
+ action: "update",
+ possession: "any",
+ })
+ async disconnectSecurities(
+ @common.Param() params: UserWhereUniqueInput,
+ @common.Body() body: SecurityWhereUniqueInput[]
+ ): Promise {
+ const data = {
+ securities: {
+ disconnect: body,
+ },
+ };
+ await this.service.updateUser({
+ where: params,
+ data,
+ select: { id: true },
+ });
+ }
+
+ @common.UseInterceptors(AclFilterResponseInterceptor)
+ @common.Get("/:id/slots")
+ @ApiNestedQuery(SlotFindManyArgs)
+ @nestAccessControl.UseRoles({
+ resource: "Slot",
+ action: "read",
+ possession: "any",
+ })
+ async findSlots(
+ @common.Req() request: Request,
+ @common.Param() params: UserWhereUniqueInput
+ ): Promise