From 6425691e543a689c2ea75d22ee4a453288f54da5 Mon Sep 17 00:00:00 2001 From: "amplication[bot]" Date: Tue, 30 Apr 2024 13:25:16 +0000 Subject: [PATCH 1/4] Amplication build # clvmf6xae1oea51ucb8pgbm5i Commit message: update database. Build URL: [https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmf6xae1oea51ucb8pgbm5i](https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmf6xae1oea51ucb8pgbm5i) --- .github/workflows/cd-tik-stock-aws-ecs.yaml | 69 ++++++ .github/workflows/ci-tik-stock.yaml | 36 +++ .../configuration/cd-tik-stock-aws-ecs.json | 58 +++++ server/.env | 15 +- server/.eslintignore | 7 + server/.eslintrc | 36 ++- server/.prettierignore | 18 +- server/.prettierrc.json | 6 +- server/README.md | 2 +- server/docker-compose.yml | 3 + server/nest-cli.json | 6 +- server/package.json | 83 +++---- server/prisma/schema.prisma | 18 +- server/scripts/seed.ts | 2 - server/src/app.module.ts | 24 +- server/src/auth/IAuthStrategy.ts | 1 + server/src/auth/abac.util.ts | 7 +- server/src/auth/acl.module.ts | 3 +- server/src/auth/auth.module.ts | 7 +- server/src/auth/auth.service.spec.ts | 2 +- server/src/auth/auth.service.ts | 2 +- server/src/auth/gqlDefaultAuth.guard.ts | 4 +- server/src/auth/jwt/base/jwt.strategy.base.ts | 2 +- server/src/auth/jwt/jwt.strategy.ts | 4 +- server/src/auth/jwt/jwtSecretFactory.ts | 9 +- server/src/auth/token.service.ts | 4 +- server/src/constants.ts | 2 +- server/src/grants.json | 68 +++--- server/src/logger/logger.config.ts | 41 ++++ server/src/logger/logger.module.ts | 16 ++ server/src/main.ts | 9 +- server/src/prisma.util.ts | 5 +- .../base/secretsManager.service.base.spec.ts | 16 +- .../base/secretsManager.service.base.ts | 10 +- .../secrets/secretsManagerFactory.ts | 55 +++++ .../providers/secrets/secretsNameKey.enum.ts | 6 + .../base/stockField.controller.base.spec.ts | 9 +- .../base/stockField.controller.base.ts | 37 ++-- .../stockField/base/stockField.module.base.ts | 5 +- .../base/stockField.resolver.base.ts | 24 +- .../base/stockField.service.base.ts | 28 +-- .../stockFundamental.controller.base.spec.ts | 9 +- .../base/stockFundamental.controller.base.ts | 39 ++-- .../base/stockFundamental.module.base.ts | 5 +- .../base/stockFundamental.resolver.base.ts | 24 +- .../base/stockFundamental.service.base.ts | 33 +-- ...undamentalsHistory.controller.base.spec.ts | 9 +- ...tockFundamentalsHistory.controller.base.ts | 37 ++-- .../stockFundamentalsHistory.module.base.ts | 5 +- .../stockFundamentalsHistory.resolver.base.ts | 24 +- .../stockFundamentalsHistory.service.base.ts | 43 ++-- server/src/strategy/base/Strategy.ts | 2 +- .../src/strategy/base/StrategyCreateInput.ts | 2 +- .../src/strategy/base/StrategyUpdateInput.ts | 2 +- .../base/strategy.controller.base.spec.ts | 9 +- .../strategy/base/strategy.controller.base.ts | 39 ++-- .../src/strategy/base/strategy.module.base.ts | 5 +- .../strategy/base/strategy.resolver.base.ts | 28 ++- .../strategy/base/strategy.service.base.ts | 34 +-- server/src/swagger/swagger.css | 1 + .../src/tests/auth/jwt/jwt.strategy.spec.ts | 10 +- server/src/user/base/User.ts | 29 +-- server/src/user/base/UserCreateInput.ts | 46 ++-- server/src/user/base/UserOrderByInput.ts | 19 +- server/src/user/base/UserUpdateInput.ts | 46 ++-- server/src/user/base/UserWhereInput.ts | 25 +-- .../user/base/user.controller.base.spec.ts | 17 +- server/src/user/base/user.controller.base.ts | 60 +++-- server/src/user/base/user.module.base.ts | 5 +- server/src/user/base/user.resolver.base.ts | 26 +-- server/src/user/base/user.service.base.ts | 34 +-- server/terraform/backend.tf | 7 + server/terraform/ecr-tik-stock.tf | 28 +++ server/terraform/ecs-tik-stock.tf | 207 ++++++++++++++++++ server/terraform/main.tf | 22 ++ server/terraform/outputs.tf | 175 +++++++++++++++ server/terraform/provider.tf | 10 + server/terraform/rds-tik-stock.tf | 123 +++++++++++ server/terraform/variables.tf | 0 server/terraform/vpc.tf | 22 ++ server/tsconfig.json | 9 +- 81 files changed, 1447 insertions(+), 582 deletions(-) create mode 100644 .github/workflows/cd-tik-stock-aws-ecs.yaml create mode 100644 .github/workflows/ci-tik-stock.yaml create mode 100644 .github/workflows/configuration/cd-tik-stock-aws-ecs.json create mode 100644 server/.eslintignore create mode 100644 server/src/logger/logger.config.ts create mode 100644 server/src/logger/logger.module.ts create mode 100644 server/src/providers/secrets/secretsManagerFactory.ts create mode 100644 server/src/providers/secrets/secretsNameKey.enum.ts create mode 100644 server/terraform/backend.tf create mode 100644 server/terraform/ecr-tik-stock.tf create mode 100644 server/terraform/ecs-tik-stock.tf create mode 100644 server/terraform/main.tf create mode 100644 server/terraform/outputs.tf create mode 100644 server/terraform/provider.tf create mode 100644 server/terraform/rds-tik-stock.tf create mode 100644 server/terraform/variables.tf create mode 100644 server/terraform/vpc.tf diff --git a/.github/workflows/cd-tik-stock-aws-ecs.yaml b/.github/workflows/cd-tik-stock-aws-ecs.yaml new file mode 100644 index 0000000..a8be6ed --- /dev/null +++ b/.github/workflows/cd-tik-stock-aws-ecs.yaml @@ -0,0 +1,69 @@ +# Introduction: +# +# This workflow is responsible for both creating and pushing the container image of the generated service to +# Amazon Elastic Container Registry (ECR), aswell as rendering and deploying an task definition to an Amazon +# Elastic Container Service (ECS) cluster. Lastly the execution of a task definition requires as IAM role which +# can be consumed. + +name: tik-stock-deploy-to-aws-ecs +concurrency: ${{ github.ref }} + +on: + workflow_dispatch: {} + pull_request: + types: [closed] + +env: + AWS_REGION: eu-west-1 + ECR_REPOSITORY: repository-name + ECS_SERVICE: tik-stock + ECS_CLUSTER: development-cluster + ECS_TASK_DEFINITION: .github/workflows/configuration/cd-tik-stock-aws-ecs.json + CONTAINER_NAME: tik-stock + +jobs: + package: + name: deploy + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: login to amazon ecr + id: registry + uses: aws-actions/amazon-ecr-login@v2 + + - name: build, tag and push image + id: image + env: + ECR_REGISTRY: ${{ steps.registry.outputs.registry }} + IMAGE_TAG: ${{github.sha}} + run: | + docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG server + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT + + # https://github.com/aws-actions/amazon-ecs-render-task-definition + - name: render amazon ecs task definition + id: task-definition + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: ${{ env.ECS_TASK_DEFINITION }} + container-name: ${{ env.CONTAINER_NAME }} + image: ${{ steps.image.outputs.image }} + + # https://github.com/aws-actions/amazon-ecs-deploy-task-definition + - name: deploy amazon ecs task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-definition.outputs.task-definition }} + service: ${{ env.ECS_SERVICE }} + cluster: ${{ env.ECS_CLUSTER }} + wait-for-service-stability: false diff --git a/.github/workflows/ci-tik-stock.yaml b/.github/workflows/ci-tik-stock.yaml new file mode 100644 index 0000000..a3a40e1 --- /dev/null +++ b/.github/workflows/ci-tik-stock.yaml @@ -0,0 +1,36 @@ +name: continuous integration - tik-stock + +concurrency: + group: tik-stock + cancel-in-progress: true + +on: + workflow_dispatch: + push: + branches: ["*"] + paths: ["server"] + +jobs: + continuous-integration: + name: continuous integration + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup node.js + uses: actions/setup-node@v3 + with: + node-version: 18.x + + - name: install dependencies + run: npm install + working-directory: server + + - name: build + run: npm run build + working-directory: server + + - name: test + run: npm test + working-directory: server diff --git a/.github/workflows/configuration/cd-tik-stock-aws-ecs.json b/.github/workflows/configuration/cd-tik-stock-aws-ecs.json new file mode 100644 index 0000000..67d69a6 --- /dev/null +++ b/.github/workflows/configuration/cd-tik-stock-aws-ecs.json @@ -0,0 +1,58 @@ +{ + "family": "tik-stock", + "containerDefinitions": [ + { + "name": "tik-stock", + "image": "012345678901.dkr.ecr.eu-west-1.amazonaws.com/repository-name:latest", + "essential": true, + "portMappings": [ + { + "name": "tik-stock-3000-tcp", + "containerPort": 3000, + "hostPort": 3000, + "protocol": "tcp" + } + ], + "secrets": [ + { + "name": "BCRYPT_SALT", + "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:BCRYPT_SALT::" + }, + { + "name": "JWT_EXPIRATION", + "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:JWT_EXPIRATION::" + }, + { + "name": "JWT_SECRET_KEY", + "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:JWT_SECRET_KEY::" + }, + { + "name": "DB_URL", + "valueFrom": "arn:aws:secretsmanager:eu-west-1:012345678901:secret:secret-name:DB_URL::" + } + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-create-group": "true", + "awslogs-group": "/ecs/tik-stock", + "awslogs-region": "eu-west-1", + "awslogs-stream-prefix": "ecs" + } + }, + "mountPoints": [], + "volumesFrom": [] + } + ], + "executionRoleArn": "arn:aws:iam::012345678901:role/task-execution-role-name", + "networkMode": "awsvpc", + "requiresCompatibilities": [ + "FARGATE" + ], + "cpu": "1024", + "memory": "2048", + "runtimePlatform": { + "cpuArchitecture": "X86_64", + "operatingSystemFamily": "LINUX" + } +} \ No newline at end of file diff --git a/server/.env b/server/.env index a10223b..b936510 100644 --- a/server/.env +++ b/server/.env @@ -1,10 +1,15 @@ +AWS_REGION=us-east-1 BCRYPT_SALT=10 COMPOSE_PROJECT_NAME=amp_cl8axttc7131562901h8ghsnt7b9 -PORT=3000 -DB_URL=postgres://admin:admin@localhost:5432/my-db -DB_USER=admin +DB_NAME=my-db DB_PASSWORD=admin DB_PORT=5432 -DB_NAME=my-db +DB_URL=postgres://admin:admin@localhost:5432/my-db +DB_USER=admin +JWT_EXPIRATION=2d JWT_SECRET_KEY=Change_ME!!! -JWT_EXPIRATION=2d \ No newline at end of file +LOG_LEVEL=info +LOG_REQUEST=false +PINO_PRETTY=false +PORT=3000 +SERVICE_NAME=TikStock \ No newline at end of file diff --git a/server/.eslintignore b/server/.eslintignore new file mode 100644 index 0000000..883542a --- /dev/null +++ b/server/.eslintignore @@ -0,0 +1,7 @@ +# Add further files to ignore here as needed + +node_modules/ +dist/ +prisma/migrations/ +package-lock.json +coverage/ \ No newline at end of file diff --git a/server/.eslintrc b/server/.eslintrc index 4a452c2..96c7f9e 100644 --- a/server/.eslintrc +++ b/server/.eslintrc @@ -1,29 +1,23 @@ { - "env": { - "es2021": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": {} -, - "overrides": [ - { + "env": { + "es2021": true, + "node": true + }, + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "rules": {}, + "overrides": [ + { "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], "env": { "jest": true }, "rules": {} } - ] + ] } diff --git a/server/.prettierignore b/server/.prettierignore index e48f355..09b671a 100644 --- a/server/.prettierignore +++ b/server/.prettierignore @@ -1,5 +1,17 @@ -node_modules/ -dist/ +# Add further files to ignore here as needed + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build +/dist + +#Server Specific prisma/migrations/ package-lock.json -coverage/ \ No newline at end of file diff --git a/server/.prettierrc.json b/server/.prettierrc.json index 7cac555..0967ef4 100644 --- a/server/.prettierrc.json +++ b/server/.prettierrc.json @@ -1,5 +1 @@ -{ - "singleQuote": true, - "arrowParens": "avoid", - "trailingComma": "all" -} +{} diff --git a/server/README.md b/server/README.md index 6db8e75..bca0445 100644 --- a/server/README.md +++ b/server/README.md @@ -1,6 +1,6 @@

- amplication-logo + amplication-logo

