diff --git a/server/.dockerignore b/server/.dockerignore deleted file mode 100644 index cb5c30b..0000000 --- a/server/.dockerignore +++ /dev/null @@ -1,8 +0,0 @@ -.dockerignore -docker-compose.yml -Dockerfile -dist/ -node_modules -.env -.gitignore -.prettierignore \ No newline at end of file diff --git a/server/.env b/server/.env deleted file mode 100644 index 714edfe..0000000 --- a/server/.env +++ /dev/null @@ -1,10 +0,0 @@ -BCRYPT_SALT=10 -COMPOSE_PROJECT_NAME=amp_clok9hy1s0haskj01jpbldjwk -PORT=3000 -DB_USER=root -DB_PASSWORD=admin -DB_PORT=3306 -DB_NAME=my-db -DB_URL=mysql://root:admin@localhost:3306/my-db -JWT_SECRET_KEY=Change_ME!!! -JWT_EXPIRATION=2d \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore deleted file mode 100644 index 08c9980..0000000 --- a/server/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -/node_modules -/dist -.DS_Store diff --git a/server/.prettierignore b/server/.prettierignore deleted file mode 100644 index e48f355..0000000 --- a/server/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -dist/ -prisma/migrations/ -package-lock.json -coverage/ \ No newline at end of file diff --git a/server/Dockerfile b/server/Dockerfile deleted file mode 100644 index 80dd8d3..0000000 --- a/server/Dockerfile +++ /dev/null @@ -1,68 +0,0 @@ -# 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/server/README.md b/server/README.md deleted file mode 100644 index 6db8e75..0000000 --- a/server/README.md +++ /dev/null @@ -1,64 +0,0 @@ -

- - amplication-logo - -

