Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): add auth, fix prisma migrate problem #5

Merged
merged 2 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion apps/backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ POSTGRES_DB="example_db"

DATABASE_URL="postgresql://example_user:example_password@localhost:5432/example_db?schema=public"

PORT=123
PORT=123

JWT_SECRET="SECRET"

NODE_ENV=example
11 changes: 7 additions & 4 deletions apps/backend/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
},
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"standard-with-typescript"
"plugin:prettier/recommended"
],
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"env": {
"jest": true
},
"files": ["*.ts", "*.tsx", "tests/**/*"],
"extends": ["plugin:@typescript-eslint/recommended"]
}
],
Expand Down Expand Up @@ -44,6 +46,7 @@
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-useless-constructor": 0,
"@typescript-eslint/space-before-function-paren": 0
"@typescript-eslint/space-before-function-paren": 0,
"@typescript-eslint/member-delimiter-style": 0
}
}
2 changes: 1 addition & 1 deletion apps/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM postgres:15
FROM postgres:13

ENV POSTGRES_USER=${POSTGRES_USER}
ENV POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/Dockerfile.development
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM postgres:15
FROM postgres:13

ARG POSTGRES_USER
ARG POSTGRES_PASSWORD
Expand Down
11 changes: 11 additions & 0 deletions apps/backend/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
roots: ["."],
transform: {
"^.+\\.ts?$": "ts-jest",
},
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.ts?$",
moduleFileExtensions: ["ts", "js", "json", "node"],
collectCoverage: true,
clearMocks: true,
coverageDirectory: "coverage",
};
138 changes: 66 additions & 72 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,35 @@
"build": "nest build",
"format": "prettier --config .prettierrc.json --write \"{src,apps,libs,test}/**/*.{json,ts}\"",
"start": "nest start",
"dev": "nest start --watch",
"dev": "dotenv -e .env.development -- nest start --watch",
"prod": "node dist/main",
"start:studio": "npx prisma studio",
"start:studio": "prisma studio",
"start:studio:dev": "dotenv -e .env.development -- prisma studio",
"generate:db": "prisma generate",
"generate:db:dev": "dotenv -e .env.development -- npx prisma generate",
"init:prisma": "npx prisma init",
"init:prisma:dev": "dotenv -e .env.development -- npx prisma init",
"migrate:deploy": "prisma migrate deploy",
"migrate:dev:deploy": "dotenv -e .env.development -- prisma migrate deploy",
"migrate:dev:deploy": "dotenv -e .env.development -- prisma migrate dev",
"debug": "nest start --debug --watch",
"db:reset": "prisma migrate reset",
"db:reset:dev": "dotenv -e .env.development -- prisma migrate reset",
"db:list": "docker ps",
"db:rm": "docker compose rm devixid -s -f -v",
"db:up": "docker compose up devixid -d",
"db:restart": "pnpm db:rm && pnpm db:up && sleep 1 && pnpm migrate:deploy",
"db:dev:rm": "docker compose rm devixid_dev -s -f -v",
"db:dev:up": "docker compose up devixid_dev -d",
"db:dev:restart": "pnpm db:dev:rm && pnpm db:dev:up && sleep 1 && pnpm migrate:dev:deploy",
"db:rm:dev": "docker compose rm devixid_dev -s -f -v",
"db:up:dev": "docker compose up devixid_dev -d",
"db:restart:dev": "pnpm db:dev:rm && pnpm db:dev:up && sleep 2 && pnpm migrate:dev:deploy",
"lint": "eslint \"{src,apps,libs,test}/**/*.{js,jsx,md,mdx,ts,tsx}\"",
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.{js,jsx,md,mdx,ts,tsx}\" --fix",
"type-check": "tsc --project tsconfig.json --pretty --noEmit",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "dotenv -e .env.test -- jest --config --watch --no-cache ./test/jest-e2e.json",
"pretest:e2e": "pnpm db:test:restart"
"test": "jest --config ./jest.config.js",
"test:watch": "jest --watch --config ./jest.config.js",
"test:cov": "jest --coverage --config ./jest.cofig.js",
"test:dev": "dotenv -e .env.development -- jest --config ./jest.config.js",
"test:watch:dev": "dotenv -e .env.development -- jest --watch --config ./jest.config.js",
"test:cov:dev": "dotenv -e .env.development jest --coverage --config ./jest.cofig.js"
},
"lint-staged": {
"**/*.{html,css,scss,less,json,js,jsx,ts,tsx,md,mdx}\"": [
Expand All @@ -42,72 +49,59 @@
}
},
"dependencies": {
"@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.3.1",
"@nestjs/core": "^9.0.0",
"@nestjs/jwt": "^10.0.2",
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.0.0",
"@prisma/client": "^4.11.0",
"argon2": "^0.30.3",
"@nestjs/common": "^10.4.1",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.4.1",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.4.1",
"@trpc/server": "^10.45.2",
"argon2": "^0.40.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"helmet": "^6.0.1",
"module-alias": "^2.2.2",
"pactum": "^3.3.2",
"passport": "^0.6.0",
"class-validator": "^0.14.1",
"cross-env": "^7.0.3",
"express": "^4.19.2",
"helmet": "^7.1.0",
"joi": "^17.13.3",
"module-alias": "^2.2.3",
"pactum": "^3.7.1",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.2.0"
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@types/express": "^4.17.13",
"@types/jest": "29.2.4",
"@types/node": "18.11.18",
"@types/passport-jwt": "^3.0.8",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@jest/globals": "^29.7.0",
"@nestjs/cli": "^10.4.4",
"@nestjs/testing": "^10.4.1",
"@prisma/client": "^5.18.0",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/passport-jwt": "^4.0.1",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.0.0",
"@typescript-eslint/utils": "^7.18.0",
"cz-conventional-changelog": "^3.3.0",
"dotenv-cli": "^7.1.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard-with-typescript": "^34.0.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.6.1",
"eslint-plugin-prettier": "^4.0.0",
"dotenv-cli": "^7.4.2",
"eslint": "^8.56.0",
"eslint-config-love": "^62.0.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-promise": "^6.1.1",
"jest": "29.3.1",
"prettier": "^2.3.2",
"prisma": "^4.11.0",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "29.0.3",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.1.1",
"typescript": "^4.7.4",
"webpack": "^5.76.0"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
"jest": "^29.7.0",
"prettier": "^3.1.1",
"prisma": "^5.18.0",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.4",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "5.5.4",
"webpack": "^5.93.0"
},
"_moduleAliases": {
"@": "./dist"
Expand Down
35 changes: 35 additions & 0 deletions apps/backend/prisma/migrations/20240820041805_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-- CreateEnum
CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'SUPER_ADMIN');