diff --git a/server/docker-compose.yml b/server/docker-compose.yml index 6b231f2..bd2d5cd 100644 --- a/server/docker-compose.yml +++ b/server/docker-compose.yml @@ -11,9 +11,12 @@ services: BCRYPT_SALT: ${BCRYPT_SALT} JWT_SECRET_KEY: ${JWT_SECRET_KEY} JWT_EXPIRATION: ${JWT_EXPIRATION} + LOG_LEVEL: ${LOG_LEVEL} + SERVICE_NAME: ${SERVICE_NAME} DB_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME} depends_on: - migrate + restart: on-failure migrate: build: context: . diff --git a/server/nest-cli.json b/server/nest-cli.json index fe51713..b7b60ae 100644 --- a/server/nest-cli.json +++ b/server/nest-cli.json @@ -1,6 +1,10 @@ { "sourceRoot": "src", "compilerOptions": { - "assets": ["swagger"] + "assets": [ + { + "include": "swagger/**/*" + } + ] } } diff --git a/server/package.json b/server/package.json index 4bccc18..9ec4c46 100644 --- a/server/package.json +++ b/server/package.json @@ -10,69 +10,70 @@ "seed": "ts-node scripts/seed.ts", "db:migrate-save": "prisma migrate dev", "db:migrate-up": "prisma migrate deploy", - "db:clean": "ts-node scripts/clean.ts", + "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", - "format": "prettier --write .", "lint": "eslint './src/**/*.{ts, tsx}'", - "lint:fix": "eslint --fix './src/**/*.{ts, tsx}'" + "lint:fix": "eslint --fix './src/**/*.{ts, tsx}'", + "format": "prettier --write ." }, "dependencies": { - "@nestjs/common": "8.4.7", - "@nestjs/config": "1.1.5", - "@nestjs/core": "8.4.7", - "@nestjs/graphql": "9.1.2", - "@nestjs/platform-express": "8.4.7", - "@nestjs/serve-static": "2.2.2", - "@nestjs/swagger": "5.1.5", + "@apollo/server": "^4.9.4", + "@aws-sdk/client-secrets-manager": "^3.451.0", + "@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", - "@prisma/client": "4.6.1", - "apollo-server-express": "3.6.1", - "bcrypt": "5.0.1", + "bcrypt": "5.1.1", "class-transformer": "0.5.1", "class-validator": "0.14.0", - "dotenv": "^16.1.4", - "graphql": "15.7.2", + "dotenv": "16.3.1", + "graphql": "^16.8.1", "graphql-type-json": "0.3.2", - "nest-access-control": "2.0.3", - "nest-morgan": "1.0.1", + "nest-access-control": "^3.1.0", + "nestjs-pino": "^3.5.0", "npm-run-all": "4.1.5", - "reflect-metadata": "0.1.13", - "swagger-ui-express": "4.3.0", - "ts-node": "10.9.1", - "type-fest": "0.13.1", - "validator": "^13.9.0", - "@nestjs/jwt": "^10.0.2", - "@nestjs/passport": "^9.0.0", "passport": "0.6.0", "passport-http": "0.3.0", - "passport-jwt": "4.0.1" + "passport-jwt": "4.0.1", + "reflect-metadata": "0.1.13", + "ts-node": "10.9.2", + "type-fest": "2.19.0", + "validator": "13.11.0" }, "devDependencies": { - "@nestjs/cli": "8.2.5", - "@nestjs/testing": "8.4.7", - "@types/express": "4.17.9", - "@types/graphql-type-json": "0.3.2", - "@types/jest": "26.0.19", + "@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/supertest": "2.0.11", - "@types/validator": "^13.7.15", - "jest": "27.0.6", - "jest-mock-extended": "^2.0.4", - "prisma": "4.6.1", - "supertest": "4.0.2", - "ts-jest": "27.0.3", - "typescript": "4.3.5", - "prettier": "^2.8.0", "@types/passport-http": "0.3.9", - "@types/passport-jwt": "3.0.8", + "@types/passport-jwt": "3.0.10", + "@types/supertest": "^2.0.14", + "@types/validator": "^13.11.2", "@typescript-eslint/eslint-plugin": "^4.1.0", "@typescript-eslint/parser": "^4.1.0", - "eslint": "^7.0.0" + "eslint": "^7.0.0", + "jest": "^29.7.0", + "jest-mock-extended": "^3.0.5", + "prettier": "^2.8.0", + "prisma": "^5.4.2", + "supertest": "^6.3.3", + "ts-jest": "^29.1.1", + "typescript": "^5.4.3" }, "jest": { "preset": "ts-jest", diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 2e5a5a1..130e3d9 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -8,17 +8,16 @@ generator client { } model User { - createdAt DateTime @default(now()) - email String @unique + createdAt DateTime @default(now()) + email String @unique firstname String? - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) lastname String? - role EnumUserRole - strategy Strategy[] - updatedAt DateTime @updatedAt - username String @unique password String roles Json + strategy Strategy[] + updatedAt DateTime @updatedAt + username String? @unique } model StockFundamental { @@ -101,8 +100,3 @@ model StockField { @@map("StockFields") } - -enum EnumUserRole { - ADMIN - USER -} diff --git a/server/scripts/seed.ts b/server/scripts/seed.ts index 93e6df3..37e78aa 100644 --- a/server/scripts/seed.ts +++ b/server/scripts/seed.ts @@ -3,7 +3,6 @@ import { PrismaClient } from "@prisma/client"; import { customSeed } from "./customSeed"; import { Salt, parseSalt } from "../src/auth/password.service"; import { hash } from "bcrypt"; -import { EnumUserRole } from "../src/user/base/EnumUserRole"; if (require.main === module) { dotenv.config(); @@ -31,7 +30,6 @@ async function seed(bcryptSalt: Salt) { password: await hash("admin", bcryptSalt), roles: ["user"], email: "", - role: EnumUserRole.Admin, }; await client.user.upsert({ diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 775fb0a..42d83be 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -1,6 +1,4 @@ -import { Module, Scope } from "@nestjs/common"; -import { APP_INTERCEPTOR } from "@nestjs/core"; -import { MorganInterceptor, MorganModule } from "nest-morgan"; +import { Module } from "@nestjs/common"; import { UserModule } from "./user/user.module"; import { StockFundamentalModule } from "./stockFundamental/stockFundamental.module"; import { StockFundamentalsHistoryModule } from "./stockFundamentalsHistory/stockFundamentalsHistory.module"; @@ -9,17 +7,21 @@ import { StockFieldModule } from "./stockField/stockField.module"; import { HealthModule } from "./health/health.module"; import { PrismaModule } from "./prisma/prisma.module"; import { SecretsManagerModule } from "./providers/secrets/secretsManager.module"; -import { ConfigModule, ConfigService } from "@nestjs/config"; 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"; +import { LoggerModule } from "./logger/logger.module"; + @Module({ controllers: [], imports: [ + LoggerModule, ACLModule, AuthModule, UserModule, @@ -30,13 +32,13 @@ import { AuthModule } from "./auth/auth.module"; HealthModule, PrismaModule, SecretsManagerModule, - MorganModule, ConfigModule.forRoot({ isGlobal: true }), ServeStaticModule.forRootAsync({ useClass: ServeStaticOptionsService, }), - GraphQLModule.forRootAsync({ - useFactory: (configService) => { + GraphQLModule.forRootAsync({ + driver: ApolloDriver, + useFactory: (configService: ConfigService) => { const playground = configService.get("GRAPHQL_PLAYGROUND"); const introspection = configService.get("GRAPHQL_INTROSPECTION"); return { @@ -50,12 +52,6 @@ import { AuthModule } from "./auth/auth.module"; imports: [ConfigModule], }), ], - providers: [ - { - provide: APP_INTERCEPTOR, - scope: Scope.REQUEST, - useClass: MorganInterceptor("combined"), - }, - ], + providers: [], }) export class AppModule {} diff --git a/server/src/auth/IAuthStrategy.ts b/server/src/auth/IAuthStrategy.ts index 5db10cf..7406267 100644 --- a/server/src/auth/IAuthStrategy.ts +++ b/server/src/auth/IAuthStrategy.ts @@ -1,5 +1,6 @@ import { UserInfo } from "./UserInfo"; export interface IAuthStrategy { + // eslint-disable-next-line @typescript-eslint/no-explicit-any validate: (...any: any) => Promise; } diff --git a/server/src/auth/abac.util.ts b/server/src/auth/abac.util.ts index 7047513..2f0dcab 100644 --- a/server/src/auth/abac.util.ts +++ b/server/src/auth/abac.util.ts @@ -9,6 +9,11 @@ export function getInvalidAttributes( // eslint-disable-next-line @typescript-eslint/ban-types data: Object ): string[] { - const filteredData = permission.filter(data); + // 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 index eb90005..040e7e5 100644 --- a/server/src/auth/acl.module.ts +++ b/server/src/auth/acl.module.ts @@ -1,6 +1,5 @@ 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 diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts index 73c8725..d69fd95 100644 --- a/server/src/auth/auth.module.ts +++ b/server/src/auth/auth.module.ts @@ -2,9 +2,10 @@ 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 { JWT_EXPIRATION } from "../constants"; import { SecretsManagerModule } from "../providers/secrets/secretsManager.module"; import { SecretsManagerService } from "../providers/secrets/secretsManager.service"; +import { EnumSecretsNameKey } from "../providers/secrets/secretsNameKey.enum"; import { AuthController } from "./auth.controller"; import { AuthResolver } from "./auth.resolver"; import { AuthService } from "./auth.service"; @@ -25,7 +26,9 @@ import { UserModule } from "../user/user.module"; secretsService: SecretsManagerService, configService: ConfigService ) => { - const secret = await secretsService.getSecret(JWT_SECRET_KEY); + const secret = await secretsService.getSecret( + EnumSecretsNameKey.JwtSecretKey + ); const expiresIn = configService.get(JWT_EXPIRATION); if (!secret) { throw new Error("Didn't get a valid jwt secret"); diff --git a/server/src/auth/auth.service.spec.ts b/server/src/auth/auth.service.spec.ts index 72fd2d3..90b04f4 100644 --- a/server/src/auth/auth.service.spec.ts +++ b/server/src/auth/auth.service.spec.ts @@ -27,7 +27,7 @@ const USER: any = { const SIGN_TOKEN = "SIGN_TOKEN"; const authEntityService = { - findOne(args: { where: { username: string } }): any | null { + user(args: { where: { username: string } }): any | null { if (args.where.username === VALID_CREDENTIALS.username) { return USER; } diff --git a/server/src/auth/auth.service.ts b/server/src/auth/auth.service.ts index f5a74ba..9f6add2 100644 --- a/server/src/auth/auth.service.ts +++ b/server/src/auth/auth.service.ts @@ -17,7 +17,7 @@ export class AuthService { username: string, password: string ): Promise { - const user = await this.userService.findOne({ + const user = await this.userService.user({ where: { username }, }); if (user && (await this.passwordService.compare(password, user.password))) { diff --git a/server/src/auth/gqlDefaultAuth.guard.ts b/server/src/auth/gqlDefaultAuth.guard.ts index 17143e1..abebd93 100644 --- a/server/src/auth/gqlDefaultAuth.guard.ts +++ b/server/src/auth/gqlDefaultAuth.guard.ts @@ -1,13 +1,11 @@ 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 { + getRequest(context: ExecutionContext): Request { const ctx = GqlExecutionContext.create(context); return ctx.getContext<{ req: Request }>().req; } diff --git a/server/src/auth/jwt/base/jwt.strategy.base.ts b/server/src/auth/jwt/base/jwt.strategy.base.ts index 3bbc919..26da6a7 100644 --- a/server/src/auth/jwt/base/jwt.strategy.base.ts +++ b/server/src/auth/jwt/base/jwt.strategy.base.ts @@ -22,7 +22,7 @@ export class JwtStrategyBase async validate(payload: UserInfo): Promise { const { username } = payload; - const user = await this.userService.findOne({ + const user = await this.userService.user({ where: { username }, }); if (!user) { diff --git a/server/src/auth/jwt/jwt.strategy.ts b/server/src/auth/jwt/jwt.strategy.ts index 9e75f4c..13395e5 100644 --- a/server/src/auth/jwt/jwt.strategy.ts +++ b/server/src/auth/jwt/jwt.strategy.ts @@ -1,12 +1,12 @@ import { Inject, Injectable } from "@nestjs/common"; -import { JWT_SECRET_KEY } from "../../constants"; +import { JWT_SECRET_KEY_PROVIDER_NAME } from "../../constants"; import { JwtStrategyBase } from "./base/jwt.strategy.base"; import { UserService } from "../../user/user.service"; @Injectable() export class JwtStrategy extends JwtStrategyBase { constructor( - @Inject(JWT_SECRET_KEY) secretOrKey: string, + @Inject(JWT_SECRET_KEY_PROVIDER_NAME) secretOrKey: string, protected readonly userService: UserService ) { super(secretOrKey, userService); diff --git a/server/src/auth/jwt/jwtSecretFactory.ts b/server/src/auth/jwt/jwtSecretFactory.ts index 151e793..8ca4d74 100644 --- a/server/src/auth/jwt/jwtSecretFactory.ts +++ b/server/src/auth/jwt/jwtSecretFactory.ts @@ -1,12 +1,15 @@ -import { JWT_SECRET_KEY } from "../../constants"; +import { JWT_SECRET_KEY_PROVIDER_NAME } from "../../constants"; import { SecretsManagerService } from "../../providers/secrets/secretsManager.service"; +import { EnumSecretsNameKey } from "../../providers/secrets/secretsNameKey.enum"; export const jwtSecretFactory = { - provide: JWT_SECRET_KEY, + provide: JWT_SECRET_KEY_PROVIDER_NAME, useFactory: async ( secretsService: SecretsManagerService ): Promise => { - const secret = await secretsService.getSecret(JWT_SECRET_KEY); + const secret = await secretsService.getSecret( + EnumSecretsNameKey.JwtSecretKey + ); if (secret) { return secret; } diff --git a/server/src/auth/token.service.ts b/server/src/auth/token.service.ts index b102b72..2ee079c 100644 --- a/server/src/auth/token.service.ts +++ b/server/src/auth/token.service.ts @@ -1,7 +1,5 @@ -//@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/constants.ts b/server/src/constants.ts index 08f98bf..e131049 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -1,2 +1,2 @@ -export const JWT_SECRET_KEY = "JWT_SECRET_KEY"; +export const JWT_SECRET_KEY_PROVIDER_NAME = "JWT_SECRET_KEY"; export const JWT_EXPIRATION = "JWT_EXPIRATION"; diff --git a/server/src/grants.json b/server/src/grants.json index f4e1ae7..4010862 100644 --- a/server/src/grants.json +++ b/server/src/grants.json @@ -1,10 +1,4 @@ [ - { - "role": "user", - "resource": "User", - "action": "read:own", - "attributes": "*" - }, { "role": "admin", "resource": "User", @@ -14,7 +8,7 @@ { "role": "user", "resource": "User", - "action": "create:any", + "action": "read:own", "attributes": "*" }, { @@ -26,7 +20,7 @@ { "role": "user", "resource": "User", - "action": "update:any", + "action": "create:any", "attributes": "*" }, { @@ -38,7 +32,7 @@ { "role": "user", "resource": "User", - "action": "delete:any", + "action": "update:any", "attributes": "*" }, { @@ -50,7 +44,7 @@ { "role": "user", "resource": "User", - "action": "read:any", + "action": "delete:any", "attributes": "*" }, { @@ -61,8 +55,8 @@ }, { "role": "user", - "resource": "StockFundamental", - "action": "read:own", + "resource": "User", + "action": "read:any", "attributes": "*" }, { @@ -74,7 +68,7 @@ { "role": "user", "resource": "StockFundamental", - "action": "create:any", + "action": "read:own", "attributes": "*" }, { @@ -86,7 +80,7 @@ { "role": "user", "resource": "StockFundamental", - "action": "update:any", + "action": "create:any", "attributes": "*" }, { @@ -98,7 +92,7 @@ { "role": "user", "resource": "StockFundamental", - "action": "delete:any", + "action": "update:any", "attributes": "*" }, { @@ -110,7 +104,7 @@ { "role": "user", "resource": "StockFundamental", - "action": "read:any", + "action": "delete:any", "attributes": "*" }, { @@ -121,8 +115,8 @@ }, { "role": "user", - "resource": "StockFundamentalsHistory", - "action": "read:own", + "resource": "StockFundamental", + "action": "read:any", "attributes": "*" }, { @@ -134,7 +128,7 @@ { "role": "user", "resource": "StockFundamentalsHistory", - "action": "create:any", + "action": "read:own", "attributes": "*" }, { @@ -146,7 +140,7 @@ { "role": "user", "resource": "StockFundamentalsHistory", - "action": "update:any", + "action": "create:any", "attributes": "*" }, { @@ -158,7 +152,7 @@ { "role": "user", "resource": "StockFundamentalsHistory", - "action": "delete:any", + "action": "update:any", "attributes": "*" }, { @@ -170,7 +164,7 @@ { "role": "user", "resource": "StockFundamentalsHistory", - "action": "read:any", + "action": "delete:any", "attributes": "*" }, { @@ -181,8 +175,8 @@ }, { "role": "user", - "resource": "Strategy", - "action": "read:own", + "resource": "StockFundamentalsHistory", + "action": "read:any", "attributes": "*" }, { @@ -194,7 +188,7 @@ { "role": "user", "resource": "Strategy", - "action": "create:any", + "action": "read:own", "attributes": "*" }, { @@ -206,7 +200,7 @@ { "role": "user", "resource": "Strategy", - "action": "update:any", + "action": "create:any", "attributes": "*" }, { @@ -218,7 +212,7 @@ { "role": "user", "resource": "Strategy", - "action": "delete:any", + "action": "update:any", "attributes": "*" }, { @@ -230,7 +224,7 @@ { "role": "user", "resource": "Strategy", - "action": "read:any", + "action": "delete:any", "attributes": "*" }, { @@ -241,8 +235,8 @@ }, { "role": "user", - "resource": "StockField", - "action": "read:own", + "resource": "Strategy", + "action": "read:any", "attributes": "*" }, { @@ -254,7 +248,7 @@ { "role": "user", "resource": "StockField", - "action": "create:any", + "action": "read:own", "attributes": "*" }, { @@ -266,7 +260,7 @@ { "role": "user", "resource": "StockField", - "action": "update:any", + "action": "create:any", "attributes": "*" }, { @@ -278,7 +272,7 @@ { "role": "user", "resource": "StockField", - "action": "delete:any", + "action": "update:any", "attributes": "*" }, { @@ -290,7 +284,7 @@ { "role": "user", "resource": "StockField", - "action": "read:any", + "action": "delete:any", "attributes": "*" }, { @@ -298,5 +292,11 @@ "resource": "StockField", "action": "read:any", "attributes": "*" + }, + { + "role": "user", + "resource": "StockField", + "action": "read:any", + "attributes": "*" } ] diff --git a/server/src/logger/logger.config.ts b/server/src/logger/logger.config.ts new file mode 100644 index 0000000..aca2189 --- /dev/null +++ b/server/src/logger/logger.config.ts @@ -0,0 +1,41 @@ +import { ConfigService } from "@nestjs/config"; +import { Params } from "nestjs-pino"; + +const ADDITIONAL_LOG_PROPERTIES = {};; + +export const LoggerConfiguration = (configService: ConfigService): Params => { + const logLevel = configService.getOrThrow("LOG_LEVEL"); + const serviceName = configService.getOrThrow("SERVICE_NAME") ?? ""; + const sensitiveKeys = configService.get("SENSITIVE_KEYS")?.split(",") ?? []; + const logRequest = configService.get("LOG_REQUEST") === "true"; + const pinoPretty = configService.get("PINO_PRETTY") === "true"; + + const allowedLevels = ["fatal", "error", "warn", "info", "debug", "trace"]; + + if (!allowedLevels.includes(logLevel)) { + throw new Error( + `${logLevel} is not a valid log level. Check your LOG_LEVEL env variable.`, + ); + } + + return { + pinoHttp: { + level: logLevel, + transport: pinoPretty + ? { + target: "pino-pretty", + options: { + colorize: true, + ignore: "pid,hostname", + }, + } + : undefined, + redact: { + paths: logRequest ? sensitiveKeys : ["req", "res"], + remove: logRequest ? false : true, + censor: "********", + }, + mixin: () => ({ ...ADDITIONAL_LOG_PROPERTIES, serviceName }), + }, + }; +}; diff --git a/server/src/logger/logger.module.ts b/server/src/logger/logger.module.ts new file mode 100644 index 0000000..4288e9f --- /dev/null +++ b/server/src/logger/logger.module.ts @@ -0,0 +1,16 @@ +import { Module } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { LoggerModule as PinoLoggerModule } from "nestjs-pino"; +import { LoggerConfiguration } from "./logger.config"; + +@Module({ + imports: [ + PinoLoggerModule.forRootAsync({ + inject: [ConfigService], + useFactory: (config: ConfigService) => LoggerConfiguration(config) + }) + ] +}) +export class LoggerModule { + +} \ No newline at end of file diff --git a/server/src/main.ts b/server/src/main.ts index 474eead..977dbd9 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -10,10 +10,17 @@ import { swaggerSetupOptions, } from "./swagger"; +import { Logger } from "nestjs-pino"; + const { PORT = 3000 } = process.env; async function main() { - const app = await NestFactory.create(AppModule, { cors: true }); + const app = await NestFactory.create(AppModule, { + cors: true, + bufferLogs: true + }); + + app.useLogger(app.get(Logger)); app.setGlobalPrefix("api"); app.useGlobalPipes( diff --git a/server/src/prisma.util.ts b/server/src/prisma.util.ts index 8e0779c..029b98a 100644 --- a/server/src/prisma.util.ts +++ b/server/src/prisma.util.ts @@ -1,10 +1,9 @@ export const PRISMA_QUERY_INTERPRETATION_ERROR = "P2016"; export const PRISMA_RECORD_NOT_FOUND = "RecordNotFound"; -export function isRecordNotFoundError( - error: Error & { code?: string } -): boolean { +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) diff --git a/server/src/providers/secrets/base/secretsManager.service.base.spec.ts b/server/src/providers/secrets/base/secretsManager.service.base.spec.ts index eb4dfb1..f161172 100644 --- a/server/src/providers/secrets/base/secretsManager.service.base.spec.ts +++ b/server/src/providers/secrets/base/secretsManager.service.base.spec.ts @@ -1,6 +1,7 @@ import { ConfigService } from "@nestjs/config"; import { mock } from "jest-mock-extended"; import { SecretsManagerServiceBase } from "./secretsManager.service.base"; +import { EnumSecretsNameKey } from "../secretsNameKey.enum"; describe("Testing the secrets manager base class", () => { const SECRET_KEY = "SECRET_KEY"; @@ -16,7 +17,9 @@ describe("Testing the secrets manager base class", () => { //ARRANGE configService.get.mockReturnValue(SECRET_VALUE); //ACT - const result = await secretsManagerServiceBase.getSecret(SECRET_KEY); + const result = await secretsManagerServiceBase.getSecret( + SECRET_KEY as unknown as EnumSecretsNameKey + ); //ASSERT expect(result).toBe(SECRET_VALUE); }); @@ -24,16 +27,15 @@ describe("Testing the secrets manager base class", () => { //ARRANGE configService.get.mockReturnValue(undefined); //ACT - const result = await secretsManagerServiceBase.getSecret(SECRET_KEY); + const result = await secretsManagerServiceBase.getSecret( + SECRET_KEY as unknown as EnumSecretsNameKey + ); //ASSERT expect(result).toBeNull(); }); - it("should throw error if dont get key", () => { - return expect(secretsManagerServiceBase.getSecret("")).rejects.toThrow(); - }); - it("should throw an exeption if getting null key", () => { + it("should throw an exception if getting null key", () => { return expect( - secretsManagerServiceBase.getSecret(null as unknown as string) + secretsManagerServiceBase.getSecret(null as unknown as EnumSecretsNameKey) ).rejects.toThrow(); }); }); diff --git a/server/src/providers/secrets/base/secretsManager.service.base.ts b/server/src/providers/secrets/base/secretsManager.service.base.ts index 18a340b..340818c 100644 --- a/server/src/providers/secrets/base/secretsManager.service.base.ts +++ b/server/src/providers/secrets/base/secretsManager.service.base.ts @@ -1,16 +1,14 @@ import { ConfigService } from "@nestjs/config"; +import { EnumSecretsNameKey } from "../secretsNameKey.enum"; export interface ISecretsManager { - getSecret: (key: string) => Promise; + getSecret: (key: EnumSecretsNameKey) => 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); + async getSecret(key: EnumSecretsNameKey): Promise { + const value = this.configService.get(key.toString()); if (value) { return value; } diff --git a/server/src/providers/secrets/secretsManagerFactory.ts b/server/src/providers/secrets/secretsManagerFactory.ts new file mode 100644 index 0000000..1b72fc7 --- /dev/null +++ b/server/src/providers/secrets/secretsManagerFactory.ts @@ -0,0 +1,55 @@ +import { ConfigService } from "@nestjs/config"; +import { + GetSecretValueCommand, + SecretsManagerClient, +} from "@aws-sdk/client-secrets-manager"; +import { Logger } from "@nestjs/common"; +import { EnumSecretsNameKey } from "./secretsNameKey.enum"; + +export const secretsManagerFactory = { + provide: "AWS_SECRETS_MANAGER", + useFactory: async (configService: ConfigService) => { + const logger = new Logger(); + + const client = new SecretsManagerClient({ + region: configService.get("AWS_REGION"), + }); + + var secrets: Partial> = {}; + + for (const path of Object.values(EnumSecretsNameKey)) { + const [secret_id, secret_name] = path.toString().split(":"); + + try { + const response = await client.send( + new GetSecretValueCommand({ SecretId: secret_id }), + ); + + const secrets_list: Record = JSON.parse( + response.SecretString + ? response.SecretString + : response.SecretBinary + ? new TextDecoder().decode(response.SecretBinary) + : "{}", + ); + + secrets = { + ...secrets, + [path.toString()]: secret_name + ? secrets_list[secret_name] + : secrets_list, + }; + } catch (err: unknown) { + if (err instanceof Error) { + logger.error( + `Error while loading secret named "${secret_name}" from secret id "${secret_id}" - ${err.message}`, + "SecretsManager", + ); + } + } + } + + return secrets; + }, + inject: [ConfigService], +}; diff --git a/server/src/providers/secrets/secretsNameKey.enum.ts b/server/src/providers/secrets/secretsNameKey.enum.ts new file mode 100644 index 0000000..e21a53a --- /dev/null +++ b/server/src/providers/secrets/secretsNameKey.enum.ts @@ -0,0 +1,6 @@ +export enum EnumSecretsNameKey { + JwtSecretKey = "JWT_SECRET_KEY", + SecretA = "/path/to:SecretA", + SecretB = "/path/to:SecretB", + Common = "/path/to/secrets/common" +} \ No newline at end of file diff --git a/server/src/stockField/base/stockField.controller.base.spec.ts b/server/src/stockField/base/stockField.controller.base.spec.ts index 309657a..98d412b 100644 --- a/server/src/stockField/base/stockField.controller.base.spec.ts +++ b/server/src/stockField/base/stockField.controller.base.spec.ts @@ -6,7 +6,6 @@ import { CallHandler, } from "@nestjs/common"; import request from "supertest"; -import { MorganModule } from "nest-morgan"; import { ACGuard } from "nest-access-control"; import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; import { ACLModule } from "../../auth/acl.module"; @@ -58,11 +57,11 @@ const FIND_ONE_RESULT = { }; const service = { - create() { + createStockField() { return CREATE_RESULT; }, - findMany: () => FIND_MANY_RESULT, - findOne: ({ where }: { where: { id: string } }) => { + stockFields: () => FIND_MANY_RESULT, + stockField: ({ where }: { where: { id: string } }) => { switch (where.id) { case existingId: return FIND_ONE_RESULT; @@ -116,7 +115,7 @@ describe("StockField", () => { }, ], controllers: [StockFieldController], - imports: [MorganModule.forRoot(), ACLModule], + imports: [ACLModule], }) .overrideGuard(DefaultAuthGuard) .useValue(basicAuthGuard) diff --git a/server/src/stockField/base/stockField.controller.base.ts b/server/src/stockField/base/stockField.controller.base.ts index c261e6d..447468c 100644 --- a/server/src/stockField/base/stockField.controller.base.ts +++ b/server/src/stockField/base/stockField.controller.base.ts @@ -22,11 +22,10 @@ import { StockFieldService } from "../stockField.service"; import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; import { StockFieldCreateInput } from "./StockFieldCreateInput"; -import { StockFieldWhereInput } from "./StockFieldWhereInput"; -import { StockFieldWhereUniqueInput } from "./StockFieldWhereUniqueInput"; +import { StockField } from "./StockField"; import { StockFieldFindManyArgs } from "./StockFieldFindManyArgs"; +import { StockFieldWhereUniqueInput } from "./StockFieldWhereUniqueInput"; import { StockFieldUpdateInput } from "./StockFieldUpdateInput"; -import { StockField } from "./StockField"; @swagger.ApiBearerAuth() @common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) @@ -38,9 +37,6 @@ export class StockFieldControllerBase { @common.UseInterceptors(AclValidateRequestInterceptor) @common.Post() @swagger.ApiCreatedResponse({ type: StockField }) - @swagger.ApiBody({ - type: StockFieldCreateInput, - }) @nestAccessControl.UseRoles({ resource: "StockField", action: "create", @@ -49,10 +45,13 @@ export class StockFieldControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async create( + @swagger.ApiBody({ + type: StockFieldCreateInput, + }) + async createStockField( @common.Body() data: StockFieldCreateInput ): Promise { - return await this.service.create({ + return await this.service.createStockField({ data: data, select: { createdAt: true, @@ -78,9 +77,9 @@ export class StockFieldControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findMany(@common.Req() request: Request): Promise { + async stockFields(@common.Req() request: Request): Promise { const args = plainToClass(StockFieldFindManyArgs, request.query); - return this.service.findMany({ + return this.service.stockFields({ ...args, select: { createdAt: true, @@ -106,10 +105,10 @@ export class StockFieldControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findOne( + async stockField( @common.Param() params: StockFieldWhereUniqueInput ): Promise { - const result = await this.service.findOne({ + const result = await this.service.stockField({ where: params, select: { createdAt: true, @@ -133,9 +132,6 @@ export class StockFieldControllerBase { @common.Patch("/:id") @swagger.ApiOkResponse({ type: StockField }) @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) - @swagger.ApiBody({ - type: StockFieldUpdateInput, - }) @nestAccessControl.UseRoles({ resource: "StockField", action: "update", @@ -144,12 +140,15 @@ export class StockFieldControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async update( + @swagger.ApiBody({ + type: StockFieldUpdateInput, + }) + async updateStockField( @common.Param() params: StockFieldWhereUniqueInput, @common.Body() data: StockFieldUpdateInput ): Promise { try { - return await this.service.update({ + return await this.service.updateStockField({ where: params, data: data, select: { @@ -183,11 +182,11 @@ export class StockFieldControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async delete( + async deleteStockField( @common.Param() params: StockFieldWhereUniqueInput ): Promise { try { - return await this.service.delete({ + return await this.service.deleteStockField({ where: params, select: { createdAt: true, diff --git a/server/src/stockField/base/stockField.module.base.ts b/server/src/stockField/base/stockField.module.base.ts index a8f84b1..e49bad6 100644 --- a/server/src/stockField/base/stockField.module.base.ts +++ b/server/src/stockField/base/stockField.module.base.ts @@ -10,10 +10,9 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { Module } from "@nestjs/common"; -import { MorganModule } from "nest-morgan"; import { ACLModule } from "../../auth/acl.module"; @Module({ - imports: [ACLModule, MorganModule], - exports: [ACLModule, MorganModule], + imports: [ACLModule], + exports: [ACLModule], }) export class StockFieldModuleBase {} diff --git a/server/src/stockField/base/stockField.resolver.base.ts b/server/src/stockField/base/stockField.resolver.base.ts index a956b81..033b3d6 100644 --- a/server/src/stockField/base/stockField.resolver.base.ts +++ b/server/src/stockField/base/stockField.resolver.base.ts @@ -10,7 +10,7 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import * as graphql from "@nestjs/graphql"; -import * as apollo from "apollo-server-express"; +import { GraphQLError } from "graphql"; import { isRecordNotFoundError } from "../../prisma.util"; import { MetaQueryPayload } from "../../util/MetaQueryPayload"; import * as nestAccessControl from "nest-access-control"; @@ -19,13 +19,13 @@ 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 { CreateStockFieldArgs } from "./CreateStockFieldArgs"; -import { UpdateStockFieldArgs } from "./UpdateStockFieldArgs"; -import { DeleteStockFieldArgs } from "./DeleteStockFieldArgs"; +import { StockField } from "./StockField"; import { StockFieldCountArgs } from "./StockFieldCountArgs"; import { StockFieldFindManyArgs } from "./StockFieldFindManyArgs"; import { StockFieldFindUniqueArgs } from "./StockFieldFindUniqueArgs"; -import { StockField } from "./StockField"; +import { CreateStockFieldArgs } from "./CreateStockFieldArgs"; +import { UpdateStockFieldArgs } from "./UpdateStockFieldArgs"; +import { DeleteStockFieldArgs } from "./DeleteStockFieldArgs"; import { StockFieldService } from "../stockField.service"; @common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) @graphql.Resolver(() => StockField) @@ -60,7 +60,7 @@ export class StockFieldResolverBase { async stockFields( @graphql.Args() args: StockFieldFindManyArgs ): Promise { - return this.service.findMany(args); + return this.service.stockFields(args); } @common.UseInterceptors(AclFilterResponseInterceptor) @@ -73,7 +73,7 @@ export class StockFieldResolverBase { async stockField( @graphql.Args() args: StockFieldFindUniqueArgs ): Promise { - const result = await this.service.findOne(args); + const result = await this.service.stockField(args); if (result === null) { return null; } @@ -90,7 +90,7 @@ export class StockFieldResolverBase { async createStockField( @graphql.Args() args: CreateStockFieldArgs ): Promise { - return await this.service.create({ + return await this.service.createStockField({ ...args, data: args.data, }); @@ -107,13 +107,13 @@ export class StockFieldResolverBase { @graphql.Args() args: UpdateStockFieldArgs ): Promise { try { - return await this.service.update({ + return await this.service.updateStockField({ ...args, data: args.data, }); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -131,10 +131,10 @@ export class StockFieldResolverBase { @graphql.Args() args: DeleteStockFieldArgs ): Promise { try { - return await this.service.delete(args); + return await this.service.deleteStockField(args); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } diff --git a/server/src/stockField/base/stockField.service.base.ts b/server/src/stockField/base/stockField.service.base.ts index 55bf1f1..a502bab 100644 --- a/server/src/stockField/base/stockField.service.base.ts +++ b/server/src/stockField/base/stockField.service.base.ts @@ -10,40 +10,40 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { PrismaService } from "../../prisma/prisma.service"; -import { Prisma, StockField } from "@prisma/client"; +import { Prisma, StockField as PrismaStockField } from "@prisma/client"; export class StockFieldServiceBase { constructor(protected readonly prisma: PrismaService) {} - async count( - args: Prisma.SelectSubset + async count( + args: Omit ): Promise { return this.prisma.stockField.count(args); } - async findMany( + async stockFields( args: Prisma.SelectSubset - ): Promise { - return this.prisma.stockField.findMany(args); + ): Promise { + return this.prisma.stockField.findMany(args); } - async findOne( + async stockField( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockField.findUnique(args); } - async create( + async createStockField( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockField.create(args); } - async update( + async updateStockField( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockField.update(args); } - async delete( + async deleteStockField( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockField.delete(args); } } diff --git a/server/src/stockFundamental/base/stockFundamental.controller.base.spec.ts b/server/src/stockFundamental/base/stockFundamental.controller.base.spec.ts index 8b753ba..ada5349 100644 --- a/server/src/stockFundamental/base/stockFundamental.controller.base.spec.ts +++ b/server/src/stockFundamental/base/stockFundamental.controller.base.spec.ts @@ -6,7 +6,6 @@ import { CallHandler, } from "@nestjs/common"; import request from "supertest"; -import { MorganModule } from "nest-morgan"; import { ACGuard } from "nest-access-control"; import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; import { ACLModule } from "../../auth/acl.module"; @@ -126,11 +125,11 @@ const FIND_ONE_RESULT = { }; const service = { - create() { + createStockFundamental() { return CREATE_RESULT; }, - findMany: () => FIND_MANY_RESULT, - findOne: ({ where }: { where: { id: string } }) => { + stockFundamentals: () => FIND_MANY_RESULT, + stockFundamental: ({ where }: { where: { id: string } }) => { switch (where.id) { case existingId: return FIND_ONE_RESULT; @@ -184,7 +183,7 @@ describe("StockFundamental", () => { }, ], controllers: [StockFundamentalController], - imports: [MorganModule.forRoot(), ACLModule], + imports: [ACLModule], }) .overrideGuard(DefaultAuthGuard) .useValue(basicAuthGuard) diff --git a/server/src/stockFundamental/base/stockFundamental.controller.base.ts b/server/src/stockFundamental/base/stockFundamental.controller.base.ts index 39383ad..10f75fb 100644 --- a/server/src/stockFundamental/base/stockFundamental.controller.base.ts +++ b/server/src/stockFundamental/base/stockFundamental.controller.base.ts @@ -22,11 +22,10 @@ import { StockFundamentalService } from "../stockFundamental.service"; import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; import { StockFundamentalCreateInput } from "./StockFundamentalCreateInput"; -import { StockFundamentalWhereInput } from "./StockFundamentalWhereInput"; -import { StockFundamentalWhereUniqueInput } from "./StockFundamentalWhereUniqueInput"; +import { StockFundamental } from "./StockFundamental"; import { StockFundamentalFindManyArgs } from "./StockFundamentalFindManyArgs"; +import { StockFundamentalWhereUniqueInput } from "./StockFundamentalWhereUniqueInput"; import { StockFundamentalUpdateInput } from "./StockFundamentalUpdateInput"; -import { StockFundamental } from "./StockFundamental"; @swagger.ApiBearerAuth() @common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) @@ -38,9 +37,6 @@ export class StockFundamentalControllerBase { @common.UseInterceptors(AclValidateRequestInterceptor) @common.Post() @swagger.ApiCreatedResponse({ type: StockFundamental }) - @swagger.ApiBody({ - type: StockFundamentalCreateInput, - }) @nestAccessControl.UseRoles({ resource: "StockFundamental", action: "create", @@ -49,10 +45,13 @@ export class StockFundamentalControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async create( + @swagger.ApiBody({ + type: StockFundamentalCreateInput, + }) + async createStockFundamental( @common.Body() data: StockFundamentalCreateInput ): Promise { - return await this.service.create({ + return await this.service.createStockFundamental({ data: data, select: { c5y: true, @@ -95,9 +94,11 @@ export class StockFundamentalControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findMany(@common.Req() request: Request): Promise { + async stockFundamentals( + @common.Req() request: Request + ): Promise { const args = plainToClass(StockFundamentalFindManyArgs, request.query); - return this.service.findMany({ + return this.service.stockFundamentals({ ...args, select: { c5y: true, @@ -140,10 +141,10 @@ export class StockFundamentalControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findOne( + async stockFundamental( @common.Param() params: StockFundamentalWhereUniqueInput ): Promise { - const result = await this.service.findOne({ + const result = await this.service.stockFundamental({ where: params, select: { c5y: true, @@ -184,9 +185,6 @@ export class StockFundamentalControllerBase { @common.Patch("/:id") @swagger.ApiOkResponse({ type: StockFundamental }) @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) - @swagger.ApiBody({ - type: StockFundamentalUpdateInput, - }) @nestAccessControl.UseRoles({ resource: "StockFundamental", action: "update", @@ -195,12 +193,15 @@ export class StockFundamentalControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async update( + @swagger.ApiBody({ + type: StockFundamentalUpdateInput, + }) + async updateStockFundamental( @common.Param() params: StockFundamentalWhereUniqueInput, @common.Body() data: StockFundamentalUpdateInput ): Promise { try { - return await this.service.update({ + return await this.service.updateStockFundamental({ where: params, data: data, select: { @@ -251,11 +252,11 @@ export class StockFundamentalControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async delete( + async deleteStockFundamental( @common.Param() params: StockFundamentalWhereUniqueInput ): Promise { try { - return await this.service.delete({ + return await this.service.deleteStockFundamental({ where: params, select: { c5y: true, diff --git a/server/src/stockFundamental/base/stockFundamental.module.base.ts b/server/src/stockFundamental/base/stockFundamental.module.base.ts index 178f7c6..91935f8 100644 --- a/server/src/stockFundamental/base/stockFundamental.module.base.ts +++ b/server/src/stockFundamental/base/stockFundamental.module.base.ts @@ -10,10 +10,9 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { Module } from "@nestjs/common"; -import { MorganModule } from "nest-morgan"; import { ACLModule } from "../../auth/acl.module"; @Module({ - imports: [ACLModule, MorganModule], - exports: [ACLModule, MorganModule], + imports: [ACLModule], + exports: [ACLModule], }) export class StockFundamentalModuleBase {} diff --git a/server/src/stockFundamental/base/stockFundamental.resolver.base.ts b/server/src/stockFundamental/base/stockFundamental.resolver.base.ts index f376743..77b24dc 100644 --- a/server/src/stockFundamental/base/stockFundamental.resolver.base.ts +++ b/server/src/stockFundamental/base/stockFundamental.resolver.base.ts @@ -10,7 +10,7 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import * as graphql from "@nestjs/graphql"; -import * as apollo from "apollo-server-express"; +import { GraphQLError } from "graphql"; import { isRecordNotFoundError } from "../../prisma.util"; import { MetaQueryPayload } from "../../util/MetaQueryPayload"; import * as nestAccessControl from "nest-access-control"; @@ -19,13 +19,13 @@ 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 { CreateStockFundamentalArgs } from "./CreateStockFundamentalArgs"; -import { UpdateStockFundamentalArgs } from "./UpdateStockFundamentalArgs"; -import { DeleteStockFundamentalArgs } from "./DeleteStockFundamentalArgs"; +import { StockFundamental } from "./StockFundamental"; import { StockFundamentalCountArgs } from "./StockFundamentalCountArgs"; import { StockFundamentalFindManyArgs } from "./StockFundamentalFindManyArgs"; import { StockFundamentalFindUniqueArgs } from "./StockFundamentalFindUniqueArgs"; -import { StockFundamental } from "./StockFundamental"; +import { CreateStockFundamentalArgs } from "./CreateStockFundamentalArgs"; +import { UpdateStockFundamentalArgs } from "./UpdateStockFundamentalArgs"; +import { DeleteStockFundamentalArgs } from "./DeleteStockFundamentalArgs"; import { StockFundamentalService } from "../stockFundamental.service"; @common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) @graphql.Resolver(() => StockFundamental) @@ -60,7 +60,7 @@ export class StockFundamentalResolverBase { async stockFundamentals( @graphql.Args() args: StockFundamentalFindManyArgs ): Promise { - return this.service.findMany(args); + return this.service.stockFundamentals(args); } @common.UseInterceptors(AclFilterResponseInterceptor) @@ -73,7 +73,7 @@ export class StockFundamentalResolverBase { async stockFundamental( @graphql.Args() args: StockFundamentalFindUniqueArgs ): Promise { - const result = await this.service.findOne(args); + const result = await this.service.stockFundamental(args); if (result === null) { return null; } @@ -90,7 +90,7 @@ export class StockFundamentalResolverBase { async createStockFundamental( @graphql.Args() args: CreateStockFundamentalArgs ): Promise { - return await this.service.create({ + return await this.service.createStockFundamental({ ...args, data: args.data, }); @@ -107,13 +107,13 @@ export class StockFundamentalResolverBase { @graphql.Args() args: UpdateStockFundamentalArgs ): Promise { try { - return await this.service.update({ + return await this.service.updateStockFundamental({ ...args, data: args.data, }); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -131,10 +131,10 @@ export class StockFundamentalResolverBase { @graphql.Args() args: DeleteStockFundamentalArgs ): Promise { try { - return await this.service.delete(args); + return await this.service.deleteStockFundamental(args); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } diff --git a/server/src/stockFundamental/base/stockFundamental.service.base.ts b/server/src/stockFundamental/base/stockFundamental.service.base.ts index 071abbd..4fa0719 100644 --- a/server/src/stockFundamental/base/stockFundamental.service.base.ts +++ b/server/src/stockFundamental/base/stockFundamental.service.base.ts @@ -10,40 +10,45 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { PrismaService } from "../../prisma/prisma.service"; -import { Prisma, StockFundamental } from "@prisma/client"; +import { + Prisma, + StockFundamental as PrismaStockFundamental, +} from "@prisma/client"; export class StockFundamentalServiceBase { constructor(protected readonly prisma: PrismaService) {} - async count( - args: Prisma.SelectSubset + async count( + args: Omit ): Promise { return this.prisma.stockFundamental.count(args); } - async findMany( + async stockFundamentals( args: Prisma.SelectSubset - ): Promise { - return this.prisma.stockFundamental.findMany(args); + ): Promise { + return this.prisma.stockFundamental.findMany( + args + ); } - async findOne( + async stockFundamental( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamental.findUnique(args); } - async create( + async createStockFundamental( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamental.create(args); } - async update( + async updateStockFundamental( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamental.update(args); } - async delete( + async deleteStockFundamental( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamental.delete(args); } } diff --git a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.spec.ts b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.spec.ts index 669fddb..debc8b1 100644 --- a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.spec.ts +++ b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.spec.ts @@ -6,7 +6,6 @@ import { CallHandler, } from "@nestjs/common"; import request from "supertest"; -import { MorganModule } from "nest-morgan"; import { ACGuard } from "nest-access-control"; import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; import { ACLModule } from "../../auth/acl.module"; @@ -126,11 +125,11 @@ const FIND_ONE_RESULT = { }; const service = { - create() { + createStockFundamentalsHistory() { return CREATE_RESULT; }, - findMany: () => FIND_MANY_RESULT, - findOne: ({ where }: { where: { id: string } }) => { + stockFundamentalsHistories: () => FIND_MANY_RESULT, + stockFundamentalsHistory: ({ where }: { where: { id: string } }) => { switch (where.id) { case existingId: return FIND_ONE_RESULT; @@ -184,7 +183,7 @@ describe("StockFundamentalsHistory", () => { }, ], controllers: [StockFundamentalsHistoryController], - imports: [MorganModule.forRoot(), ACLModule], + imports: [ACLModule], }) .overrideGuard(DefaultAuthGuard) .useValue(basicAuthGuard) diff --git a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.ts b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.ts index 5c45041..a81e1e9 100644 --- a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.ts +++ b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.controller.base.ts @@ -22,11 +22,10 @@ import { StockFundamentalsHistoryService } from "../stockFundamentalsHistory.ser import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; import { StockFundamentalsHistoryCreateInput } from "./StockFundamentalsHistoryCreateInput"; -import { StockFundamentalsHistoryWhereInput } from "./StockFundamentalsHistoryWhereInput"; -import { StockFundamentalsHistoryWhereUniqueInput } from "./StockFundamentalsHistoryWhereUniqueInput"; +import { StockFundamentalsHistory } from "./StockFundamentalsHistory"; import { StockFundamentalsHistoryFindManyArgs } from "./StockFundamentalsHistoryFindManyArgs"; +import { StockFundamentalsHistoryWhereUniqueInput } from "./StockFundamentalsHistoryWhereUniqueInput"; import { StockFundamentalsHistoryUpdateInput } from "./StockFundamentalsHistoryUpdateInput"; -import { StockFundamentalsHistory } from "./StockFundamentalsHistory"; @swagger.ApiBearerAuth() @common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) @@ -38,9 +37,6 @@ export class StockFundamentalsHistoryControllerBase { @common.UseInterceptors(AclValidateRequestInterceptor) @common.Post() @swagger.ApiCreatedResponse({ type: StockFundamentalsHistory }) - @swagger.ApiBody({ - type: StockFundamentalsHistoryCreateInput, - }) @nestAccessControl.UseRoles({ resource: "StockFundamentalsHistory", action: "create", @@ -49,10 +45,13 @@ export class StockFundamentalsHistoryControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async create( + @swagger.ApiBody({ + type: StockFundamentalsHistoryCreateInput, + }) + async createStockFundamentalsHistory( @common.Body() data: StockFundamentalsHistoryCreateInput ): Promise { - return await this.service.create({ + return await this.service.createStockFundamentalsHistory({ data: data, select: { c5y: true, @@ -95,14 +94,14 @@ export class StockFundamentalsHistoryControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findMany( + async stockFundamentalsHistories( @common.Req() request: Request ): Promise { const args = plainToClass( StockFundamentalsHistoryFindManyArgs, request.query ); - return this.service.findMany({ + return this.service.stockFundamentalsHistories({ ...args, select: { c5y: true, @@ -145,10 +144,10 @@ export class StockFundamentalsHistoryControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findOne( + async stockFundamentalsHistory( @common.Param() params: StockFundamentalsHistoryWhereUniqueInput ): Promise { - const result = await this.service.findOne({ + const result = await this.service.stockFundamentalsHistory({ where: params, select: { c5y: true, @@ -189,9 +188,6 @@ export class StockFundamentalsHistoryControllerBase { @common.Patch("/:id") @swagger.ApiOkResponse({ type: StockFundamentalsHistory }) @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) - @swagger.ApiBody({ - type: StockFundamentalsHistoryUpdateInput, - }) @nestAccessControl.UseRoles({ resource: "StockFundamentalsHistory", action: "update", @@ -200,12 +196,15 @@ export class StockFundamentalsHistoryControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async update( + @swagger.ApiBody({ + type: StockFundamentalsHistoryUpdateInput, + }) + async updateStockFundamentalsHistory( @common.Param() params: StockFundamentalsHistoryWhereUniqueInput, @common.Body() data: StockFundamentalsHistoryUpdateInput ): Promise { try { - return await this.service.update({ + return await this.service.updateStockFundamentalsHistory({ where: params, data: data, select: { @@ -256,11 +255,11 @@ export class StockFundamentalsHistoryControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async delete( + async deleteStockFundamentalsHistory( @common.Param() params: StockFundamentalsHistoryWhereUniqueInput ): Promise { try { - return await this.service.delete({ + return await this.service.deleteStockFundamentalsHistory({ where: params, select: { c5y: true, diff --git a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.module.base.ts b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.module.base.ts index 4eb782e..2fdc325 100644 --- a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.module.base.ts +++ b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.module.base.ts @@ -10,10 +10,9 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { Module } from "@nestjs/common"; -import { MorganModule } from "nest-morgan"; import { ACLModule } from "../../auth/acl.module"; @Module({ - imports: [ACLModule, MorganModule], - exports: [ACLModule, MorganModule], + imports: [ACLModule], + exports: [ACLModule], }) export class StockFundamentalsHistoryModuleBase {} diff --git a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.resolver.base.ts b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.resolver.base.ts index af4868a..2b37b36 100644 --- a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.resolver.base.ts +++ b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.resolver.base.ts @@ -10,7 +10,7 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import * as graphql from "@nestjs/graphql"; -import * as apollo from "apollo-server-express"; +import { GraphQLError } from "graphql"; import { isRecordNotFoundError } from "../../prisma.util"; import { MetaQueryPayload } from "../../util/MetaQueryPayload"; import * as nestAccessControl from "nest-access-control"; @@ -19,13 +19,13 @@ 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 { CreateStockFundamentalsHistoryArgs } from "./CreateStockFundamentalsHistoryArgs"; -import { UpdateStockFundamentalsHistoryArgs } from "./UpdateStockFundamentalsHistoryArgs"; -import { DeleteStockFundamentalsHistoryArgs } from "./DeleteStockFundamentalsHistoryArgs"; +import { StockFundamentalsHistory } from "./StockFundamentalsHistory"; import { StockFundamentalsHistoryCountArgs } from "./StockFundamentalsHistoryCountArgs"; import { StockFundamentalsHistoryFindManyArgs } from "./StockFundamentalsHistoryFindManyArgs"; import { StockFundamentalsHistoryFindUniqueArgs } from "./StockFundamentalsHistoryFindUniqueArgs"; -import { StockFundamentalsHistory } from "./StockFundamentalsHistory"; +import { CreateStockFundamentalsHistoryArgs } from "./CreateStockFundamentalsHistoryArgs"; +import { UpdateStockFundamentalsHistoryArgs } from "./UpdateStockFundamentalsHistoryArgs"; +import { DeleteStockFundamentalsHistoryArgs } from "./DeleteStockFundamentalsHistoryArgs"; import { StockFundamentalsHistoryService } from "../stockFundamentalsHistory.service"; @common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) @graphql.Resolver(() => StockFundamentalsHistory) @@ -60,7 +60,7 @@ export class StockFundamentalsHistoryResolverBase { async stockFundamentalsHistories( @graphql.Args() args: StockFundamentalsHistoryFindManyArgs ): Promise { - return this.service.findMany(args); + return this.service.stockFundamentalsHistories(args); } @common.UseInterceptors(AclFilterResponseInterceptor) @@ -73,7 +73,7 @@ export class StockFundamentalsHistoryResolverBase { async stockFundamentalsHistory( @graphql.Args() args: StockFundamentalsHistoryFindUniqueArgs ): Promise { - const result = await this.service.findOne(args); + const result = await this.service.stockFundamentalsHistory(args); if (result === null) { return null; } @@ -90,7 +90,7 @@ export class StockFundamentalsHistoryResolverBase { async createStockFundamentalsHistory( @graphql.Args() args: CreateStockFundamentalsHistoryArgs ): Promise { - return await this.service.create({ + return await this.service.createStockFundamentalsHistory({ ...args, data: args.data, }); @@ -107,13 +107,13 @@ export class StockFundamentalsHistoryResolverBase { @graphql.Args() args: UpdateStockFundamentalsHistoryArgs ): Promise { try { - return await this.service.update({ + return await this.service.updateStockFundamentalsHistory({ ...args, data: args.data, }); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -131,10 +131,10 @@ export class StockFundamentalsHistoryResolverBase { @graphql.Args() args: DeleteStockFundamentalsHistoryArgs ): Promise { try { - return await this.service.delete(args); + return await this.service.deleteStockFundamentalsHistory(args); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } diff --git a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.service.base.ts b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.service.base.ts index 85ccba8..75c88b1 100644 --- a/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.service.base.ts +++ b/server/src/stockFundamentalsHistory/base/stockFundamentalsHistory.service.base.ts @@ -10,40 +10,55 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { PrismaService } from "../../prisma/prisma.service"; -import { Prisma, StockFundamentalsHistory } from "@prisma/client"; +import { + Prisma, + StockFundamentalsHistory as PrismaStockFundamentalsHistory, +} from "@prisma/client"; export class StockFundamentalsHistoryServiceBase { constructor(protected readonly prisma: PrismaService) {} - async count( - args: Prisma.SelectSubset + async count( + args: Omit ): Promise { return this.prisma.stockFundamentalsHistory.count(args); } - async findMany( + async stockFundamentalsHistories< + T extends Prisma.StockFundamentalsHistoryFindManyArgs + >( args: Prisma.SelectSubset - ): Promise { - return this.prisma.stockFundamentalsHistory.findMany(args); + ): Promise { + return this.prisma.stockFundamentalsHistory.findMany( + args + ); } - async findOne( + async stockFundamentalsHistory< + T extends Prisma.StockFundamentalsHistoryFindUniqueArgs + >( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamentalsHistory.findUnique(args); } - async create( + async createStockFundamentalsHistory< + T extends Prisma.StockFundamentalsHistoryCreateArgs + >( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamentalsHistory.create(args); } - async update( + async updateStockFundamentalsHistory< + T extends Prisma.StockFundamentalsHistoryUpdateArgs + >( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamentalsHistory.update(args); } - async delete( + async deleteStockFundamentalsHistory< + T extends Prisma.StockFundamentalsHistoryDeleteArgs + >( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.stockFundamentalsHistory.delete(args); } } diff --git a/server/src/strategy/base/Strategy.ts b/server/src/strategy/base/Strategy.ts index 84a5ac6..3b13497 100644 --- a/server/src/strategy/base/Strategy.ts +++ b/server/src/strategy/base/Strategy.ts @@ -21,7 +21,7 @@ import { IsBoolean, } from "class-validator"; import { Type } from "class-transformer"; -import { IsJSONValue } from "@app/custom-validators"; +import { IsJSONValue } from "../../validators"; import { GraphQLJSON } from "graphql-type-json"; import { JsonValue } from "type-fest"; diff --git a/server/src/strategy/base/StrategyCreateInput.ts b/server/src/strategy/base/StrategyCreateInput.ts index 8871f2a..e7c7eca 100644 --- a/server/src/strategy/base/StrategyCreateInput.ts +++ b/server/src/strategy/base/StrategyCreateInput.ts @@ -19,7 +19,7 @@ import { IsBoolean, } from "class-validator"; import { Type } from "class-transformer"; -import { IsJSONValue } from "@app/custom-validators"; +import { IsJSONValue } from "../../validators"; import { GraphQLJSON } from "graphql-type-json"; import { InputJsonValue } from "../../types"; diff --git a/server/src/strategy/base/StrategyUpdateInput.ts b/server/src/strategy/base/StrategyUpdateInput.ts index 9d66504..af68020 100644 --- a/server/src/strategy/base/StrategyUpdateInput.ts +++ b/server/src/strategy/base/StrategyUpdateInput.ts @@ -19,7 +19,7 @@ import { IsBoolean, } from "class-validator"; import { Type } from "class-transformer"; -import { IsJSONValue } from "@app/custom-validators"; +import { IsJSONValue } from "../../validators"; import { GraphQLJSON } from "graphql-type-json"; import { InputJsonValue } from "../../types"; diff --git a/server/src/strategy/base/strategy.controller.base.spec.ts b/server/src/strategy/base/strategy.controller.base.spec.ts index 66006df..3d31953 100644 --- a/server/src/strategy/base/strategy.controller.base.spec.ts +++ b/server/src/strategy/base/strategy.controller.base.spec.ts @@ -6,7 +6,6 @@ import { CallHandler, } from "@nestjs/common"; import request from "supertest"; -import { MorganModule } from "nest-morgan"; import { ACGuard } from "nest-access-control"; import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; import { ACLModule } from "../../auth/acl.module"; @@ -54,11 +53,11 @@ const FIND_ONE_RESULT = { }; const service = { - create() { + createStrategy() { return CREATE_RESULT; }, - findMany: () => FIND_MANY_RESULT, - findOne: ({ where }: { where: { id: string } }) => { + strategies: () => FIND_MANY_RESULT, + strategy: ({ where }: { where: { id: string } }) => { switch (where.id) { case existingId: return FIND_ONE_RESULT; @@ -112,7 +111,7 @@ describe("Strategy", () => { }, ], controllers: [StrategyController], - imports: [MorganModule.forRoot(), ACLModule], + imports: [ACLModule], }) .overrideGuard(DefaultAuthGuard) .useValue(basicAuthGuard) diff --git a/server/src/strategy/base/strategy.controller.base.ts b/server/src/strategy/base/strategy.controller.base.ts index 505aea1..71d9f0c 100644 --- a/server/src/strategy/base/strategy.controller.base.ts +++ b/server/src/strategy/base/strategy.controller.base.ts @@ -22,11 +22,10 @@ import { StrategyService } from "../strategy.service"; import { AclValidateRequestInterceptor } from "../../interceptors/aclValidateRequest.interceptor"; import { AclFilterResponseInterceptor } from "../../interceptors/aclFilterResponse.interceptor"; import { StrategyCreateInput } from "./StrategyCreateInput"; -import { StrategyWhereInput } from "./StrategyWhereInput"; -import { StrategyWhereUniqueInput } from "./StrategyWhereUniqueInput"; +import { Strategy } from "./Strategy"; import { StrategyFindManyArgs } from "./StrategyFindManyArgs"; +import { StrategyWhereUniqueInput } from "./StrategyWhereUniqueInput"; import { StrategyUpdateInput } from "./StrategyUpdateInput"; -import { Strategy } from "./Strategy"; @swagger.ApiBearerAuth() @common.UseGuards(defaultAuthGuard.DefaultAuthGuard, nestAccessControl.ACGuard) @@ -38,9 +37,6 @@ export class StrategyControllerBase { @common.UseInterceptors(AclValidateRequestInterceptor) @common.Post() @swagger.ApiCreatedResponse({ type: Strategy }) - @swagger.ApiBody({ - type: StrategyCreateInput, - }) @nestAccessControl.UseRoles({ resource: "Strategy", action: "create", @@ -49,8 +45,13 @@ export class StrategyControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async create(@common.Body() data: StrategyCreateInput): Promise { - return await this.service.create({ + @swagger.ApiBody({ + type: StrategyCreateInput, + }) + async createStrategy( + @common.Body() data: StrategyCreateInput + ): Promise { + return await this.service.createStrategy({ data: { ...data, @@ -91,9 +92,9 @@ export class StrategyControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findMany(@common.Req() request: Request): Promise { + async strategies(@common.Req() request: Request): Promise { const args = plainToClass(StrategyFindManyArgs, request.query); - return this.service.findMany({ + return this.service.strategies({ ...args, select: { author: { @@ -126,10 +127,10 @@ export class StrategyControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findOne( + async strategy( @common.Param() params: StrategyWhereUniqueInput ): Promise { - const result = await this.service.findOne({ + const result = await this.service.strategy({ where: params, select: { author: { @@ -160,9 +161,6 @@ export class StrategyControllerBase { @common.Patch("/:id") @swagger.ApiOkResponse({ type: Strategy }) @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) - @swagger.ApiBody({ - type: StrategyUpdateInput, - }) @nestAccessControl.UseRoles({ resource: "Strategy", action: "update", @@ -171,12 +169,15 @@ export class StrategyControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async update( + @swagger.ApiBody({ + type: StrategyUpdateInput, + }) + async updateStrategy( @common.Param() params: StrategyWhereUniqueInput, @common.Body() data: StrategyUpdateInput ): Promise { try { - return await this.service.update({ + return await this.service.updateStrategy({ where: params, data: { ...data, @@ -225,11 +226,11 @@ export class StrategyControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async delete( + async deleteStrategy( @common.Param() params: StrategyWhereUniqueInput ): Promise { try { - return await this.service.delete({ + return await this.service.deleteStrategy({ where: params, select: { author: { diff --git a/server/src/strategy/base/strategy.module.base.ts b/server/src/strategy/base/strategy.module.base.ts index 6e4449a..f2da48c 100644 --- a/server/src/strategy/base/strategy.module.base.ts +++ b/server/src/strategy/base/strategy.module.base.ts @@ -10,10 +10,9 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { Module } from "@nestjs/common"; -import { MorganModule } from "nest-morgan"; import { ACLModule } from "../../auth/acl.module"; @Module({ - imports: [ACLModule, MorganModule], - exports: [ACLModule, MorganModule], + imports: [ACLModule], + exports: [ACLModule], }) export class StrategyModuleBase {} diff --git a/server/src/strategy/base/strategy.resolver.base.ts b/server/src/strategy/base/strategy.resolver.base.ts index 0b2fec7..ee9b979 100644 --- a/server/src/strategy/base/strategy.resolver.base.ts +++ b/server/src/strategy/base/strategy.resolver.base.ts @@ -10,7 +10,7 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import * as graphql from "@nestjs/graphql"; -import * as apollo from "apollo-server-express"; +import { GraphQLError } from "graphql"; import { isRecordNotFoundError } from "../../prisma.util"; import { MetaQueryPayload } from "../../util/MetaQueryPayload"; import * as nestAccessControl from "nest-access-control"; @@ -19,13 +19,13 @@ 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 { CreateStrategyArgs } from "./CreateStrategyArgs"; -import { UpdateStrategyArgs } from "./UpdateStrategyArgs"; -import { DeleteStrategyArgs } from "./DeleteStrategyArgs"; +import { Strategy } from "./Strategy"; import { StrategyCountArgs } from "./StrategyCountArgs"; import { StrategyFindManyArgs } from "./StrategyFindManyArgs"; import { StrategyFindUniqueArgs } from "./StrategyFindUniqueArgs"; -import { Strategy } from "./Strategy"; +import { CreateStrategyArgs } from "./CreateStrategyArgs"; +import { UpdateStrategyArgs } from "./UpdateStrategyArgs"; +import { DeleteStrategyArgs } from "./DeleteStrategyArgs"; import { User } from "../../user/base/User"; import { StrategyService } from "../strategy.service"; @common.UseGuards(GqlDefaultAuthGuard, gqlACGuard.GqlACGuard) @@ -61,7 +61,7 @@ export class StrategyResolverBase { async strategies( @graphql.Args() args: StrategyFindManyArgs ): Promise { - return this.service.findMany(args); + return this.service.strategies(args); } @common.UseInterceptors(AclFilterResponseInterceptor) @@ -74,7 +74,7 @@ export class StrategyResolverBase { async strategy( @graphql.Args() args: StrategyFindUniqueArgs ): Promise { - const result = await this.service.findOne(args); + const result = await this.service.strategy(args); if (result === null) { return null; } @@ -91,7 +91,7 @@ export class StrategyResolverBase { async createStrategy( @graphql.Args() args: CreateStrategyArgs ): Promise { - return await this.service.create({ + return await this.service.createStrategy({ ...args, data: { ...args.data, @@ -116,7 +116,7 @@ export class StrategyResolverBase { @graphql.Args() args: UpdateStrategyArgs ): Promise { try { - return await this.service.update({ + return await this.service.updateStrategy({ ...args, data: { ...args.data, @@ -130,7 +130,7 @@ export class StrategyResolverBase { }); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -148,10 +148,10 @@ export class StrategyResolverBase { @graphql.Args() args: DeleteStrategyArgs ): Promise { try { - return await this.service.delete(args); + return await this.service.deleteStrategy(args); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -169,9 +169,7 @@ export class StrategyResolverBase { action: "read", possession: "any", }) - async resolveFieldAuthor( - @graphql.Parent() parent: Strategy - ): Promise { + async getAuthor(@graphql.Parent() parent: Strategy): Promise { const result = await this.service.getAuthor(parent.id); if (!result) { diff --git a/server/src/strategy/base/strategy.service.base.ts b/server/src/strategy/base/strategy.service.base.ts index 58f6290..e9d53e6 100644 --- a/server/src/strategy/base/strategy.service.base.ts +++ b/server/src/strategy/base/strategy.service.base.ts @@ -10,44 +10,46 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { PrismaService } from "../../prisma/prisma.service"; -import { Prisma, Strategy, User } from "@prisma/client"; +import { + Prisma, + Strategy as PrismaStrategy, + User as PrismaUser, +} from "@prisma/client"; export class StrategyServiceBase { constructor(protected readonly prisma: PrismaService) {} - async count( - args: Prisma.SelectSubset - ): Promise { + async count(args: Omit): Promise { return this.prisma.strategy.count(args); } - async findMany( + async strategies( args: Prisma.SelectSubset - ): Promise { - return this.prisma.strategy.findMany(args); + ): Promise { + return this.prisma.strategy.findMany(args); } - async findOne( + async strategy( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.strategy.findUnique(args); } - async create( + async createStrategy( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.strategy.create(args); } - async update( + async updateStrategy( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.strategy.update(args); } - async delete( + async deleteStrategy( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.strategy.delete(args); } - async getAuthor(parentId: number): Promise { + async getAuthor(parentId: number): Promise { return this.prisma.strategy .findUnique({ where: { id: parentId }, diff --git a/server/src/swagger/swagger.css b/server/src/swagger/swagger.css index 3ff8e74..b7c4037 100644 --- a/server/src/swagger/swagger.css +++ b/server/src/swagger/swagger.css @@ -93,6 +93,7 @@ body { background-size: contain; } +.swagger-ui .topbar-wrapper svg, .swagger-ui .topbar-wrapper img { display: none; } diff --git a/server/src/tests/auth/jwt/jwt.strategy.spec.ts b/server/src/tests/auth/jwt/jwt.strategy.spec.ts index 2463c9b..36bbb24 100644 --- a/server/src/tests/auth/jwt/jwt.strategy.spec.ts +++ b/server/src/tests/auth/jwt/jwt.strategy.spec.ts @@ -5,14 +5,16 @@ 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"); + const jwtStrategy = new JwtStrategyBase("Secrete", userService); beforeEach(() => { - userService.findOne.mockClear(); + userService.user.mockClear(); }); it("should throw UnauthorizedException where there is no user", async () => { //ARRANGE - userService.findOne - .calledWith({ where: { username: TEST_USER.username } }) + userService.user + .calledWith({ + where: { username: TEST_USER.username }, + }) .mockReturnValue(Promise.resolve(null)); //ACT const result = jwtStrategy.validate({ diff --git a/server/src/user/base/User.ts b/server/src/user/base/User.ts index b4c8e24..3ae3695 100644 --- a/server/src/user/base/User.ts +++ b/server/src/user/base/User.ts @@ -16,15 +16,13 @@ import { IsString, IsOptional, IsInt, - IsEnum, ValidateNested, } from "class-validator"; import { Type } from "class-transformer"; -import { EnumUserRole } from "./EnumUserRole"; -import { Strategy } from "../../strategy/base/Strategy"; -import { IsJSONValue } from "@app/custom-validators"; +import { IsJSONValue } from "../../validators"; import { GraphQLJSON } from "graphql-type-json"; import { JsonValue } from "type-fest"; +import { Strategy } from "../../strategy/base/Strategy"; @ObjectType() class User { @@ -76,13 +74,10 @@ class User { @ApiProperty({ required: true, - enum: EnumUserRole, }) - @IsEnum(EnumUserRole) - @Field(() => EnumUserRole, { - nullable: true, - }) - role?: "ADMIN" | "USER"; + @IsJSONValue() + @Field(() => GraphQLJSON) + roles!: JsonValue; @ApiProperty({ required: false, @@ -102,19 +97,15 @@ class User { updatedAt!: Date; @ApiProperty({ - required: true, + required: false, type: String, }) @IsString() - @Field(() => String) - username!: string; - - @ApiProperty({ - required: true, + @IsOptional() + @Field(() => String, { + nullable: true, }) - @IsJSONValue() - @Field(() => GraphQLJSON) - roles!: JsonValue; + username!: string | null; } export { User as User }; diff --git a/server/src/user/base/UserCreateInput.ts b/server/src/user/base/UserCreateInput.ts index ab1c1c3..cd55045 100644 --- a/server/src/user/base/UserCreateInput.ts +++ b/server/src/user/base/UserCreateInput.ts @@ -11,13 +11,12 @@ https://docs.amplication.com/how-to/custom-code */ import { InputType, Field } from "@nestjs/graphql"; import { ApiProperty } from "@nestjs/swagger"; -import { IsString, IsOptional, IsEnum, ValidateNested } from "class-validator"; -import { EnumUserRole } from "./EnumUserRole"; -import { StrategyCreateNestedManyWithoutUsersInput } from "./StrategyCreateNestedManyWithoutUsersInput"; -import { Type } from "class-transformer"; -import { IsJSONValue } from "@app/custom-validators"; +import { IsString, IsOptional, ValidateNested } from "class-validator"; +import { IsJSONValue } from "../../validators"; import { GraphQLJSON } from "graphql-type-json"; import { InputJsonValue } from "../../types"; +import { StrategyCreateNestedManyWithoutUsersInput } from "./StrategyCreateNestedManyWithoutUsersInput"; +import { Type } from "class-transformer"; @InputType() class UserCreateInput { @@ -53,11 +52,18 @@ class UserCreateInput { @ApiProperty({ required: true, - enum: EnumUserRole, + type: String, + }) + @IsString() + @Field(() => String) + password!: string; + + @ApiProperty({ + required: true, }) - @IsEnum(EnumUserRole) - @Field(() => EnumUserRole) - role!: "ADMIN" | "USER"; + @IsJSONValue() + @Field(() => GraphQLJSON) + roles!: InputJsonValue; @ApiProperty({ required: false, @@ -72,27 +78,15 @@ class UserCreateInput { strategy?: StrategyCreateNestedManyWithoutUsersInput; @ApiProperty({ - required: true, - type: String, - }) - @IsString() - @Field(() => String) - username!: string; - - @ApiProperty({ - required: true, + required: false, type: String, }) @IsString() - @Field(() => String) - password!: string; - - @ApiProperty({ - required: true, + @IsOptional() + @Field(() => String, { + nullable: true, }) - @IsJSONValue() - @Field(() => GraphQLJSON) - roles!: InputJsonValue; + username?: string | null; } export { UserCreateInput as UserCreateInput }; diff --git a/server/src/user/base/UserOrderByInput.ts b/server/src/user/base/UserOrderByInput.ts index 3b316a8..787a1cc 100644 --- a/server/src/user/base/UserOrderByInput.ts +++ b/server/src/user/base/UserOrderByInput.ts @@ -83,18 +83,7 @@ class UserOrderByInput { @Field(() => SortOrder, { nullable: true, }) - role?: SortOrder; - - @ApiProperty({ - required: false, - enum: ["asc", "desc"], - }) - @IsOptional() - @IsEnum(SortOrder) - @Field(() => SortOrder, { - nullable: true, - }) - updatedAt?: SortOrder; + password?: SortOrder; @ApiProperty({ required: false, @@ -105,7 +94,7 @@ class UserOrderByInput { @Field(() => SortOrder, { nullable: true, }) - username?: SortOrder; + roles?: SortOrder; @ApiProperty({ required: false, @@ -116,7 +105,7 @@ class UserOrderByInput { @Field(() => SortOrder, { nullable: true, }) - password?: SortOrder; + updatedAt?: SortOrder; @ApiProperty({ required: false, @@ -127,7 +116,7 @@ class UserOrderByInput { @Field(() => SortOrder, { nullable: true, }) - roles?: SortOrder; + username?: SortOrder; } export { UserOrderByInput as UserOrderByInput }; diff --git a/server/src/user/base/UserUpdateInput.ts b/server/src/user/base/UserUpdateInput.ts index ad021c1..22fefdf 100644 --- a/server/src/user/base/UserUpdateInput.ts +++ b/server/src/user/base/UserUpdateInput.ts @@ -11,13 +11,12 @@ https://docs.amplication.com/how-to/custom-code */ import { InputType, Field } from "@nestjs/graphql"; import { ApiProperty } from "@nestjs/swagger"; -import { IsString, IsOptional, IsEnum, ValidateNested } from "class-validator"; -import { EnumUserRole } from "./EnumUserRole"; -import { StrategyUpdateManyWithoutUsersInput } from "./StrategyUpdateManyWithoutUsersInput"; -import { Type } from "class-transformer"; -import { IsJSONValue } from "@app/custom-validators"; +import { IsString, IsOptional, ValidateNested } from "class-validator"; +import { IsJSONValue } from "../../validators"; import { GraphQLJSON } from "graphql-type-json"; import { InputJsonValue } from "../../types"; +import { StrategyUpdateManyWithoutUsersInput } from "./StrategyUpdateManyWithoutUsersInput"; +import { Type } from "class-transformer"; @InputType() class UserUpdateInput { @@ -56,37 +55,36 @@ class UserUpdateInput { @ApiProperty({ required: false, - enum: EnumUserRole, + type: String, }) - @IsEnum(EnumUserRole) + @IsString() @IsOptional() - @Field(() => EnumUserRole, { + @Field(() => String, { nullable: true, }) - role?: "ADMIN" | "USER"; + password?: string; @ApiProperty({ required: false, - type: () => StrategyUpdateManyWithoutUsersInput, }) - @ValidateNested() - @Type(() => StrategyUpdateManyWithoutUsersInput) + @IsJSONValue() @IsOptional() - @Field(() => StrategyUpdateManyWithoutUsersInput, { + @Field(() => GraphQLJSON, { nullable: true, }) - strategy?: StrategyUpdateManyWithoutUsersInput; + roles?: InputJsonValue; @ApiProperty({ required: false, - type: String, + type: () => StrategyUpdateManyWithoutUsersInput, }) - @IsString() + @ValidateNested() + @Type(() => StrategyUpdateManyWithoutUsersInput) @IsOptional() - @Field(() => String, { + @Field(() => StrategyUpdateManyWithoutUsersInput, { nullable: true, }) - username?: string; + strategy?: StrategyUpdateManyWithoutUsersInput; @ApiProperty({ required: false, @@ -97,17 +95,7 @@ class UserUpdateInput { @Field(() => String, { nullable: true, }) - password?: string; - - @ApiProperty({ - required: false, - }) - @IsJSONValue() - @IsOptional() - @Field(() => GraphQLJSON, { - nullable: true, - }) - roles?: InputJsonValue; + username?: string | null; } export { UserUpdateInput as UserUpdateInput }; diff --git a/server/src/user/base/UserWhereInput.ts b/server/src/user/base/UserWhereInput.ts index 533d8c8..cb03b1f 100644 --- a/server/src/user/base/UserWhereInput.ts +++ b/server/src/user/base/UserWhereInput.ts @@ -13,11 +13,10 @@ import { InputType, Field } from "@nestjs/graphql"; import { ApiProperty } from "@nestjs/swagger"; import { DateTimeFilter } from "../../util/DateTimeFilter"; import { Type } from "class-transformer"; -import { IsOptional, IsEnum, ValidateNested } from "class-validator"; +import { IsOptional, ValidateNested } from "class-validator"; import { StringFilter } from "../../util/StringFilter"; import { StringNullableFilter } from "../../util/StringNullableFilter"; import { IntFilter } from "../../util/IntFilter"; -import { EnumUserRole } from "./EnumUserRole"; import { StrategyListRelationFilter } from "../../strategy/base/StrategyListRelationFilter"; @InputType() @@ -77,17 +76,6 @@ class UserWhereInput { }) lastname?: StringNullableFilter; - @ApiProperty({ - required: false, - enum: EnumUserRole, - }) - @IsEnum(EnumUserRole) - @IsOptional() - @Field(() => EnumUserRole, { - nullable: true, - }) - role?: "ADMIN" | "USER"; - @ApiProperty({ required: false, type: () => StrategyListRelationFilter, @@ -110,6 +98,17 @@ class UserWhereInput { nullable: true, }) updatedAt?: DateTimeFilter; + + @ApiProperty({ + required: false, + type: StringNullableFilter, + }) + @Type(() => StringNullableFilter) + @IsOptional() + @Field(() => StringNullableFilter, { + nullable: true, + }) + username?: StringNullableFilter; } export { UserWhereInput as UserWhereInput }; diff --git a/server/src/user/base/user.controller.base.spec.ts b/server/src/user/base/user.controller.base.spec.ts index e1aab5a..a2f6548 100644 --- a/server/src/user/base/user.controller.base.spec.ts +++ b/server/src/user/base/user.controller.base.spec.ts @@ -6,7 +6,6 @@ import { CallHandler, } from "@nestjs/common"; import request from "supertest"; -import { MorganModule } from "nest-morgan"; import { ACGuard } from "nest-access-control"; import { DefaultAuthGuard } from "../../auth/defaultAuth.guard"; import { ACLModule } from "../../auth/acl.module"; @@ -24,9 +23,9 @@ const CREATE_INPUT = { firstname: "exampleFirstname", id: 42, lastname: "exampleLastname", + password: "examplePassword", updatedAt: new Date(), username: "exampleUsername", - password: "examplePassword", }; const CREATE_RESULT = { createdAt: new Date(), @@ -34,9 +33,9 @@ const CREATE_RESULT = { firstname: "exampleFirstname", id: 42, lastname: "exampleLastname", + password: "examplePassword", updatedAt: new Date(), username: "exampleUsername", - password: "examplePassword", }; const FIND_MANY_RESULT = [ { @@ -45,9 +44,9 @@ const FIND_MANY_RESULT = [ firstname: "exampleFirstname", id: 42, lastname: "exampleLastname", + password: "examplePassword", updatedAt: new Date(), username: "exampleUsername", - password: "examplePassword", }, ]; const FIND_ONE_RESULT = { @@ -56,17 +55,17 @@ const FIND_ONE_RESULT = { firstname: "exampleFirstname", id: 42, lastname: "exampleLastname", + password: "examplePassword", updatedAt: new Date(), username: "exampleUsername", - password: "examplePassword", }; const service = { - create() { + createUser() { return CREATE_RESULT; }, - findMany: () => FIND_MANY_RESULT, - findOne: ({ where }: { where: { id: string } }) => { + users: () => FIND_MANY_RESULT, + user: ({ where }: { where: { id: string } }) => { switch (where.id) { case existingId: return FIND_ONE_RESULT; @@ -120,7 +119,7 @@ describe("User", () => { }, ], controllers: [UserController], - imports: [MorganModule.forRoot(), ACLModule], + imports: [ACLModule], }) .overrideGuard(DefaultAuthGuard) .useValue(basicAuthGuard) diff --git a/server/src/user/base/user.controller.base.ts b/server/src/user/base/user.controller.base.ts index e692397..e6275c6 100644 --- a/server/src/user/base/user.controller.base.ts +++ b/server/src/user/base/user.controller.base.ts @@ -22,11 +22,10 @@ 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 { User } from "./User"; import { UserFindManyArgs } from "./UserFindManyArgs"; +import { UserWhereUniqueInput } from "./UserWhereUniqueInput"; import { UserUpdateInput } from "./UserUpdateInput"; -import { User } from "./User"; import { StrategyFindManyArgs } from "../../strategy/base/StrategyFindManyArgs"; import { Strategy } from "../../strategy/base/Strategy"; import { StrategyWhereUniqueInput } from "../../strategy/base/StrategyWhereUniqueInput"; @@ -41,9 +40,6 @@ export class UserControllerBase { @common.UseInterceptors(AclValidateRequestInterceptor) @common.Post() @swagger.ApiCreatedResponse({ type: User }) - @swagger.ApiBody({ - type: UserCreateInput, - }) @nestAccessControl.UseRoles({ resource: "User", action: "create", @@ -52,8 +48,11 @@ export class UserControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async create(@common.Body() data: UserCreateInput): Promise { - return await this.service.create({ + @swagger.ApiBody({ + type: UserCreateInput, + }) + async createUser(@common.Body() data: UserCreateInput): Promise { + return await this.service.createUser({ data: data, select: { createdAt: true, @@ -61,10 +60,9 @@ export class UserControllerBase { firstname: true, id: true, lastname: true, - role: true, + roles: true, updatedAt: true, username: true, - roles: true, }, }); } @@ -81,9 +79,9 @@ export class UserControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findMany(@common.Req() request: Request): Promise { + async users(@common.Req() request: Request): Promise { const args = plainToClass(UserFindManyArgs, request.query); - return this.service.findMany({ + return this.service.users({ ...args, select: { createdAt: true, @@ -91,10 +89,9 @@ export class UserControllerBase { firstname: true, id: true, lastname: true, - role: true, + roles: true, updatedAt: true, username: true, - roles: true, }, }); } @@ -111,10 +108,10 @@ export class UserControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async findOne( + async user( @common.Param() params: UserWhereUniqueInput ): Promise { - const result = await this.service.findOne({ + const result = await this.service.user({ where: params, select: { createdAt: true, @@ -122,10 +119,9 @@ export class UserControllerBase { firstname: true, id: true, lastname: true, - role: true, + roles: true, updatedAt: true, username: true, - roles: true, }, }); if (result === null) { @@ -140,9 +136,6 @@ export class UserControllerBase { @common.Patch("/:id") @swagger.ApiOkResponse({ type: User }) @swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) - @swagger.ApiBody({ - type: UserUpdateInput, - }) @nestAccessControl.UseRoles({ resource: "User", action: "update", @@ -151,12 +144,15 @@ export class UserControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async update( + @swagger.ApiBody({ + type: UserUpdateInput, + }) + async updateUser( @common.Param() params: UserWhereUniqueInput, @common.Body() data: UserUpdateInput ): Promise { try { - return await this.service.update({ + return await this.service.updateUser({ where: params, data: data, select: { @@ -165,10 +161,9 @@ export class UserControllerBase { firstname: true, id: true, lastname: true, - role: true, + roles: true, updatedAt: true, username: true, - roles: true, }, }); } catch (error) { @@ -192,11 +187,11 @@ export class UserControllerBase { @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException, }) - async delete( + async deleteUser( @common.Param() params: UserWhereUniqueInput ): Promise { try { - return await this.service.delete({ + return await this.service.deleteUser({ where: params, select: { createdAt: true, @@ -204,10 +199,9 @@ export class UserControllerBase { firstname: true, id: true, lastname: true, - role: true, + roles: true, updatedAt: true, username: true, - roles: true, }, }); } catch (error) { @@ -228,7 +222,7 @@ export class UserControllerBase { action: "read", possession: "any", }) - async findManyStrategy( + async findStrategy( @common.Req() request: Request, @common.Param() params: UserWhereUniqueInput ): Promise { @@ -275,7 +269,7 @@ export class UserControllerBase { connect: body, }, }; - await this.service.update({ + await this.service.updateUser({ where: params, data, select: { id: true }, @@ -297,7 +291,7 @@ export class UserControllerBase { set: body, }, }; - await this.service.update({ + await this.service.updateUser({ where: params, data, select: { id: true }, @@ -319,7 +313,7 @@ export class UserControllerBase { disconnect: body, }, }; - await this.service.update({ + await this.service.updateUser({ where: params, data, select: { id: true }, diff --git a/server/src/user/base/user.module.base.ts b/server/src/user/base/user.module.base.ts index 078e0b5..a8b6c68 100644 --- a/server/src/user/base/user.module.base.ts +++ b/server/src/user/base/user.module.base.ts @@ -10,10 +10,9 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { Module } from "@nestjs/common"; -import { MorganModule } from "nest-morgan"; import { ACLModule } from "../../auth/acl.module"; @Module({ - imports: [ACLModule, MorganModule], - exports: [ACLModule, MorganModule], + 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 index 6af2b22..8645937 100644 --- a/server/src/user/base/user.resolver.base.ts +++ b/server/src/user/base/user.resolver.base.ts @@ -10,7 +10,7 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import * as graphql from "@nestjs/graphql"; -import * as apollo from "apollo-server-express"; +import { GraphQLError } from "graphql"; import { isRecordNotFoundError } from "../../prisma.util"; import { MetaQueryPayload } from "../../util/MetaQueryPayload"; import * as nestAccessControl from "nest-access-control"; @@ -19,13 +19,13 @@ 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 { User } from "./User"; import { UserCountArgs } from "./UserCountArgs"; import { UserFindManyArgs } from "./UserFindManyArgs"; import { UserFindUniqueArgs } from "./UserFindUniqueArgs"; -import { User } from "./User"; +import { CreateUserArgs } from "./CreateUserArgs"; +import { UpdateUserArgs } from "./UpdateUserArgs"; +import { DeleteUserArgs } from "./DeleteUserArgs"; import { StrategyFindManyArgs } from "../../strategy/base/StrategyFindManyArgs"; import { Strategy } from "../../strategy/base/Strategy"; import { UserService } from "../user.service"; @@ -60,7 +60,7 @@ export class UserResolverBase { possession: "any", }) async users(@graphql.Args() args: UserFindManyArgs): Promise { - return this.service.findMany(args); + return this.service.users(args); } @common.UseInterceptors(AclFilterResponseInterceptor) @@ -71,7 +71,7 @@ export class UserResolverBase { possession: "own", }) async user(@graphql.Args() args: UserFindUniqueArgs): Promise { - const result = await this.service.findOne(args); + const result = await this.service.user(args); if (result === null) { return null; } @@ -86,7 +86,7 @@ export class UserResolverBase { possession: "any", }) async createUser(@graphql.Args() args: CreateUserArgs): Promise { - return await this.service.create({ + return await this.service.createUser({ ...args, data: args.data, }); @@ -101,13 +101,13 @@ export class UserResolverBase { }) async updateUser(@graphql.Args() args: UpdateUserArgs): Promise { try { - return await this.service.update({ + return await this.service.updateUser({ ...args, data: args.data, }); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -123,10 +123,10 @@ export class UserResolverBase { }) async deleteUser(@graphql.Args() args: DeleteUserArgs): Promise { try { - return await this.service.delete(args); + return await this.service.deleteUser(args); } catch (error) { if (isRecordNotFoundError(error)) { - throw new apollo.ApolloError( + throw new GraphQLError( `No resource was found for ${JSON.stringify(args.where)}` ); } @@ -141,7 +141,7 @@ export class UserResolverBase { action: "read", possession: "any", }) - async resolveFieldStrategy( + async findStrategy( @graphql.Parent() parent: User, @graphql.Args() args: StrategyFindManyArgs ): Promise { diff --git a/server/src/user/base/user.service.base.ts b/server/src/user/base/user.service.base.ts index 6bf05b5..96b68f7 100644 --- a/server/src/user/base/user.service.base.ts +++ b/server/src/user/base/user.service.base.ts @@ -10,7 +10,11 @@ https://docs.amplication.com/how-to/custom-code ------------------------------------------------------------------------------ */ import { PrismaService } from "../../prisma/prisma.service"; -import { Prisma, User, Strategy } from "@prisma/client"; +import { + Prisma, + User as PrismaUser, + Strategy as PrismaStrategy, +} from "@prisma/client"; import { PasswordService } from "../../auth/password.service"; import { transformStringFieldUpdateInput } from "../../prisma.util"; @@ -20,25 +24,23 @@ export class UserServiceBase { protected readonly passwordService: PasswordService ) {} - async count( - args: Prisma.SelectSubset - ): Promise { + async count(args: Omit): Promise { return this.prisma.user.count(args); } - async findMany( + async users( args: Prisma.SelectSubset - ): Promise { - return this.prisma.user.findMany(args); + ): Promise { + return this.prisma.user.findMany(args); } - async findOne( + async user( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.user.findUnique(args); } - async create( + async createUser( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.user.create({ ...args, @@ -48,9 +50,9 @@ export class UserServiceBase { }, }); } - async update( + async updateUser( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.user.update({ ...args, @@ -66,16 +68,16 @@ export class UserServiceBase { }, }); } - async delete( + async deleteUser( args: Prisma.SelectSubset - ): Promise { + ): Promise { return this.prisma.user.delete(args); } async findStrategy( parentId: number, args: Prisma.StrategyFindManyArgs - ): Promise { + ): Promise { return this.prisma.user .findUniqueOrThrow({ where: { id: parentId }, diff --git a/server/terraform/backend.tf b/server/terraform/backend.tf new file mode 100644 index 0000000..43df88c --- /dev/null +++ b/server/terraform/backend.tf @@ -0,0 +1,7 @@ +terraform { + backend "s3" { + bucket = "bucket-name" + key = "path/to/key" + region = "eu-west-1" + } + } \ No newline at end of file diff --git a/server/terraform/ecr-tik-stock.tf b/server/terraform/ecr-tik-stock.tf new file mode 100644 index 0000000..bbd967c --- /dev/null +++ b/server/terraform/ecr-tik-stock.tf @@ -0,0 +1,28 @@ +module "ecr_tik_stock" { + source = "terraform-aws-modules/ecr/aws" + version = "1.6.0" + + repository_name = "tik-stock" + repository_type = "private" + + create_lifecycle_policy = false + + repository_force_delete = false + repository_read_access_arns = [] + repository_read_write_access_arns = [] +} + +output "repository_arn" { + description = "Full ARN of the repository" + value = module.ecr_tik_stock.repository_arn +} + +output "repository_registry_id" { + description = "The registry ID where the repository was created" + value = module.ecr_tik_stock.repository_registry_id +} + +output "repository_url" { + description = "The URL of the repository (in the form `aws_account_id.dkr.ecr.region.amazonaws.com/repositoryName`)" + value = module.ecr_tik_stock.repository_url +} diff --git a/server/terraform/ecs-tik-stock.tf b/server/terraform/ecs-tik-stock.tf new file mode 100644 index 0000000..6d93207 --- /dev/null +++ b/server/terraform/ecs-tik-stock.tf @@ -0,0 +1,207 @@ +module "ecs_cluster_tik_stock" { + source = "terraform-aws-modules/ecs/aws//modules/cluster" + version = "5.2.2" + + cluster_name = "tik-stock" + + fargate_capacity_providers = { + FARGATE = { + default_capacity_provider_strategy = { + weight = 100 + base = 0 + } + } + FARGATE_SPOT = { + default_capacity_provider_strategy = { + weight = 0 + } + } + } +} + +module "ecs_service_tik_stock" { + source = "terraform-aws-modules/ecs/aws//modules/service" + version = "5.2.2" + + name = "tik-stock" + cluster_arn = module.ecs_cluster_tik_stock.arn + + cpu = 1024 + memory = 4096 + + container_definitions = { + ("tik-stock") = { + essential = true + cpu = 512 + memory = 1024 + image = "0000000000.dkr.ecr.eu-west-1.amazonaws.com/service-name" + + port_mappings = [ + { + name = "tik-stock" + containerPort = 3000 + hostPort = 3000 + protocol = "tcp" + } + ] + + readonly_root_filesystem = false + + enable_cloudwatch_logging = false + + log_configuration = { + logDriver = "awslogs" + options = { + awslogs-create-group = "true" + awslogs-group = "/ecs/tik-stock" + awslogs-region = local.region + awslogs-stream-prefix = "ecs" + } + } + + memory_reservation = 100 + } + } + + load_balancer = { + service = { + target_group_arn = element(module.ecs_alb_tik_stock.target_group_arns, 0) + container_name = "tik-stock" + container_port = 3000 + } + } + + subnet_ids = module.vpc.private_subnets + + security_group_rules = { + alb_ingress_3000 = { + type = "ingress" + from_port = 3000 + to_port = 3000 + protocol = "tcp" + source_security_group_id = module.ecs_alb_sg_tik_stock.security_group_id + } + egress_all = { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } +} + +resource "aws_service_discovery_http_namespace" "tik_stock" { + name = "tik-stock" +} + +module "ecs_alb_sg_tik_stock" { + source = "terraform-aws-modules/security-group/aws" + version = "5.1.0" + + name = "tik-stock" + vpc_id = module.vpc.vpc_id + + ingress_rules = ["http-80-tcp"] + ingress_cidr_blocks = ["0.0.0.0/0"] + + egress_rules = ["all-all"] + egress_cidr_blocks = module.vpc.private_subnets_cidr_blocks +} + +module "ecs_alb_tik_stock" { + source = "terraform-aws-modules/alb/aws" + version = "8.7.0" + + name = "tik-stock" + + load_balancer_type = "application" + + vpc_id = module.vpc.vpc_id + subnets = module.vpc.public_subnets + security_groups = [module.ecs_alb_sg_tik_stock.security_group_id] + + http_tcp_listeners = [ + { + port = 80 + protocol = "HTTP" + target_group_index = 0 + }, + ] + + target_groups = [ + { + name = "tik-stock" + backend_protocol = "HTTP" + backend_port = 3000 + target_type = "ip" + + health_check = { + enabled = true + interval = 30 + path = "/api/_health/live" + port = "traffic-port" + healthy_threshold = 3 + unhealthy_threshold = 3 + timeout = 6 + protocol = "HTTP" + matcher = "200-299" + } + }, + ] +} + +output "cluster_arn" { + description = "ARN that identifies the cluster" + value = module.ecs_cluster_tik_stock.arn +} + +output "cluster_id" { + description = "ID that identifies the cluster" + value = module.ecs_cluster_tik_stock.id +} + +output "cluster_name" { + description = "Name that identifies the cluster" + value = module.ecs_cluster_tik_stock.name +} + +output "cluster_capacity_providers" { + description = "Map of cluster capacity providers attributes" + value = module.ecs_cluster_tik_stock.cluster_capacity_providers +} + +output "service_id" { + description = "ARN that identifies the service" + value = module.ecs_service_tik_stock.id +} + +output "service_name" { + description = "Name of the service" + value = module.ecs_service_tik_stock.name +} + +output "service_iam_role_name" { + description = "Service IAM role name" + value = module.ecs_service_tik_stock.iam_role_name +} + +output "service_iam_role_arn" { + description = "Service IAM role ARN" + value = module.ecs_service_tik_stock.iam_role_arn +} + +output "service_iam_role_unique_id" { + description = "Stable and unique string identifying the service IAM role" + value = module.ecs_service_tik_stock.iam_role_unique_id +} + +output "service_container_definitions" { + description = "Container definitions" + value = module.ecs_service_tik_stock.container_definitions +} + +output "service_task_definition_arn" { + description = "Full ARN of the Task Definition (including both `family` and `revision`)" + value = module.ecs_service_tik_stock.task_definition_arn +} diff --git a/server/terraform/main.tf b/server/terraform/main.tf new file mode 100644 index 0000000..3946ebf --- /dev/null +++ b/server/terraform/main.tf @@ -0,0 +1,22 @@ +provider "aws" { + region = local.region + + default_tags { + tags = { + Terraform = "true" + Amplication = "true" + Environment = local.environment + } + } +} + +data "aws_availability_zones" "available" {} + +locals { + name = "" + region = "eu-west-1" + environment = "development" + + vpc_cidr_block = "10.0.0.0/16" + vpc_azs = slice(data.aws_availability_zones.available.names, 0, 3) +} diff --git a/server/terraform/outputs.tf b/server/terraform/outputs.tf new file mode 100644 index 0000000..a5137e5 --- /dev/null +++ b/server/terraform/outputs.tf @@ -0,0 +1,175 @@ +output "vpc_id" { + description = "The ID of the VPC" + value = module.vpc.vpc_id +} + +output "vpc_arn" { + description = "The ARN of the VPC" + value = module.vpc.vpc_arn +} + +output "vpc_cidr_block" { + description = "The CIDR block of the VPC" + value = module.vpc.vpc_cidr_block +} + +output "default_security_group_id" { + description = "The ID of the security group created by default on VPC creation" + value = module.vpc.default_security_group_id +} + +output "default_network_acl_id" { + description = "The ID of the default network ACL" + value = module.vpc.default_network_acl_id +} + +output "default_route_table_id" { + description = "The ID of the default route table" + value = module.vpc.default_route_table_id +} + +output "vpc_main_route_table_id" { + description = "The ID of the main route table associated with this VPC" + value = module.vpc.vpc_main_route_table_id +} + +output "private_subnets" { + description = "List of IDs of private subnets" + value = module.vpc.private_subnets +} + +output "private_subnet_arns" { + description = "List of ARNs of private subnets" + value = module.vpc.private_subnet_arns +} + +output "public_subnets" { + description = "List of IDs of public subnets" + value = module.vpc.public_subnets +} + +output "public_subnet_arns" { + description = "List of ARNs of public subnets" + value = module.vpc.public_subnet_arns +} + +output "database_subnets" { + description = "List of IDs of database subnets" + value = module.vpc.database_subnets +} + +output "database_subnet_arns" { + description = "List of ARNs of database subnets" + value = module.vpc.database_subnet_arns +} + +output "database_subnet_group" { + description = "ID of database subnet group" + value = module.vpc.database_subnet_group +} + +output "database_subnet_group_name" { + description = "Name of database subnet group" + value = module.vpc.database_subnet_group_name +} + +output "public_route_table_ids" { + description = "List of IDs of public route tables" + value = module.vpc.public_route_table_ids +} + +output "private_route_table_ids" { + description = "List of IDs of private route tables" + value = module.vpc.private_route_table_ids +} + +output "database_route_table_ids" { + description = "List of IDs of database route tables" + value = module.vpc.database_route_table_ids +} + +output "public_internet_gateway_route_id" { + description = "ID of the internet gateway route" + value = module.vpc.public_internet_gateway_route_id +} + +output "database_internet_gateway_route_id" { + description = "ID of the database internet gateway route" + value = module.vpc.database_internet_gateway_route_id +} + +output "database_nat_gateway_route_ids" { + description = "List of IDs of the database nat gateway route" + value = module.vpc.database_nat_gateway_route_ids +} + +output "private_nat_gateway_route_ids" { + description = "List of IDs of the private nat gateway route" + value = module.vpc.private_nat_gateway_route_ids +} + +output "database_route_table_association_ids" { + description = "List of IDs of the database route table association" + value = module.vpc.database_route_table_association_ids +} + +output "public_route_table_association_ids" { + description = "List of IDs of the public route table association" + value = module.vpc.public_route_table_association_ids +} + +output "nat_ids" { + description = "List of allocation ID of Elastic IPs created for AWS NAT Gateway" + value = module.vpc.nat_ids +} + +output "nat_public_ips" { + description = "List of public Elastic IPs created for AWS NAT Gateway" + value = module.vpc.nat_public_ips +} + +output "natgw_ids" { + description = "List of NAT Gateway IDs" + value = module.vpc.natgw_ids +} + +output "igw_id" { + description = "The ID of the Internet Gateway" + value = module.vpc.igw_id +} + +output "igw_arn" { + description = "The ARN of the Internet Gateway" + value = module.vpc.igw_arn +} + + +output "public_network_acl_id" { + description = "ID of the public network ACL" + value = module.vpc.public_network_acl_id +} + +output "public_network_acl_arn" { + description = "ARN of the public network ACL" + value = module.vpc.public_network_acl_arn +} + +output "private_network_acl_id" { + description = "ID of the private network ACL" + value = module.vpc.private_network_acl_id +} + +output "private_network_acl_arn" { + description = "ARN of the private network ACL" + value = module.vpc.private_network_acl_arn +} + +output "database_network_acl_id" { + description = "ID of the database network ACL" + value = module.vpc.database_network_acl_id +} + +output "database_network_acl_arn" { + description = "ARN of the database network ACL" + value = module.vpc.database_network_acl_arn +} diff --git a/server/terraform/provider.tf b/server/terraform/provider.tf new file mode 100644 index 0000000..ddfcb0e --- /dev/null +++ b/server/terraform/provider.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.0" + } + } +} diff --git a/server/terraform/rds-tik-stock.tf b/server/terraform/rds-tik-stock.tf new file mode 100644 index 0000000..7f6c7b2 --- /dev/null +++ b/server/terraform/rds-tik-stock.tf @@ -0,0 +1,123 @@ +module "rds_tik_stock" { + source = "terraform-aws-modules/rds/aws" + version = "6.2.0" + + identifier = "tik-stock" + + engine = "postgres" + engine_version = "14" + family = "postgres14" + major_engine_version = "14" + instance_class = "db.t4g.medium" + + allocated_storage = 20 + max_allocated_storage = 100 + + db_name = "tikStock" + username = "postgres" + password = random_password.database_password.result + port = 5432 + + manage_master_user_password = false + + db_subnet_group_name = module.vpc.database_subnet_group + vpc_security_group_ids = [module.sg_tik_stock.security_group_id] + + maintenance_window = "Mon:00:00-Mon:03:00" + backup_window = "03:00-06:00" + backup_retention_period = 14 +} + +resource "random_password" "database_password" { + length = 20 + special = false +} + +module "sg_tik_stock" { + source = "terraform-aws-modules/security-group/aws" + version = "5.0.0" + + name = "rds-tik-stock" + vpc_id = module.vpc.vpc_id + + ingress_with_cidr_blocks = [ + { + from_port = 5432 + to_port = 5432 + protocol = "tcp" + cidr_blocks = module.vpc.vpc_cidr_block + }, + ] +} + +output "db_password" { + description = "The password for the master user of the database" + value = random_password.database_password.result + sensitive = true +} + +output "db_instance_address" { + description = "The address of the RDS instance" + value = module.rds_tik_stock.db_instance_address +} + +output "db_instance_arn" { + description = "The ARN of the RDS instance" + value = module.rds_tik_stock.db_instance_arn +} + +output "db_instance_availability_zone" { + description = "The availability zone of the RDS instance" + value = module.rds_tik_stock.db_instance_availability_zone +} + +output "db_instance_endpoint" { + description = "The connection endpoint" + value = module.rds_tik_stock.db_instance_endpoint +} + +output "db_instance_engine" { + description = "The database engine" + value = module.rds_tik_stock.db_instance_engine +} + +output "db_instance_identifier" { + description = "The RDS instance identifier" + value = module.rds_tik_stock.db_instance_identifier +} + +output "db_instance_name" { + description = "The database name" + value = module.rds_tik_stock.db_instance_name +} + +output "db_instance_username" { + description = "The master username for the database" + value = module.rds_tik_stock.db_instance_username + sensitive = true +} + +output "db_instance_port" { + description = "The database port" + value = module.rds_tik_stock.db_instance_port +} + +output "db_subnet_group_id" { + description = "The db subnet group name" + value = module.rds_tik_stock.db_subnet_group_id +} + +output "db_subnet_group_arn" { + description = "The ARN of the db subnet group" + value = module.rds_tik_stock.db_subnet_group_arn +} + +output "db_parameter_group_id" { + description = "The db parameter group id" + value = module.rds_tik_stock.db_parameter_group_id +} + +output "db_parameter_group_arn" { + description = "The ARN of the db parameter group" + value = module.rds_tik_stock.db_parameter_group_arn +} diff --git a/server/terraform/variables.tf b/server/terraform/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/server/terraform/vpc.tf b/server/terraform/vpc.tf new file mode 100644 index 0000000..2f191cb --- /dev/null +++ b/server/terraform/vpc.tf @@ -0,0 +1,22 @@ +// https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "5.1.2" + + name = join("-", ["vpc", local.name]) + cidr = local.vpc_cidr_block + + azs = local.vpc_azs + private_subnets = [for k, v in local.vpc_azs : cidrsubnet(local.vpc_cidr_block, 8, k)] + public_subnets = [for k, v in local.vpc_azs : cidrsubnet(local.vpc_cidr_block, 8, k + 4)] + database_subnets = [for k, v in local.vpc_azs : cidrsubnet(local.vpc_cidr_block, 8, k + 8)] + + create_database_subnet_group = true + + enable_dns_hostnames = true + enable_dns_support = true + + enable_nat_gateway = true + single_nat_gateway = true +} diff --git a/server/tsconfig.json b/server/tsconfig.json index f084cf7..707e8cd 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -6,8 +6,8 @@ "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es2017", - "lib": ["ES2020"], + "target": "es2022", + "lib": ["es2023"], "sourceMap": true, "outDir": "./dist", "incremental": true, @@ -15,10 +15,7 @@ "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "skipLibCheck": true, - "strict": true, - "paths": { - "@app/custom-validators": ["src/validators"] - } + "strict": true }, "include": ["src"] } From 4f3434643b5cd1eb3a26d99c0870ef6cebef8d3b Mon Sep 17 00:00:00 2001 From: "amplication[bot]" Date: Tue, 30 Apr 2024 14:11:56 +0000 Subject: [PATCH 2/4] Amplication build # clvmguuyk0bvwn4v200nymudr Build URL: [https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmguuyk0bvwn4v200nymudr](https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmguuyk0bvwn4v200nymudr) --- admin-ui/.eslintignore | 12 +++++++++ admin-ui/.eslintrc | 10 +++----- admin-ui/.prettierignore | 17 +++++++++++++ admin-ui/.prettierrc.json | 1 + admin-ui/Dockerfile | 2 +- admin-ui/README.md | 4 +-- admin-ui/configuration/nginx.conf | 2 +- admin-ui/package.json | 12 ++++----- admin-ui/src/api/user/User.ts | 7 +++--- admin-ui/src/api/user/UserCreateInput.ts | 7 +++--- admin-ui/src/api/user/UserOrderByInput.ts | 5 ++-- admin-ui/src/api/user/UserUpdateInput.ts | 7 +++--- admin-ui/src/api/user/UserWhereInput.ts | 2 +- admin-ui/src/index.tsx | 3 +-- admin-ui/src/stockField/StockFieldTitle.ts | 2 +- .../stockFundamental/StockFundamentalTitle.ts | 2 +- .../StockFundamentalsHistoryTitle.ts | 2 +- admin-ui/src/strategy/StrategyTitle.ts | 2 +- admin-ui/src/user/EnumRoles.ts | 2 +- admin-ui/src/user/RolesOptions.ts | 1 - admin-ui/src/user/UserCreate.tsx | 25 ++++++------------- admin-ui/src/user/UserEdit.tsx | 25 ++++++------------- admin-ui/src/user/UserList.tsx | 5 ++-- admin-ui/src/user/UserShow.tsx | 5 ++-- admin-ui/src/user/UserTitle.ts | 2 +- admin-ui/src/user/roles.ts | 8 +++--- 26 files changed, 84 insertions(+), 88 deletions(-) create mode 100644 admin-ui/.eslintignore create mode 100644 admin-ui/.prettierignore create mode 100644 admin-ui/.prettierrc.json diff --git a/admin-ui/.eslintignore b/admin-ui/.eslintignore new file mode 100644 index 0000000..efaba3b --- /dev/null +++ b/admin-ui/.eslintignore @@ -0,0 +1,12 @@ +# Add further files to ignore here as needed + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build \ No newline at end of file diff --git a/admin-ui/.eslintrc b/admin-ui/.eslintrc index 381d0bd..9c99ba0 100644 --- a/admin-ui/.eslintrc +++ b/admin-ui/.eslintrc @@ -6,22 +6,18 @@ "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", - "plugin:react/recommended" + "plugin:react/recommended" ], "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" }, - "plugins": [ - "@typescript-eslint", - "react" - ], + "plugins": ["@typescript-eslint", "react"], "settings": { "react": { "version": "detect" } }, "rules": {} - -} \ No newline at end of file +} diff --git a/admin-ui/.prettierignore b/admin-ui/.prettierignore new file mode 100644 index 0000000..09b671a --- /dev/null +++ b/admin-ui/.prettierignore @@ -0,0 +1,17 @@ +# Add further files to ignore here as needed + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build +/dist + +#Server Specific +prisma/migrations/ +package-lock.json diff --git a/admin-ui/.prettierrc.json b/admin-ui/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/admin-ui/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/admin-ui/Dockerfile b/admin-ui/Dockerfile index 9c43e40..0911e21 100644 --- a/admin-ui/Dockerfile +++ b/admin-ui/Dockerfile @@ -44,7 +44,7 @@ RUN chown -R nginx:nginx /var/run/nginx.pid \ USER nginx # expose a specific port on the docker container -ENV PORT=80 +ENV PORT=3001 EXPOSE ${PORT} # start the server using the previously build application diff --git a/admin-ui/README.md b/admin-ui/README.md index 715d898..cc7c387 100644 --- a/admin-ui/README.md +++ b/admin-ui/README.md @@ -1,12 +1,12 @@

- amplication-logo + amplication-logo

# Introduction -This service was generated with Amplication. It serves as the client-side for the generated server component. The client-side consist of a React application with ready-made forms for creating and editing the different data models of the application. It is pre-conffigured to work with the server and comes with the boilerplate and foundation for the client - i.e., routing, navigation, authentication, premissions, menu, breadcrumbs, error handling and much more. Additional information about the admin component and the architecture around it, can be found on the [documentation](https://docs.amplication.com/guides/getting-started) site. This side of the generated project was bootstrapped with [create-react-app](https://github.com/facebook/create-react-app) and built with [react-admin](https://marmelab.com/react-admin/). +This service was generated with Amplication. It serves as the client-side for the generated server component. The client-side consist of a React application with ready-made forms for creating and editing the different data models of the application. It is pre-conffigured to work with the server and comes with the boilerplate and foundation for the client - i.e., routing, navigation, authentication, permissions, menu, breadcrumbs, error handling and much more. Additional information about the admin component and the architecture around it, can be found on the [documentation](https://docs.amplication.com/guides/getting-started) site. This side of the generated project was bootstrapped with [create-react-app](https://github.com/facebook/create-react-app) and built with [react-admin](https://marmelab.com/react-admin/).

diff --git a/admin-ui/configuration/nginx.conf b/admin-ui/configuration/nginx.conf index 88dad6e..c907b5c 100644 --- a/admin-ui/configuration/nginx.conf +++ b/admin-ui/configuration/nginx.conf @@ -1,7 +1,7 @@ server_tokens off; server { - listen 8080; + listen 3001; server_name localhost; location / { root /usr/share/nginx/html; diff --git a/admin-ui/package.json b/admin-ui/package.json index e6e77c6..0bc2d1b 100644 --- a/admin-ui/package.json +++ b/admin-ui/package.json @@ -26,9 +26,9 @@ "test": "react-scripts test", "eject": "react-scripts eject", "package:container": "docker build .", - "format": "prettier --write .", "lint": "eslint './src/**/*.{ts, tsx}'", - "lint:fix": "eslint --fix './src/**/*.{ts, tsx}'" + "lint:fix": "eslint --fix './src/**/*.{ts, tsx}'", + "format": "prettier --write ." }, "eslintConfig": { "extends": [ @@ -57,12 +57,12 @@ "@types/node": "12.20.16", "@types/react": "16.14.11", "@types/react-dom": "17.0.0", - "type-fest": "0.13.1", - "typescript": "4.3.5", - "prettier": "^2.8.0", "@typescript-eslint/eslint-plugin": "^4.1.0", "@typescript-eslint/parser": "^4.1.0", "eslint": "^7.0.0", - "eslint-plugin-react": "^7.33.1" + "eslint-plugin-react": "^7.33.1", + "prettier": "^2.8.0", + "type-fest": "0.13.1", + "typescript": "4.3.5" } } \ No newline at end of file diff --git a/admin-ui/src/api/user/User.ts b/admin-ui/src/api/user/User.ts index 2e079de..354486e 100644 --- a/admin-ui/src/api/user/User.ts +++ b/admin-ui/src/api/user/User.ts @@ -1,5 +1,5 @@ -import { Strategy } from "../strategy/Strategy"; import { JsonValue } from "type-fest"; +import { Strategy } from "../strategy/Strategy"; export type User = { createdAt: Date; @@ -7,9 +7,8 @@ export type User = { firstname: string | null; id: number; lastname: string | null; - role?: "ADMIN" | "USER"; + roles: JsonValue; strategy?: Array; updatedAt: Date; - username: string; - roles: JsonValue; + username: string | null; }; diff --git a/admin-ui/src/api/user/UserCreateInput.ts b/admin-ui/src/api/user/UserCreateInput.ts index ae58442..f0075d7 100644 --- a/admin-ui/src/api/user/UserCreateInput.ts +++ b/admin-ui/src/api/user/UserCreateInput.ts @@ -1,13 +1,12 @@ -import { StrategyCreateNestedManyWithoutUsersInput } from "./StrategyCreateNestedManyWithoutUsersInput"; import { InputJsonValue } from "../../types"; +import { StrategyCreateNestedManyWithoutUsersInput } from "./StrategyCreateNestedManyWithoutUsersInput"; export type UserCreateInput = { email: string; firstname?: string | null; lastname?: string | null; - role: "ADMIN" | "USER"; - strategy?: StrategyCreateNestedManyWithoutUsersInput; - username: string; password: string; roles: InputJsonValue; + strategy?: StrategyCreateNestedManyWithoutUsersInput; + username?: string | null; }; diff --git a/admin-ui/src/api/user/UserOrderByInput.ts b/admin-ui/src/api/user/UserOrderByInput.ts index 81fdad9..2ce3bc7 100644 --- a/admin-ui/src/api/user/UserOrderByInput.ts +++ b/admin-ui/src/api/user/UserOrderByInput.ts @@ -6,9 +6,8 @@ export type UserOrderByInput = { firstname?: SortOrder; id?: SortOrder; lastname?: SortOrder; - role?: SortOrder; - updatedAt?: SortOrder; - username?: SortOrder; password?: SortOrder; roles?: SortOrder; + updatedAt?: SortOrder; + username?: SortOrder; }; diff --git a/admin-ui/src/api/user/UserUpdateInput.ts b/admin-ui/src/api/user/UserUpdateInput.ts index 4b9f1df..a2c690f 100644 --- a/admin-ui/src/api/user/UserUpdateInput.ts +++ b/admin-ui/src/api/user/UserUpdateInput.ts @@ -1,13 +1,12 @@ -import { StrategyUpdateManyWithoutUsersInput } from "./StrategyUpdateManyWithoutUsersInput"; import { InputJsonValue } from "../../types"; +import { StrategyUpdateManyWithoutUsersInput } from "./StrategyUpdateManyWithoutUsersInput"; export type UserUpdateInput = { email?: string; firstname?: string | null; lastname?: string | null; - role?: "ADMIN" | "USER"; - strategy?: StrategyUpdateManyWithoutUsersInput; - username?: string; password?: string; roles?: InputJsonValue; + strategy?: StrategyUpdateManyWithoutUsersInput; + username?: string | null; }; diff --git a/admin-ui/src/api/user/UserWhereInput.ts b/admin-ui/src/api/user/UserWhereInput.ts index 8251c53..a5bff1a 100644 --- a/admin-ui/src/api/user/UserWhereInput.ts +++ b/admin-ui/src/api/user/UserWhereInput.ts @@ -10,7 +10,7 @@ export type UserWhereInput = { firstname?: StringNullableFilter; id?: IntFilter; lastname?: StringNullableFilter; - role?: "ADMIN" | "USER"; strategy?: StrategyListRelationFilter; updatedAt?: DateTimeFilter; + username?: StringNullableFilter; }; diff --git a/admin-ui/src/index.tsx b/admin-ui/src/index.tsx index 5e2de69..2da129c 100644 --- a/admin-ui/src/index.tsx +++ b/admin-ui/src/index.tsx @@ -1,8 +1,7 @@ import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; -// @ts-ignore -// eslint-disable-next-line import/no-unresolved + import App from "./App"; import reportWebVitals from "./reportWebVitals"; diff --git a/admin-ui/src/stockField/StockFieldTitle.ts b/admin-ui/src/stockField/StockFieldTitle.ts index c9d12de..5bd04e9 100644 --- a/admin-ui/src/stockField/StockFieldTitle.ts +++ b/admin-ui/src/stockField/StockFieldTitle.ts @@ -3,5 +3,5 @@ import { StockField as TStockField } from "../api/stockField/StockField"; export const STOCKFIELD_TITLE_FIELD = "sector"; export const StockFieldTitle = (record: TStockField): string => { - return record.sector || String(record.id); + return record.sector?.toString() || String(record.id); }; diff --git a/admin-ui/src/stockFundamental/StockFundamentalTitle.ts b/admin-ui/src/stockFundamental/StockFundamentalTitle.ts index 6bb42f6..a0e942a 100644 --- a/admin-ui/src/stockFundamental/StockFundamentalTitle.ts +++ b/admin-ui/src/stockFundamental/StockFundamentalTitle.ts @@ -3,5 +3,5 @@ import { StockFundamental as TStockFundamental } from "../api/stockFundamental/S export const STOCKFUNDAMENTAL_TITLE_FIELD = "papel"; export const StockFundamentalTitle = (record: TStockFundamental): string => { - return record.papel || String(record.id); + return record.papel?.toString() || String(record.id); }; diff --git a/admin-ui/src/stockFundamentalsHistory/StockFundamentalsHistoryTitle.ts b/admin-ui/src/stockFundamentalsHistory/StockFundamentalsHistoryTitle.ts index c020fe5..ce99773 100644 --- a/admin-ui/src/stockFundamentalsHistory/StockFundamentalsHistoryTitle.ts +++ b/admin-ui/src/stockFundamentalsHistory/StockFundamentalsHistoryTitle.ts @@ -5,5 +5,5 @@ export const STOCKFUNDAMENTALSHISTORY_TITLE_FIELD = "papel"; export const StockFundamentalsHistoryTitle = ( record: TStockFundamentalsHistory ): string => { - return record.papel || String(record.id); + return record.papel?.toString() || String(record.id); }; diff --git a/admin-ui/src/strategy/StrategyTitle.ts b/admin-ui/src/strategy/StrategyTitle.ts index bbb5089..5b07d26 100644 --- a/admin-ui/src/strategy/StrategyTitle.ts +++ b/admin-ui/src/strategy/StrategyTitle.ts @@ -3,5 +3,5 @@ import { Strategy as TStrategy } from "../api/strategy/Strategy"; export const STRATEGY_TITLE_FIELD = "title"; export const StrategyTitle = (record: TStrategy): string => { - return record.title || String(record.id); + return record.title?.toString() || String(record.id); }; diff --git a/admin-ui/src/user/EnumRoles.ts b/admin-ui/src/user/EnumRoles.ts index 2c301e5..44e09db 100644 --- a/admin-ui/src/user/EnumRoles.ts +++ b/admin-ui/src/user/EnumRoles.ts @@ -1,4 +1,4 @@ export enum EnumRoles { - User = "user", Admin = "admin", + User = "user", } diff --git a/admin-ui/src/user/RolesOptions.ts b/admin-ui/src/user/RolesOptions.ts index 2f12fcf..5e30fe9 100644 --- a/admin-ui/src/user/RolesOptions.ts +++ b/admin-ui/src/user/RolesOptions.ts @@ -1,4 +1,3 @@ -//@ts-ignore import { ROLES } from "./roles"; declare interface Role { diff --git a/admin-ui/src/user/UserCreate.tsx b/admin-ui/src/user/UserCreate.tsx index 253ba83..c4a9cfe 100644 --- a/admin-ui/src/user/UserCreate.tsx +++ b/admin-ui/src/user/UserCreate.tsx @@ -5,10 +5,9 @@ import { SimpleForm, CreateProps, TextInput, - SelectInput, - ReferenceArrayInput, - SelectArrayInput, PasswordInput, + SelectArrayInput, + ReferenceArrayInput, } from "react-admin"; import { StrategyTitle } from "../strategy/StrategyTitle"; @@ -21,13 +20,10 @@ export const UserCreate = (props: CreateProps): React.ReactElement => { - + @@ -39,14 +35,7 @@ export const UserCreate = (props: CreateProps): React.ReactElement => { > - - - + ); diff --git a/admin-ui/src/user/UserEdit.tsx b/admin-ui/src/user/UserEdit.tsx index 0c68553..6075174 100644 --- a/admin-ui/src/user/UserEdit.tsx +++ b/admin-ui/src/user/UserEdit.tsx @@ -5,10 +5,9 @@ import { SimpleForm, EditProps, TextInput, - SelectInput, - ReferenceArrayInput, - SelectArrayInput, PasswordInput, + SelectArrayInput, + ReferenceArrayInput, } from "react-admin"; import { StrategyTitle } from "../strategy/StrategyTitle"; @@ -21,13 +20,10 @@ export const UserEdit = (props: EditProps): React.ReactElement => { - + @@ -39,14 +35,7 @@ export const UserEdit = (props: EditProps): React.ReactElement => { > - - - + ); diff --git a/admin-ui/src/user/UserList.tsx b/admin-ui/src/user/UserList.tsx index 74ad88c..c18591e 100644 --- a/admin-ui/src/user/UserList.tsx +++ b/admin-ui/src/user/UserList.tsx @@ -17,10 +17,9 @@ export const UserList = (props: ListProps): React.ReactElement => { - - - + + ); diff --git a/admin-ui/src/user/UserShow.tsx b/admin-ui/src/user/UserShow.tsx index f2f259d..68d7eda 100644 --- a/admin-ui/src/user/UserShow.tsx +++ b/admin-ui/src/user/UserShow.tsx @@ -23,10 +23,9 @@ export const UserShow = (props: ShowProps): React.ReactElement => { - - - + + { - return record.firstname || String(record.id); + return record.firstname?.toString() || String(record.id); }; diff --git a/admin-ui/src/user/roles.ts b/admin-ui/src/user/roles.ts index 6a93eda..2fbcdf4 100644 --- a/admin-ui/src/user/roles.ts +++ b/admin-ui/src/user/roles.ts @@ -1,10 +1,10 @@ export const ROLES = [ - { - name: "user", - displayName: "User", - }, { name: "admin", displayName: "admin", }, + { + name: "user", + displayName: "User", + }, ]; From 2a5a688e270f66ffa18ea6231115c59d89ab3867 Mon Sep 17 00:00:00 2001 From: "amplication[bot]" Date: Tue, 30 Apr 2024 14:16:10 +0000 Subject: [PATCH 3/4] Amplication build # clvmh0hh80c01n4v23qdldlal Build URL: [https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmh0hh80c01n4v23qdldlal](https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmh0hh80c01n4v23qdldlal) --- .github/workflows/ci-tik-stock.yaml | 37 ++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-tik-stock.yaml b/.github/workflows/ci-tik-stock.yaml index a3a40e1..b98d9b9 100644 --- a/.github/workflows/ci-tik-stock.yaml +++ b/.github/workflows/ci-tik-stock.yaml @@ -10,10 +10,16 @@ on: branches: ["*"] paths: ["server"] +env: + REGISTRY: ghcr.io + jobs: continuous-integration: name: continuous integration runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - name: checkout uses: actions/checkout@v3 @@ -21,7 +27,7 @@ jobs: - name: setup node.js uses: actions/setup-node@v3 with: - node-version: 18.x + node-version: 18 - name: install dependencies run: npm install @@ -34,3 +40,32 @@ jobs: - name: test run: npm test working-directory: server + + - name: docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ghcr.io/victorCampelo/tik-stock + flavor: latest=true + tags: | + type=sha,prefix=sha- + type=ref,event=branch + type=ref,event=pr,prefix=pr- + type=ref,event=tag,prefix=tag- + type=raw,value=${{ github.run_id }},prefix=gh- + + - name: login to image repostiory + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: victorCampelo + password: ${{ secrets.GITHUB_TOKEN }} + + - name: build and push + uses: docker/build-push-action@v3 + with: + context: server + file: server/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 12ae551b957ff0b22ecf6b7f16f969209132243e Mon Sep 17 00:00:00 2001 From: "amplication[bot]" Date: Tue, 30 Apr 2024 17:54:25 +0000 Subject: [PATCH 4/4] Amplication build # clvmot0ji1kss12f9djpjeu8d Build URL: [https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmot0ji1kss12f9djpjeu8d](https://app.amplication.com/cl8axtik2137534501ij0r9rjm51/cl8axtikd137537601ij2dvsnzmq/cl8axttc7131562901h8ghsnt7b9/builds/clvmot0ji1kss12f9djpjeu8d) --- .github/workflows/ci-tik-stock.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-tik-stock.yaml b/.github/workflows/ci-tik-stock.yaml index b98d9b9..3330c93 100644 --- a/.github/workflows/ci-tik-stock.yaml +++ b/.github/workflows/ci-tik-stock.yaml @@ -45,7 +45,7 @@ jobs: id: meta uses: docker/metadata-action@v4 with: - images: ghcr.io/victorCampelo/tik-stock + images: ghcr.io/victorcampelo/tik-stock flavor: latest=true tags: | type=sha,prefix=sha- @@ -58,7 +58,7 @@ jobs: uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} - username: victorCampelo + username: victorcampelo password: ${{ secrets.GITHUB_TOKEN }} - name: build and push