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..3330c93
--- /dev/null
+++ b/.github/workflows/ci-tik-stock.yaml
@@ -0,0 +1,71 @@
+name: continuous integration - tik-stock
+
+concurrency:
+ group: tik-stock
+ cancel-in-progress: true
+
+on:
+ workflow_dispatch:
+ push:
+ 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
+
+ - name: setup node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18
+
+ - 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
+
+ - 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 }}
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/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 @@
-
+
# 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",
+ },
];
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 @@
-
+
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"]
}