- -# 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/server/docker-compose.dev.yml b/server/docker-compose.dev.yml deleted file mode 100644 index e2c7ce0..0000000 --- a/server/docker-compose.dev.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: "3" -services: - db: - image: mysql - command: --default-authentication-plugin=mysql_native_password - restart: always - ports: - - ${DB_PORT}:3306 - environment: - MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} - healthcheck: - test: - - CMD - - mysqladmin - - ping - - -h - - localhost - - -u - - ${DB_USER} - timeout: 45s - interval: 10s - retries: 10 - adminer: - image: adminer - restart: always - ports: - - 1234:8080 -volumes: - mysql: ~ diff --git a/server/docker-compose.yml b/server/docker-compose.yml deleted file mode 100644 index 3eddc28..0000000 --- a/server/docker-compose.yml +++ /dev/null @@ -1,57 +0,0 @@ -version: "3" -services: - server: - build: - context: . - args: - NPM_LOG_LEVEL: notice - ports: - - ${PORT}:3000 - environment: - BCRYPT_SALT: ${BCRYPT_SALT} - JWT_SECRET_KEY: ${JWT_SECRET_KEY} - JWT_EXPIRATION: ${JWT_EXPIRATION} - DB_URL: mysql://${DB_USER}:${DB_PASSWORD}@db:3306/${DB_NAME} - depends_on: - - migrate - 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: mysql://${DB_USER}:${DB_PASSWORD}@db:3306/${DB_NAME} - depends_on: - db: - condition: service_healthy - adminer: - image: adminer - restart: always - ports: - - 1234:8080 - db: - image: mysql - command: --default-authentication-plugin=mysql_native_password - restart: always - ports: - - ${DB_PORT}:3306 - environment: - MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} - healthcheck: - test: - - CMD - - mysqladmin - - ping - - -h - - localhost - - -u - - ${DB_USER} - timeout: 45s - interval: 10s - retries: 10 -volumes: - mysql: ~ diff --git a/server/nest-cli.json b/server/nest-cli.json deleted file mode 100644 index fe51713..0000000 --- a/server/nest-cli.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sourceRoot": "src", - "compilerOptions": { - "assets": ["swagger"] - } -} diff --git a/server/package.json b/server/package.json deleted file mode 100644 index 6d19d1d..0000000 --- a/server/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "@record/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 \"db:migrate-save -- --name 'initial version'\" db:migrate-up 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" - }, - "dependencies": { - "@amplication/nest-access-control": "2.2.1", - "@apollo/server": "^4.9.4", - "@nestjs/apollo": "12.0.9", - "@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/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", - "class-transformer": "0.5.1", - "class-validator": "0.14.0", - "dotenv": "16.3.1", - "graphql": "^16.8.1", - "graphql-type-json": "0.3.2", - "nest-access-control": "^3.1.0", - "npm-run-all": "4.1.5", - "passport": "0.6.0", - "passport-http": "0.3.0", - "passport-jwt": "4.0.1", - "reflect-metadata": "0.1.13", - "ts-node": "10.9.1", - "type-fest": "2.19.0", - "validator": "13.11.0" - }, - "devDependencies": { - "@nestjs/cli": "^10.1.18", - "@nestjs/testing": "^10.2.7", - "@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.2.2" - }, - "jest": { - "preset": "ts-jest", - "testEnvironment": "node", - "modulePathIgnorePatterns": ["/dist/"] - } -} diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma deleted file mode 100644 index 1379699..0000000 --- a/server/prisma/schema.prisma +++ /dev/null @@ -1,19 +0,0 @@ -datasource db { - provider = "mysql" - url = env("DB_URL") -} - -generator client { - provider = "prisma-client-js" -} - -model User { - createdAt DateTime @default(now()) - firstName String? - id String @id @default(cuid()) - lastName String? - password String - roles Json - updatedAt DateTime @updatedAt - username String @unique -} diff --git a/server/scripts/customSeed.ts b/server/scripts/customSeed.ts deleted file mode 100644 index 6baf5f6..0000000 --- a/server/scripts/customSeed.ts +++ /dev/null @@ -1,17 +0,0 @@ -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/server/scripts/seed.ts b/server/scripts/seed.ts deleted file mode 100644 index 272dddd..0000000 --- a/server/scripts/seed.ts +++ /dev/null @@ -1,49 +0,0 @@ -import * as dotenv from "dotenv"; -import { PrismaClient } from "@prisma/client"; -import { customSeed } from "./customSeed"; -import { Salt, parseSalt } from "../src/auth/password.service"; -import { hash } from "bcrypt"; - -if (require.main === module) { - dotenv.config(); - - const { BCRYPT_SALT } = process.env; - - if (!BCRYPT_SALT) { - throw new Error("BCRYPT_SALT environment variable must be defined"); - } - const salt = parseSalt(BCRYPT_SALT); - - seed(salt).catch((error) => { - 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/server/src/app.module.ts b/server/src/app.module.ts deleted file mode 100644 index 2fcb3b5..0000000 --- a/server/src/app.module.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Module } from "@nestjs/common"; -import { UserModule } from "./user/user.module"; -import { HealthModule } from "./health/health.module"; -import { PrismaModule } from "./prisma/prisma.module"; -import { SecretsManagerModule } from "./providers/secrets/secretsManager.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 { ACLModule } from "./auth/acl.module"; -import { AuthModule } from "./auth/auth.module"; - -@Module({ - controllers: [], - imports: [ - ACLModule, - AuthModule, - UserModule, - 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], - }), - ], - providers: [], -}) -export class AppModule {} diff --git a/server/src/auth/Credentials.ts b/server/src/auth/Credentials.ts deleted file mode 100644 index 9ac6798..0000000 --- a/server/src/auth/Credentials.ts +++ /dev/null @@ -1,21 +0,0 @@ -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/server/src/auth/IAuthStrategy.ts b/server/src/auth/IAuthStrategy.ts deleted file mode 100644 index 5db10cf..0000000 --- a/server/src/auth/IAuthStrategy.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { UserInfo } from "./UserInfo"; - -export interface IAuthStrategy { - validate: (...any: any) => Promise; -} diff --git a/server/src/auth/ITokenService.ts b/server/src/auth/ITokenService.ts deleted file mode 100644 index 7983189..0000000 --- a/server/src/auth/ITokenService.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface ITokenPayload { - id: string; - username: string; - password: string; -} - -export interface ITokenService { - createToken: ({ id, username, password }: ITokenPayload) => Promise; -} diff --git a/server/src/auth/LoginArgs.ts b/server/src/auth/LoginArgs.ts deleted file mode 100644 index 66a0b2f..0000000 --- a/server/src/auth/LoginArgs.ts +++ /dev/null @@ -1,12 +0,0 @@ -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/server/src/auth/UserInfo.ts b/server/src/auth/UserInfo.ts deleted file mode 100644 index ef61dc4..0000000 --- a/server/src/auth/UserInfo.ts +++ /dev/null @@ -1,14 +0,0 @@ -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/server/src/auth/abac.util.ts b/server/src/auth/abac.util.ts deleted file mode 100644 index 2f0dcab..0000000 --- a/server/src/auth/abac.util.ts +++ /dev/null @@ -1,19 +0,0 @@ -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/server/src/auth/acl.module.ts b/server/src/auth/acl.module.ts deleted file mode 100644 index eb90005..0000000 --- a/server/src/auth/acl.module.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AccessControlModule, RolesBuilder } from "nest-access-control"; -// @ts-ignore -// eslint-disable-next-line import/no-unresolved -import grants from "../grants.json"; - -// eslint-disable-next-line @typescript-eslint/naming-convention -export const ACLModule = AccessControlModule.forRoles(new RolesBuilder(grants)); diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts deleted file mode 100644 index 7ae732f..0000000 --- a/server/src/auth/auth.controller.ts +++ /dev/null @@ -1,15 +0,0 @@ -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/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts deleted file mode 100644 index 73c8725..0000000 --- a/server/src/auth/auth.module.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { forwardRef, Module } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; -import { JwtModule } from "@nestjs/jwt"; -import { PassportModule } from "@nestjs/passport"; -import { JWT_EXPIRATION, JWT_SECRET_KEY } from "../constants"; -import { SecretsManagerModule } from "../providers/secrets/secretsManager.module"; -import { SecretsManagerService } from "../providers/secrets/secretsManager.service"; -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(JWT_SECRET_KEY); - 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/server/src/auth/auth.resolver.ts b/server/src/auth/auth.resolver.ts deleted file mode 100644 index c186f41..0000000 --- a/server/src/auth/auth.resolver.ts +++ /dev/null @@ -1,23 +0,0 @@ -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/server/src/auth/auth.service.spec.ts b/server/src/auth/auth.service.spec.ts deleted file mode 100644 index 72fd2d3..0000000 --- a/server/src/auth/auth.service.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -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 = { - findOne(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/server/src/auth/auth.service.ts b/server/src/auth/auth.service.ts deleted file mode 100644 index f5a74ba..0000000 --- a/server/src/auth/auth.service.ts +++ /dev/null @@ -1,49 +0,0 @@ -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.findOne({ - 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/server/src/auth/base/token.service.base.ts b/server/src/auth/base/token.service.base.ts deleted file mode 100644 index f25fdb5..0000000 --- a/server/src/auth/base/token.service.base.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* 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/server/src/auth/constants.ts b/server/src/auth/constants.ts deleted file mode 100644 index 59f9f7d..0000000 --- a/server/src/auth/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const INVALID_USERNAME_ERROR = "Invalid username"; -export const INVALID_PASSWORD_ERROR = "Invalid password"; diff --git a/server/src/auth/defaultAuth.guard.ts b/server/src/auth/defaultAuth.guard.ts deleted file mode 100644 index 33a530c..0000000 --- a/server/src/auth/defaultAuth.guard.ts +++ /dev/null @@ -1,27 +0,0 @@ -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/server/src/auth/gqlAC.guard.ts b/server/src/auth/gqlAC.guard.ts deleted file mode 100644 index dacac55..0000000 --- a/server/src/auth/gqlAC.guard.ts +++ /dev/null @@ -1,11 +0,0 @@ -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/server/src/auth/gqlDefaultAuth.guard.ts b/server/src/auth/gqlDefaultAuth.guard.ts deleted file mode 100644 index 0455177..0000000 --- a/server/src/auth/gqlDefaultAuth.guard.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ExecutionContext } from "@nestjs/common"; -import { GqlExecutionContext } from "@nestjs/graphql"; -import type { Request } from "express"; -// @ts-ignore -// eslint-disable-next-line -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/server/src/auth/gqlUserRoles.decorator.ts b/server/src/auth/gqlUserRoles.decorator.ts deleted file mode 100644 index 5ea256b..0000000 --- a/server/src/auth/gqlUserRoles.decorator.ts +++ /dev/null @@ -1,19 +0,0 @@ -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/server/src/auth/jwt/base/jwt.strategy.base.ts b/server/src/auth/jwt/base/jwt.strategy.base.ts deleted file mode 100644 index 3bbc919..0000000 --- a/server/src/auth/jwt/base/jwt.strategy.base.ts +++ /dev/null @@ -1,40 +0,0 @@ -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.findOne({ - 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/server/src/auth/jwt/jwt.strategy.ts b/server/src/auth/jwt/jwt.strategy.ts deleted file mode 100644 index 9e75f4c..0000000 --- a/server/src/auth/jwt/jwt.strategy.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Inject, Injectable } from "@nestjs/common"; -import { JWT_SECRET_KEY } 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) secretOrKey: string, - protected readonly userService: UserService - ) { - super(secretOrKey, userService); - } -} diff --git a/server/src/auth/jwt/jwtAuth.guard.ts b/server/src/auth/jwt/jwtAuth.guard.ts deleted file mode 100644 index f0c5570..0000000 --- a/server/src/auth/jwt/jwtAuth.guard.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { AuthGuard } from "@nestjs/passport"; - -export class JwtAuthGuard extends AuthGuard("jwt") {} diff --git a/server/src/auth/jwt/jwtSecretFactory.ts b/server/src/auth/jwt/jwtSecretFactory.ts deleted file mode 100644 index 151e793..0000000 --- a/server/src/auth/jwt/jwtSecretFactory.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { JWT_SECRET_KEY } from "../../constants"; -import { SecretsManagerService } from "../../providers/secrets/secretsManager.service"; - -export const jwtSecretFactory = { - provide: JWT_SECRET_KEY, - useFactory: async ( - secretsService: SecretsManagerService - ): Promise => { - const secret = await secretsService.getSecret(JWT_SECRET_KEY); - if (secret) { - return secret; - } - throw new Error("jwtSecretFactory missing secret"); - }, - inject: [SecretsManagerService], -}; diff --git a/server/src/auth/password.service.spec.ts b/server/src/auth/password.service.spec.ts deleted file mode 100644 index 309c8c0..0000000 --- a/server/src/auth/password.service.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -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/server/src/auth/password.service.ts b/server/src/auth/password.service.ts deleted file mode 100644 index 377b64b..0000000 --- a/server/src/auth/password.service.ts +++ /dev/null @@ -1,64 +0,0 @@ -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/server/src/auth/token.service.ts b/server/src/auth/token.service.ts deleted file mode 100644 index b102b72..0000000 --- a/server/src/auth/token.service.ts +++ /dev/null @@ -1,7 +0,0 @@ -//@ts-ignore -import { ITokenService } from "./ITokenService"; -// eslint-disable-next-line import/no-unresolved -//@ts-ignore -import { TokenServiceBase } from "./base/token.service.base"; - -export class TokenService extends TokenServiceBase implements ITokenService {} diff --git a/server/src/auth/userData.decorator.ts b/server/src/auth/userData.decorator.ts deleted file mode 100644 index 6a40ad1..0000000 --- a/server/src/auth/userData.decorator.ts +++ /dev/null @@ -1,30 +0,0 @@ -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/server/src/connectMicroservices.ts b/server/src/connectMicroservices.ts deleted file mode 100644 index 068fa5f..0000000 --- a/server/src/connectMicroservices.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { INestApplication } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; - -export async function connectMicroservices(app: INestApplication) { - const configService = app.get(ConfigService); -} diff --git a/server/src/constants.ts b/server/src/constants.ts deleted file mode 100644 index 08f98bf..0000000 --- a/server/src/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const JWT_SECRET_KEY = "JWT_SECRET_KEY"; -export const JWT_EXPIRATION = "JWT_EXPIRATION"; diff --git a/server/src/decorators/api-nested-query.decorator.ts b/server/src/decorators/api-nested-query.decorator.ts deleted file mode 100644 index 9fd5ba3..0000000 --- a/server/src/decorators/api-nested-query.decorator.ts +++ /dev/null @@ -1,80 +0,0 @@ -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/server/src/decorators/public.decorator.ts b/server/src/decorators/public.decorator.ts deleted file mode 100644 index 9eab4e0..0000000 --- a/server/src/decorators/public.decorator.ts +++ /dev/null @@ -1,10 +0,0 @@ -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/server/src/errors.ts b/server/src/errors.ts deleted file mode 100644 index bd1aa6d..0000000 --- a/server/src/errors.ts +++ /dev/null @@ -1,16 +0,0 @@ -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/server/src/filters/HttpExceptions.filter.ts b/server/src/filters/HttpExceptions.filter.ts deleted file mode 100644 index f5eda8e..0000000 --- a/server/src/filters/HttpExceptions.filter.ts +++ /dev/null @@ -1,89 +0,0 @@ -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/server/src/grants.json b/server/src/grants.json deleted file mode 100644 index 51ae229..0000000 --- a/server/src/grants.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "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/server/src/health/base/health.controller.base.ts b/server/src/health/base/health.controller.base.ts deleted file mode 100644 index afd9e0d..0000000 --- a/server/src/health/base/health.controller.base.ts +++ /dev/null @@ -1,19 +0,0 @@ -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/server/src/health/base/health.service.base.ts b/server/src/health/base/health.service.base.ts deleted file mode 100644 index 49a93a5..0000000 --- a/server/src/health/base/health.service.base.ts +++ /dev/null @@ -1,15 +0,0 @@ -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.$queryRaw`SELECT 1`; - return true; - } catch (error) { - return false; - } - } -} diff --git a/server/src/health/health.controller.ts b/server/src/health/health.controller.ts deleted file mode 100644 index ff484e7..0000000 --- a/server/src/health/health.controller.ts +++ /dev/null @@ -1,10 +0,0 @@ -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/server/src/health/health.module.ts b/server/src/health/health.module.ts deleted file mode 100644 index 39eff7f..0000000 --- a/server/src/health/health.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -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/server/src/health/health.service.ts b/server/src/health/health.service.ts deleted file mode 100644 index 44d9343..0000000 --- a/server/src/health/health.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -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/server/src/interceptors/aclFilterResponse.interceptor.ts b/server/src/interceptors/aclFilterResponse.interceptor.ts deleted file mode 100644 index 5eeba18..0000000 --- a/server/src/interceptors/aclFilterResponse.interceptor.ts +++ /dev/null @@ -1,42 +0,0 @@ -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/server/src/interceptors/aclValidateRequest.interceptor.ts b/server/src/interceptors/aclValidateRequest.interceptor.ts deleted file mode 100644 index 6d30246..0000000 --- a/server/src/interceptors/aclValidateRequest.interceptor.ts +++ /dev/null @@ -1,53 +0,0 @@ -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/server/src/main.ts b/server/src/main.ts deleted file mode 100644 index 474eead..0000000 --- a/server/src/main.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ValidationPipe } from "@nestjs/common"; -import { 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"; - -const { PORT = 3000 } = process.env; - -async function main() { - const app = await NestFactory.create(AppModule, { cors: true }); - - app.setGlobalPrefix("api"); - app.useGlobalPipes( - new ValidationPipe({ - transform: true, - forbidUnknownValues: false, - }) - ); - - 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)); - - void app.listen(PORT); - - return app; -} - -module.exports = main(); diff --git a/server/src/prisma.util.spec.ts b/server/src/prisma.util.spec.ts deleted file mode 100644 index 0aa308e..0000000 --- a/server/src/prisma.util.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -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/server/src/prisma.util.ts b/server/src/prisma.util.ts deleted file mode 100644 index 029b98a..0000000 --- a/server/src/prisma.util.ts +++ /dev/null @@ -1,29 +0,0 @@ -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/server/src/prisma/prisma.module.ts b/server/src/prisma/prisma.module.ts deleted file mode 100644 index 1edbf95..0000000 --- a/server/src/prisma/prisma.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Global, Module } from "@nestjs/common"; -import { PrismaService } from "./prisma.service"; - -@Global() -@Module({ - providers: [PrismaService], - exports: [PrismaService], -}) -export class PrismaModule {} diff --git a/server/src/prisma/prisma.service.ts b/server/src/prisma/prisma.service.ts deleted file mode 100644 index 79ea4fa..0000000 --- a/server/src/prisma/prisma.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -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/server/src/providers/secrets/base/secretsManager.service.base.spec.ts b/server/src/providers/secrets/base/secretsManager.service.base.spec.ts deleted file mode 100644 index beb2607..0000000 --- a/server/src/providers/secrets/base/secretsManager.service.base.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ConfigService } from "@nestjs/config"; -import { mock } from "jest-mock-extended"; -import { SecretsManagerServiceBase } from "./secretsManager.service.base"; - -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); - //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); - //ASSERT - expect(result).toBeNull(); - }); - it("should throw error if dont get key", () => { - return expect(secretsManagerServiceBase.getSecret("")).rejects.toThrow(); - }); - it("should throw an exception if getting null key", () => { - return expect( - secretsManagerServiceBase.getSecret(null as unknown as string) - ).rejects.toThrow(); - }); -}); diff --git a/server/src/providers/secrets/base/secretsManager.service.base.ts b/server/src/providers/secrets/base/secretsManager.service.base.ts deleted file mode 100644 index 18a340b..0000000 --- a/server/src/providers/secrets/base/secretsManager.service.base.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ConfigService } from "@nestjs/config"; - -export interface ISecretsManager { - getSecret: (key: string) => Promise; -} - -export class SecretsManagerServiceBase implements ISecretsManager { - constructor(protected readonly configService: ConfigService) {} - async getSecret(key: string): Promise { - if (!key) { - throw new Error("Didn't got the key"); - } - const value = this.configService.get(key); - if (value) { - return value; - } - return null; - } -} diff --git a/server/src/providers/secrets/secretsManager.module.ts b/server/src/providers/secrets/secretsManager.module.ts deleted file mode 100644 index 3a621e4..0000000 --- a/server/src/providers/secrets/secretsManager.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Module } from "@nestjs/common"; -import { SecretsManagerService } from "./secretsManager.service"; - -@Module({ - providers: [SecretsManagerService], - exports: [SecretsManagerService], -}) -export class SecretsManagerModule {} diff --git a/server/src/providers/secrets/secretsManager.service.ts b/server/src/providers/secrets/secretsManager.service.ts deleted file mode 100644 index 89907c3..0000000 --- a/server/src/providers/secrets/secretsManager.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -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/server/src/serveStaticOptions.service.ts b/server/src/serveStaticOptions.service.ts deleted file mode 100644 index 390248b..0000000 --- a/server/src/serveStaticOptions.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -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/server/src/swagger.ts b/server/src/swagger.ts deleted file mode 100644 index cadb474..0000000 --- a/server/src/swagger.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { DocumentBuilder, SwaggerCustomOptions } from "@nestjs/swagger"; - -export const swaggerPath = "api"; - -export const swaggerDocumentOptions = new DocumentBuilder() - .setTitle("Record") - .setDescription( - '\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: "Record", -}; diff --git a/server/src/swagger/favicon.png b/server/src/swagger/favicon.png deleted file mode 100644 index a79882d..0000000 Binary files a/server/src/swagger/favicon.png and /dev/null differ diff --git a/server/src/swagger/logo-amplication-white.svg b/server/src/swagger/logo-amplication-white.svg deleted file mode 100644 index 0054cd4..0000000 --- a/server/src/swagger/logo-amplication-white.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/server/src/swagger/swagger.css b/server/src/swagger/swagger.css deleted file mode 100644 index b7c4037..0000000 --- a/server/src/swagger/swagger.css +++ /dev/null @@ -1,321 +0,0 @@ -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/server/src/tests/auth/constants.ts b/server/src/tests/auth/constants.ts deleted file mode 100644 index 98e4887..0000000 --- a/server/src/tests/auth/constants.ts +++ /dev/null @@ -1,19 +0,0 @@ -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/server/src/tests/auth/jwt/jwt.strategy.spec.ts b/server/src/tests/auth/jwt/jwt.strategy.spec.ts deleted file mode 100644 index 2463c9b..0000000 --- a/server/src/tests/auth/jwt/jwt.strategy.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -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(userService, "Secrete"); - beforeEach(() => { - userService.findOne.mockClear(); - }); - it("should throw UnauthorizedException where there is no user", async () => { - //ARRANGE - userService.findOne - .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/server/src/tests/auth/token.service.spec.ts b/server/src/tests/auth/token.service.spec.ts deleted file mode 100644 index 83b5a51..0000000 --- a/server/src/tests/auth/token.service.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -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/server/src/tests/health/health.service.spec.ts b/server/src/tests/health/health.service.spec.ts deleted file mode 100644 index 4b191f1..0000000 --- a/server/src/tests/health/health.service.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { mock } from "jest-mock-extended"; -import { PrismaService } from "../../prisma/prisma.service"; -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.$queryRaw as jest.Mock).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.$queryRaw as jest.Mock).mockReturnValue( - Promise.reject(false) - ); - //ACT - const response = await healthServiceBase.isDbReady(); - //ASSERT - expect(response).toBe(false); - }); - }); -}); diff --git a/server/src/types.ts b/server/src/types.ts deleted file mode 100644 index f762a5d..0000000 --- a/server/src/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { JsonValue } from "type-fest"; - -export type InputJsonValue = Omit; diff --git a/server/src/user/base/CreateUserArgs.ts b/server/src/user/base/CreateUserArgs.ts deleted file mode 100644 index 092a504..0000000 --- a/server/src/user/base/CreateUserArgs.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/DeleteUserArgs.ts b/server/src/user/base/DeleteUserArgs.ts deleted file mode 100644 index 042ed5f..0000000 --- a/server/src/user/base/DeleteUserArgs.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/UpdateUserArgs.ts b/server/src/user/base/UpdateUserArgs.ts deleted file mode 100644 index 1f13420..0000000 --- a/server/src/user/base/UpdateUserArgs.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/User.ts b/server/src/user/base/User.ts deleted file mode 100644 index 45adebe..0000000 --- a/server/src/user/base/User.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* ------------------------------------------------------------------------------- -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, IsOptional } from "class-validator"; -import { Type } from "class-transformer"; -import { IsJSONValue } from "@app/custom-validators"; -import { GraphQLJSON } from "graphql-type-json"; -import { JsonValue } from "type-fest"; - -@ObjectType() -class User { - @ApiProperty({ - required: true, - }) - @IsDate() - @Type(() => Date) - @Field(() => Date) - createdAt!: Date; - - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - firstName!: string | null; - - @ApiProperty({ - required: true, - type: String, - }) - @IsString() - @Field(() => String) - id!: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - lastName!: string | null; - - @ApiProperty({ - required: true, - }) - @IsJSONValue() - @Field(() => GraphQLJSON) - roles!: JsonValue; - - @ApiProperty({ - required: true, - }) - @IsDate() - @Type(() => Date) - @Field(() => Date) - updatedAt!: Date; - - @ApiProperty({ - required: true, - type: String, - }) - @IsString() - @Field(() => String) - username!: string; -} - -export { User as User }; diff --git a/server/src/user/base/UserCountArgs.ts b/server/src/user/base/UserCountArgs.ts deleted file mode 100644 index f4a14ac..0000000 --- a/server/src/user/base/UserCountArgs.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/UserCreateInput.ts b/server/src/user/base/UserCreateInput.ts deleted file mode 100644 index 6896f2a..0000000 --- a/server/src/user/base/UserCreateInput.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* ------------------------------------------------------------------------------- -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, IsOptional } from "class-validator"; -import { IsJSONValue } from "@app/custom-validators"; -import { GraphQLJSON } from "graphql-type-json"; -import { InputJsonValue } from "../../types"; - -@InputType() -class UserCreateInput { - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - firstName?: string | null; - - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - lastName?: string | null; - - @ApiProperty({ - required: true, - type: String, - }) - @IsString() - @Field(() => String) - password!: string; - - @ApiProperty({ - required: true, - }) - @IsJSONValue() - @Field(() => GraphQLJSON) - roles!: InputJsonValue; - - @ApiProperty({ - required: true, - type: String, - }) - @IsString() - @Field(() => String) - username!: string; -} - -export { UserCreateInput as UserCreateInput }; diff --git a/server/src/user/base/UserFindManyArgs.ts b/server/src/user/base/UserFindManyArgs.ts deleted file mode 100644 index 8ba369c..0000000 --- a/server/src/user/base/UserFindManyArgs.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/UserFindUniqueArgs.ts b/server/src/user/base/UserFindUniqueArgs.ts deleted file mode 100644 index c64506f..0000000 --- a/server/src/user/base/UserFindUniqueArgs.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/UserListRelationFilter.ts b/server/src/user/base/UserListRelationFilter.ts deleted file mode 100644 index 0ff7d94..0000000 --- a/server/src/user/base/UserListRelationFilter.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/UserOrderByInput.ts b/server/src/user/base/UserOrderByInput.ts deleted file mode 100644 index 1ded2ed..0000000 --- a/server/src/user/base/UserOrderByInput.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* ------------------------------------------------------------------------------- -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, - }) - 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, - }) - 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/server/src/user/base/UserUpdateInput.ts b/server/src/user/base/UserUpdateInput.ts deleted file mode 100644 index b6e0e21..0000000 --- a/server/src/user/base/UserUpdateInput.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* ------------------------------------------------------------------------------- -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, IsOptional } from "class-validator"; -import { IsJSONValue } from "@app/custom-validators"; -import { GraphQLJSON } from "graphql-type-json"; -import { InputJsonValue } from "../../types"; - -@InputType() -class UserUpdateInput { - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - firstName?: string | null; - - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - lastName?: string | null; - - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - password?: string; - - @ApiProperty({ - required: false, - }) - @IsJSONValue() - @IsOptional() - @Field(() => GraphQLJSON, { - nullable: true, - }) - roles?: InputJsonValue; - - @ApiProperty({ - required: false, - type: String, - }) - @IsString() - @IsOptional() - @Field(() => String, { - nullable: true, - }) - username?: string; -} - -export { UserUpdateInput as UserUpdateInput }; diff --git a/server/src/user/base/UserWhereInput.ts b/server/src/user/base/UserWhereInput.ts deleted file mode 100644 index a8babc1..0000000 --- a/server/src/user/base/UserWhereInput.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* ------------------------------------------------------------------------------- -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 { StringFilter } from "../../util/StringFilter"; - -@InputType() -class UserWhereInput { - @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: StringFilter, - }) - @Type(() => StringFilter) - @IsOptional() - @Field(() => StringFilter, { - nullable: true, - }) - username?: StringFilter; -} - -export { UserWhereInput as UserWhereInput }; diff --git a/server/src/user/base/UserWhereUniqueInput.ts b/server/src/user/base/UserWhereUniqueInput.ts deleted file mode 100644 index 0bcea12..0000000 --- a/server/src/user/base/UserWhereUniqueInput.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------------------------------------------- -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/server/src/user/base/user.controller.base.spec.ts b/server/src/user/base/user.controller.base.spec.ts deleted file mode 100644 index 2a2044a..0000000 --- a/server/src/user/base/user.controller.base.spec.ts +++ /dev/null @@ -1,206 +0,0 @@ -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(), - firstName: "exampleFirstName", - id: "exampleId", - lastName: "exampleLastName", - password: "examplePassword", - updatedAt: new Date(), - username: "exampleUsername", -}; -const CREATE_RESULT = { - createdAt: new Date(), - firstName: "exampleFirstName", - id: "exampleId", - lastName: "exampleLastName", - password: "examplePassword", - updatedAt: new Date(), - username: "exampleUsername", -}; -const FIND_MANY_RESULT = [ - { - createdAt: new Date(), - firstName: "exampleFirstName", - id: "exampleId", - lastName: "exampleLastName", - password: "examplePassword", - updatedAt: new Date(), - username: "exampleUsername", - }, -]; -const FIND_ONE_RESULT = { - createdAt: new Date(), - firstName: "exampleFirstName", - id: "exampleId", - lastName: "exampleLastName", - password: "examplePassword", - updatedAt: new Date(), - username: "exampleUsername", -}; - -const service = { - create() { - return CREATE_RESULT; - }, - findMany: () => FIND_MANY_RESULT, - findOne: ({ 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/server/src/user/base/user.controller.base.ts b/server/src/user/base/user.controller.base.ts deleted file mode 100644 index 0a05e44..0000000 --- a/server/src/user/base/user.controller.base.ts +++ /dev/null @@ -1,203 +0,0 @@ -/* ------------------------------------------------------------------------------- -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 { UserWhereInput } from "./UserWhereInput"; -import { UserWhereUniqueInput } from "./UserWhereUniqueInput"; -import { UserFindManyArgs } from "./UserFindManyArgs"; -import { UserUpdateInput } from "./UserUpdateInput"; -import { User } from "./User"; - -@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 create(@common.Body() data: UserCreateInput): Promise { - return await this.service.create({ - data: data, - select: { - createdAt: true, - firstName: true, - id: true, - lastName: 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 findMany(@common.Req() request: Request): Promise { - const args = plainToClass(UserFindManyArgs, request.query); - return this.service.findMany({ - ...args, - select: { - createdAt: true, - firstName: true, - id: true, - lastName: 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 findOne( - @common.Param() params: UserWhereUniqueInput - ): Promise { - const result = await this.service.findOne({ - where: params, - select: { - createdAt: true, - firstName: true, - id: true, - lastName: 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 update( - @common.Param() params: UserWhereUniqueInput, - @common.Body() data: UserUpdateInput - ): Promise { - try { - return await this.service.update({ - where: params, - data: data, - select: { - createdAt: true, - firstName: true, - id: true, - lastName: 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 delete( - @common.Param() params: UserWhereUniqueInput - ): Promise { - try { - return await this.service.delete({ - where: params, - select: { - createdAt: true, - firstName: true, - id: true, - lastName: 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; - } - } -} diff --git a/server/src/user/base/user.module.base.ts b/server/src/user/base/user.module.base.ts deleted file mode 100644 index a8b6c68..0000000 --- a/server/src/user/base/user.module.base.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* ------------------------------------------------------------------------------- -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 UserModuleBase {} diff --git a/server/src/user/base/user.resolver.base.ts b/server/src/user/base/user.resolver.base.ts deleted file mode 100644 index 21558be..0000000 --- a/server/src/user/base/user.resolver.base.ts +++ /dev/null @@ -1,134 +0,0 @@ -/* ------------------------------------------------------------------------------- -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 { CreateUserArgs } from "./CreateUserArgs"; -import { UpdateUserArgs } from "./UpdateUserArgs"; -import { DeleteUserArgs } from "./DeleteUserArgs"; -import { UserCountArgs } from "./UserCountArgs"; -import { UserFindManyArgs } from "./UserFindManyArgs"; -import { UserFindUniqueArgs } from "./UserFindUniqueArgs"; -import { User } from "./User"; -import { UserService } from "../user.service"; -@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) -@graphql.Resolver(() => User) -export class UserResolverBase { - constructor( - protected readonly service: UserService, - protected readonly rolesBuilder: nestAccessControl.RolesBuilder - ) {} - - @graphql.Query(() => MetaQueryPayload) - @nestAccessControl.UseRoles({ - resource: "User", - action: "read", - possession: "any", - }) - async _usersMeta( - @graphql.Args() args: UserCountArgs - ): Promise { - const result = await this.service.count(args); - return { - count: result, - }; - } - - @common.UseInterceptors(AclFilterResponseInterceptor) - @graphql.Query(() => [User]) - @nestAccessControl.UseRoles({ - resource: "User", - action: "read", - possession: "any", - }) - async users(@graphql.Args() args: UserFindManyArgs): Promise { - return this.service.findMany(args); - } - - @common.UseInterceptors(AclFilterResponseInterceptor) - @graphql.Query(() => User, { nullable: true }) - @nestAccessControl.UseRoles({ - resource: "User", - action: "read", - possession: "own", - }) - async user(@graphql.Args() args: UserFindUniqueArgs): Promise { - const result = await this.service.findOne(args); - if (result === null) { - return null; - } - return result; - } - - @common.UseInterceptors(AclValidateRequestInterceptor) - @graphql.Mutation(() => User) - @nestAccessControl.UseRoles({ - resource: "User", - action: "create", - possession: "any", - }) - async createUser(@graphql.Args() args: CreateUserArgs): Promise { - return await this.service.create({ - ...args, - data: args.data, - }); - } - - @common.UseInterceptors(AclValidateRequestInterceptor) - @graphql.Mutation(() => User) - @nestAccessControl.UseRoles({ - resource: "User", - action: "update", - possession: "any", - }) - async updateUser(@graphql.Args() args: UpdateUserArgs): Promise { - try { - return await this.service.update({ - ...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(() => User) - @nestAccessControl.UseRoles({ - resource: "User", - action: "delete", - possession: "any", - }) - async deleteUser(@graphql.Args() args: DeleteUserArgs): Promise { - try { - return await this.service.delete(args); - } catch (error) { - if (isRecordNotFoundError(error)) { - throw new GraphQLError( - `No resource was found for ${JSON.stringify(args.where)}` - ); - } - throw error; - } - } -} diff --git a/server/src/user/base/user.service.base.ts b/server/src/user/base/user.service.base.ts deleted file mode 100644 index 3c9de61..0000000 --- a/server/src/user/base/user.service.base.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* ------------------------------------------------------------------------------- -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, User } from "@prisma/client"; -import { PasswordService } from "../../auth/password.service"; -import { transformStringFieldUpdateInput } from "../../prisma.util"; - -export class UserServiceBase { - constructor( - protected readonly prisma: PrismaService, - protected readonly passwordService: PasswordService - ) {} - - async count( - args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.count(args); - } - - async findMany( - args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.findMany(args); - } - async findOne( - args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.findUnique(args); - } - async create( - args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.create({ - ...args, - - data: { - ...args.data, - password: await this.passwordService.hash(args.data.password), - }, - }); - } - async update( - args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.update({ - ...args, - - data: { - ...args.data, - - password: - args.data.password && - (await transformStringFieldUpdateInput( - args.data.password, - (password) => this.passwordService.hash(password) - )), - }, - }); - } - async delete( - args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.delete(args); - } -} diff --git a/server/src/user/user.controller.ts b/server/src/user/user.controller.ts deleted file mode 100644 index 21d9583..0000000 --- a/server/src/user/user.controller.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as common from "@nestjs/common"; -import * as swagger from "@nestjs/swagger"; -import * as nestAccessControl from "nest-access-control"; -import { UserService } from "./user.service"; -import { UserControllerBase } from "./base/user.controller.base"; - -@swagger.ApiTags("users") -@common.Controller("users") -export class UserController extends UserControllerBase { - constructor( - protected readonly service: UserService, - @nestAccessControl.InjectRolesBuilder() - protected readonly rolesBuilder: nestAccessControl.RolesBuilder - ) { - super(service, rolesBuilder); - } -} diff --git a/server/src/user/user.module.ts b/server/src/user/user.module.ts deleted file mode 100644 index 2d6dd05..0000000 --- a/server/src/user/user.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module, forwardRef } from "@nestjs/common"; -import { AuthModule } from "../auth/auth.module"; -import { UserModuleBase } from "./base/user.module.base"; -import { UserService } from "./user.service"; -import { UserController } from "./user.controller"; -import { UserResolver } from "./user.resolver"; - -@Module({ - imports: [UserModuleBase, forwardRef(() => AuthModule)], - controllers: [UserController], - providers: [UserService, UserResolver], - exports: [UserService], -}) -export class UserModule {} diff --git a/server/src/user/user.resolver.ts b/server/src/user/user.resolver.ts deleted file mode 100644 index bc3a79b..0000000 --- a/server/src/user/user.resolver.ts +++ /dev/null @@ -1,20 +0,0 @@ -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 { UserResolverBase } from "./base/user.resolver.base"; -import { User } from "./base/User"; -import { UserService } from "./user.service"; - -@common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) -@graphql.Resolver(() => User) -export class UserResolver extends UserResolverBase { - constructor( - protected readonly service: UserService, - @nestAccessControl.InjectRolesBuilder() - protected readonly rolesBuilder: nestAccessControl.RolesBuilder - ) { - super(service, rolesBuilder); - } -} diff --git a/server/src/user/user.service.ts b/server/src/user/user.service.ts deleted file mode 100644 index a8e4508..0000000 --- a/server/src/user/user.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { PrismaService } from "../prisma/prisma.service"; -import { PasswordService } from "../auth/password.service"; -import { UserServiceBase } from "./base/user.service.base"; - -@Injectable() -export class UserService extends UserServiceBase { - constructor( - protected readonly prisma: PrismaService, - protected readonly passwordService: PasswordService - ) { - super(prisma, passwordService); - } -} diff --git a/server/src/util/BooleanFilter.ts b/server/src/util/BooleanFilter.ts deleted file mode 100644 index 75f4e34..0000000 --- a/server/src/util/BooleanFilter.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class BooleanFilter { - @ApiProperty({ - required: false, - type: Boolean, - }) - @IsOptional() - @Field(() => Boolean, { - nullable: true, - }) - @Type(() => Boolean) - equals?: boolean; - - @ApiProperty({ - required: false, - type: Boolean, - }) - @IsOptional() - @Field(() => Boolean, { - nullable: true, - }) - @Type(() => Boolean) - not?: boolean; -} diff --git a/server/src/util/BooleanNullableFilter.ts b/server/src/util/BooleanNullableFilter.ts deleted file mode 100644 index 9f48ac1..0000000 --- a/server/src/util/BooleanNullableFilter.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; -@InputType({ - isAbstract: true, - description: undefined, -}) -export class BooleanNullableFilter { - @ApiProperty({ - required: false, - type: Boolean, - }) - @IsOptional() - @Field(() => Boolean, { - nullable: true, - }) - @Type(() => Boolean) - equals?: boolean | null; - - @ApiProperty({ - required: false, - type: Boolean, - }) - @IsOptional() - @Field(() => Boolean, { - nullable: true, - }) - @Type(() => Boolean) - not?: boolean | null; -} diff --git a/server/src/util/DateTimeFilter.ts b/server/src/util/DateTimeFilter.ts deleted file mode 100644 index d2b6dfb..0000000 --- a/server/src/util/DateTimeFilter.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; -@InputType({ - isAbstract: true, - description: undefined, -}) -export class DateTimeFilter { - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - equals?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - not?: Date; - - @ApiProperty({ - required: false, - type: [Date], - }) - @IsOptional() - @Field(() => [Date], { - nullable: true, - }) - @Type(() => Date) - in?: Date[]; - - @ApiProperty({ - required: false, - type: [Date], - }) - @IsOptional() - @Field(() => [Date], { - nullable: true, - }) - @Type(() => Date) - notIn?: Date[]; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - lt?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - lte?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - gt?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - gte?: Date; -} diff --git a/server/src/util/DateTimeNullableFilter.ts b/server/src/util/DateTimeNullableFilter.ts deleted file mode 100644 index ccc00a5..0000000 --- a/server/src/util/DateTimeNullableFilter.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; -@InputType({ - isAbstract: true, - description: undefined, -}) -export class DateTimeNullableFilter { - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - equals?: Date | null; - - @ApiProperty({ - required: false, - type: [Date], - }) - @IsOptional() - @Field(() => [Date], { - nullable: true, - }) - @Type(() => Date) - in?: Date[] | null; - - @ApiProperty({ - required: false, - type: [Date], - }) - @IsOptional() - @Field(() => [Date], { - nullable: true, - }) - @Type(() => Date) - notIn?: Date[] | null; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - lt?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - lte?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - gt?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - gte?: Date; - - @ApiProperty({ - required: false, - type: Date, - }) - @IsOptional() - @Field(() => Date, { - nullable: true, - }) - @Type(() => Date) - not?: Date; -} diff --git a/server/src/util/FloatFilter.ts b/server/src/util/FloatFilter.ts deleted file mode 100644 index a3266d2..0000000 --- a/server/src/util/FloatFilter.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Field, InputType, Float } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class FloatFilter { - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - equals?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => [Float], { - nullable: true, - }) - @Type(() => Number) - in?: number[]; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Float], { - nullable: true, - }) - @Type(() => Number) - notIn?: number[]; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - lt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - lte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - gt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - gte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - not?: number; -} diff --git a/server/src/util/FloatNullableFilter.ts b/server/src/util/FloatNullableFilter.ts deleted file mode 100644 index feb0fc5..0000000 --- a/server/src/util/FloatNullableFilter.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Field, InputType, Float } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class FloatNullableFilter { - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - equals?: number | null; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Float], { - nullable: true, - }) - @Type(() => Number) - in?: number[] | null; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Float], { - nullable: true, - }) - @Type(() => Number) - notIn?: number[] | null; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - lt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - lte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - gt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - gte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Float, { - nullable: true, - }) - @Type(() => Number) - not?: number; -} diff --git a/server/src/util/IntFilter.ts b/server/src/util/IntFilter.ts deleted file mode 100644 index f6880e7..0000000 --- a/server/src/util/IntFilter.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Field, InputType, Int } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class IntFilter { - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - equals?: number; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Int], { - nullable: true, - }) - @Type(() => Number) - in?: number[]; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Int], { - nullable: true, - }) - @Type(() => Number) - notIn?: number[]; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - lt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - lte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - gt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - gte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - not?: number; -} diff --git a/server/src/util/IntNullableFilter.ts b/server/src/util/IntNullableFilter.ts deleted file mode 100644 index e3b71a3..0000000 --- a/server/src/util/IntNullableFilter.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Field, InputType, Int } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class IntNullableFilter { - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - equals?: number | null; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Int], { - nullable: true, - }) - @Type(() => Number) - in?: number[] | null; - - @ApiProperty({ - required: false, - type: [Number], - }) - @IsOptional() - @Field(() => [Int], { - nullable: true, - }) - @Type(() => Number) - notIn?: number[] | null; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - lt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - lte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - gt?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - gte?: number; - - @ApiProperty({ - required: false, - type: Number, - }) - @IsOptional() - @Field(() => Int, { - nullable: true, - }) - @Type(() => Number) - not?: number; -} diff --git a/server/src/util/JsonFilter.ts b/server/src/util/JsonFilter.ts deleted file mode 100644 index 7040b74..0000000 --- a/server/src/util/JsonFilter.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { GraphQLJSONObject } from "graphql-type-json"; -import { InputJsonValue } from "../types"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class JsonFilter { - @ApiProperty({ - required: false, - type: GraphQLJSONObject, - }) - @IsOptional() - @Field(() => GraphQLJSONObject, { - nullable: true, - }) - equals?: InputJsonValue; - - @ApiProperty({ - required: false, - type: GraphQLJSONObject, - }) - @IsOptional() - @Field(() => GraphQLJSONObject, { - nullable: true, - }) - not?: InputJsonValue; -} diff --git a/server/src/util/JsonNullableFilter.ts b/server/src/util/JsonNullableFilter.ts deleted file mode 100644 index 3381d52..0000000 --- a/server/src/util/JsonNullableFilter.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { JsonValue } from "type-fest"; -import { Field, InputType } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { GraphQLJSONObject } from "graphql-type-json"; - -@InputType({ - isAbstract: true, - description: undefined, -}) -export class JsonNullableFilter { - @ApiProperty({ - required: false, - type: GraphQLJSONObject, - }) - @IsOptional() - @Field(() => GraphQLJSONObject, { - nullable: true, - }) - equals?: JsonValue; - - @ApiProperty({ - required: false, - type: GraphQLJSONObject, - }) - @IsOptional() - @Field(() => GraphQLJSONObject, { - nullable: true, - }) - not?: JsonValue; -} diff --git a/server/src/util/MetaQueryPayload.ts b/server/src/util/MetaQueryPayload.ts deleted file mode 100644 index fc30531..0000000 --- a/server/src/util/MetaQueryPayload.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ObjectType, Field } from "@nestjs/graphql"; -import { ApiProperty } from "@nestjs/swagger"; - -@ObjectType() -class MetaQueryPayload { - @ApiProperty({ - required: true, - type: [Number], - }) - @Field(() => Number) - count!: number; -} -export { MetaQueryPayload }; diff --git a/server/src/util/QueryMode.ts b/server/src/util/QueryMode.ts deleted file mode 100644 index f9b1653..0000000 --- a/server/src/util/QueryMode.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { registerEnumType } from "@nestjs/graphql"; - -export enum QueryMode { - Default = "default", - Insensitive = "insensitive", -} -registerEnumType(QueryMode, { - name: "QueryMode", - description: undefined, -}); diff --git a/server/src/util/SortOrder.ts b/server/src/util/SortOrder.ts deleted file mode 100644 index d4108e6..0000000 --- a/server/src/util/SortOrder.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { registerEnumType } from "@nestjs/graphql"; - -export enum SortOrder { - Asc = "asc", - Desc = "desc", -} -registerEnumType(SortOrder, { - name: "SortOrder", - description: undefined, -}); diff --git a/server/src/util/StringFilter.ts b/server/src/util/StringFilter.ts deleted file mode 100644 index 80b573d..0000000 --- a/server/src/util/StringFilter.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { QueryMode } from "./QueryMode"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, -}) -export class StringFilter { - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - equals?: string; - - @ApiProperty({ - required: false, - type: [String], - }) - @IsOptional() - @Field(() => [String], { - nullable: true, - }) - @Type(() => String) - in?: string[]; - - @ApiProperty({ - required: false, - type: [String], - }) - @IsOptional() - @Field(() => [String], { - nullable: true, - }) - @Type(() => String) - notIn?: string[]; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - lt?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - lte?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - gt?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - gte?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - contains?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - startsWith?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - endsWith?: string; - - @ApiProperty({ - required: false, - enum: ["Default", "Insensitive"], - }) - @IsOptional() - @Field(() => QueryMode, { - nullable: true, - }) - mode?: QueryMode; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - not?: string; -} diff --git a/server/src/util/StringNullableFilter.ts b/server/src/util/StringNullableFilter.ts deleted file mode 100644 index 01b399c..0000000 --- a/server/src/util/StringNullableFilter.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Field, InputType } from "@nestjs/graphql"; -import { QueryMode } from "./QueryMode"; -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional } from "class-validator"; -import { Type } from "class-transformer"; - -@InputType({ - isAbstract: true, -}) -export class StringNullableFilter { - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - equals?: string | null; - - @ApiProperty({ - required: false, - type: [String], - }) - @IsOptional() - @Field(() => [String], { - nullable: true, - }) - @Type(() => String) - in?: string[] | null; - - @ApiProperty({ - required: false, - type: [String], - }) - @IsOptional() - @Field(() => [String], { - nullable: true, - }) - @Type(() => String) - notIn?: string[] | null; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - lt?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - lte?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - gt?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - gte?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - contains?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - startsWith?: string; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - endsWith?: string; - - @ApiProperty({ - required: false, - enum: ["Default", "Insensitive"], - }) - @IsOptional() - @Field(() => QueryMode, { - nullable: true, - }) - mode?: QueryMode; - - @ApiProperty({ - required: false, - type: String, - }) - @IsOptional() - @Field(() => String, { - nullable: true, - }) - @Type(() => String) - not?: string; -} diff --git a/server/src/validators/index.ts b/server/src/validators/index.ts deleted file mode 100644 index 7f62d84..0000000 --- a/server/src/validators/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./is-json-value-validator"; diff --git a/server/src/validators/is-json-value-validator.spec.ts b/server/src/validators/is-json-value-validator.spec.ts deleted file mode 100644 index 5a77824..0000000 --- a/server/src/validators/is-json-value-validator.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { validate, ValidationError } from "class-validator"; -import { IsJSONValue } from "./is-json-value-validator"; - -class TestClass { - @IsJSONValue() - jsonProperty: unknown; -} - -describe("IsJSONValue", () => { - it("should validate a valid JSON string", async () => { - const testObj = new TestClass(); - testObj.jsonProperty = '{"name": "John", "age": 30}'; - const errors: ValidationError[] = await validate(testObj); - expect(errors.length).toBe(0); - }); - - it("should not validate an invalid JSON string", async () => { - const testObj = new TestClass(); - testObj.jsonProperty = '{name: "John", age: 30}'; - const errors: ValidationError[] = await validate(testObj); - expect(errors.length).toBe(1); - }); - - it("should not validate an invalid JSON string", async () => { - const testObj = new TestClass(); - testObj.jsonProperty = "John"; - const errors: ValidationError[] = await validate(testObj); - expect(errors.length).toBe(1); - }); - - it("should validate a valid JSON object", async () => { - const testObj = new TestClass(); - testObj.jsonProperty = { name: "John", age: 30 }; - const errors: ValidationError[] = await validate(testObj); - expect(errors.length).toBe(0); - }); - - it("should validate a valid JSON array", async () => { - const testObj = new TestClass(); - testObj.jsonProperty = ["John", "30"]; - const errors: ValidationError[] = await validate(testObj); - expect(errors.length).toBe(0); - }); -}); diff --git a/server/src/validators/is-json-value-validator.ts b/server/src/validators/is-json-value-validator.ts deleted file mode 100644 index 1002540..0000000 --- a/server/src/validators/is-json-value-validator.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { - ValidationArguments, - registerDecorator, - ValidationOptions, -} from "class-validator"; -import isJSONValidator from "validator/lib/isJSON"; - -export function IsJSONValue(validationOptions?: ValidationOptions) { - return function (object: Record, propertyName: string) { - registerDecorator({ - name: "IsJSONValue", - target: object.constructor, - propertyName: propertyName, - options: validationOptions, - validator: { - validate(value: any, args: ValidationArguments) { - if (typeof value === "string") { - return isJSONValidator(value); - } - - return isJSONValidator(JSON.stringify(value)); - }, - defaultMessage(args: ValidationArguments): string { - return `${args.property} must be a valid json`; - }, - }, - }); - }; -} diff --git a/server/tsconfig.build.json b/server/tsconfig.build.json deleted file mode 100644 index e579401..0000000 --- a/server/tsconfig.build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["node_modules", "prisma", "test", "dist", "**/*spec.ts", "admin"] -} diff --git a/server/tsconfig.json b/server/tsconfig.json deleted file mode 100644 index f6c463b..0000000 --- a/server/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./", - "module": "commonjs", - "declaration": false, - "removeComments": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es2022", - "lib": ["es2023"], - "sourceMap": true, - "outDir": "./dist", - "incremental": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "strict": true, - "paths": { - "@app/custom-validators": ["src/validators"] - } - }, - "include": ["src"] -}