-- CreateTable
CREATE TABLE "portfolios" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"url" TEXT NOT NULL,
"image" VARCHAR(255) NOT NULL,
"keywords" TEXT[],
"uploaderId" INTEGER NOT NULL,

CONSTRAINT "portfolios_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"email" TEXT NOT NULL,
"hash" TEXT NOT NULL,
"userName" TEXT,
"fullName" TEXT,
"role" "UserRole" NOT NULL DEFAULT 'ADMIN',

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "portfolios_title_keywords_idx" ON "portfolios"("title", "keywords");

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
3 changes: 3 additions & 0 deletions apps/backend/prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
6 changes: 4 additions & 2 deletions apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
provider = "prisma-client-js"
}
Expand All @@ -20,6 +23,7 @@ model Portfolio {
uploaderId Int

@@index([title, keywords])
@@map("portfolios")
}

model User {
Expand All @@ -33,8 +37,6 @@ model User {
userName String?
fullName String?
role UserRole @default(ADMIN)

@@map("users")
}

enum UserRole {
Expand Down
11 changes: 11 additions & 0 deletions apps/backend/src/admin/admin.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PrismaClient, type User } from "@prisma/client";
import { Injectable } from "@nestjs/common";

@Injectable()
export class AdminService {
private readonly prisma = new PrismaClient();

async findById(id: number): Promise<User | null> {
return await this.prisma.user.findUnique({ where: { id } });
}
}
16 changes: 16 additions & 0 deletions apps/backend/src/admin/guard/admin.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
type CanActivate,
type ExecutionContext,
Injectable,
} from "@nestjs/common";
import { type Observable } from "rxjs";

@Injectable()
export class AdminGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
return true;
}
}
3 changes: 3 additions & 0 deletions apps/backend/src/admin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./admin.service";
export * from "./guard/admin.guard";
export * from "./middleware/admin.middleware";
9 changes: 9 additions & 0 deletions apps/backend/src/admin/middleware/admin.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Injectable, type NestMiddleware } from "@nestjs/common";
import { type Request, type Response } from "express";

@Injectable()
export class AdminMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: () => void) {
next();
}
}
1 change: 0 additions & 1 deletion apps/backend/src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { AppService } from "./app.service";

@Controller("/")
export class AppController {
// eslint-disable-next-line prettier/prettier
constructor(private readonly appService: AppService) {}

@Get()
Expand Down
39 changes: 33 additions & 6 deletions apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
import { Module } from "@nestjs/common";
import {
type NestModule,
type MiddlewareConsumer,
Module,
RequestMethod,
} from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { ConfigModule } from "@nestjs/config";
import { PassportModule } from "@nestjs/passport";
import { JwtModule } from "@nestjs/jwt";
import { AppService } from "./app.service";
import { AuthService } from "./auth/auth.service";
import { AdminService } from "./admin/admin.service";
import { AuthController } from "./auth/auth.controller";
import { JwtStrategy } from "./auth";
import { LoggerMiddleware } from "./log/log.middleware";

@Module({
imports: [ConfigModule.forRoot({ isGlobal: true })],
controllers: [AppController],
providers: [AppService],
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
PassportModule.register({ defaultStrategy: "jwt" }),
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: process.env.JWT_EXPIRES_IN },
}),
],
controllers: [AppController, AuthController],
providers: [AppService, AuthService, AdminService, JwtStrategy],
})
export class AppModule {}
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: "*", method: RequestMethod.ALL });
}
}
Loading
Loading