Skip to content

Commit

Permalink
Merge pull request #125 from ldhbenecia/feature/mogaco
Browse files Browse the repository at this point in the history
[Feat] 모각코 CRUD 초안 설계 및 구현
  • Loading branch information
ldhbenecia authored Nov 21, 2023
2 parents 071f82d + 83f5e1b commit 7e046d1
Show file tree
Hide file tree
Showing 18 changed files with 263 additions and 5 deletions.
3 changes: 3 additions & 0 deletions app/backend/libs/utils/bigIntToJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};
11 changes: 11 additions & 0 deletions app/backend/prisma/migrations/20231121065729_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
Warnings:
- You are about to alter the column `date` on the `Mogaco` table. The data in that column could be lost. The data in that column will be cast from `DateTime(0)` to `DateTime`.
- You are about to alter the column `deleted_at` on the `Mogaco` table. The data in that column could be lost. The data in that column will be cast from `DateTime(0)` to `DateTime`.
*/
-- AlterTable
ALTER TABLE `Mogaco` MODIFY `date` DATETIME NOT NULL,
MODIFY `updated_at` DATETIME(3) NULL,
MODIFY `deleted_at` DATETIME NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Warnings:
- You are about to alter the column `date` on the `Mogaco` table. The data in that column could be lost. The data in that column will be cast from `DateTime(0)` to `DateTime`.
- You are about to alter the column `deleted_at` on the `Mogaco` table. The data in that column could be lost. The data in that column will be cast from `DateTime(0)` to `DateTime`.
*/
-- AlterTable
ALTER TABLE `Mogaco` MODIFY `date` DATETIME NOT NULL,
MODIFY `deleted_at` DATETIME NULL;
4 changes: 2 additions & 2 deletions app/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ model Mogaco {
address String @db.VarChar(191)
status String @db.VarChar(191)
created_at DateTime @default(now())
updated_at DateTime @updatedAt()
deleted_at DateTime @db.DateTime
updated_at DateTime? @updatedAt()
deleted_at DateTime? @db.DateTime
mogacos Participant[]
@@map("Mogaco")
Expand Down
2 changes: 2 additions & 0 deletions app/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AppController } from './app.controller';
import { MemberModule } from './member/member.module';
import * as redisStore from 'cache-manager-redis-store';
import { getSecret } from 'vault';
import { MogacoModule } from './mogaco/mogaco.module';

@Module({
imports: [
Expand All @@ -16,6 +17,7 @@ import { getSecret } from 'vault';
}),
AuthModule,
MemberModule,
MogacoModule,
],
controllers: [AppController],
providers: [],
Expand Down
2 changes: 1 addition & 1 deletion app/backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class AuthController {

res.cookie('access_token', tokens.access_token, { httpOnly: false, maxAge: getSecret('MAX_AGE_ACCESS_TOKEN') });
res.cookie('refresh_token', tokens.refresh_token, {
httpOnly: false,
httpOnly: true,
maxAge: getSecret('MAX_AGE_REFRESH_TOKEN'),
});

Expand Down
2 changes: 1 addition & 1 deletion app/backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class AuthService {
generateJwt(payload: Payload): Tokens {
const accessToken = this.jwtService.sign(payload, {
expiresIn: getSecret('MAX_AGE_ACCESS_TOKEN'),
secret: getSecret('MAX_AGE_ACCESS_TOKEN'),
secret: getSecret('JWT_ACCESS_SECRET'),
});

const refreshToken = this.jwtService.sign(payload, {
Expand Down
1 change: 1 addition & 0 deletions app/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as cookieParser from 'cookie-parser';
import { ValidationPipe } from '@nestjs/common';
import { setupSwagger } from '../libs/utils/swagger';
import { getSecret, loadSecrets } from 'vault';
import '../libs/utils/bigIntToJson';

async function bootstrap() {
await loadSecrets();
Expand Down
3 changes: 2 additions & 1 deletion app/backend/src/member/member.service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { MemberDto } from './dto/member.dto';
import { getSecret } from 'vault';

@Injectable()
export class MemberService {
constructor(private jwtService: JwtService) {}

async getUserData(encryptedToken: string): Promise<MemberDto> {
const decodedAccessToken = this.jwtService.verify(encryptedToken, { secret: process.env.JWT_ACCESS_SECRET });
const decodedAccessToken = this.jwtService.verify(encryptedToken, { secret: getSecret(`JWT_ACCESS_SECRET`) });
const { providerId, email, nickname, profilePicture } = decodedAccessToken;

return { providerId, email, nickname, profilePicture };
Expand Down
28 changes: 28 additions & 0 deletions app/backend/src/mogaco/dto/create-mogaco.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { IsDateString, IsEnum, IsInt, IsNotEmpty, IsOptional } from 'class-validator';
import { MogacoStatus } from './mogaco-status.enum';

export class CreateMogacoDto {
@IsNotEmpty()
@IsInt()
group_id: number;

@IsNotEmpty()
title: string;

@IsNotEmpty()
contents: string;

@IsNotEmpty()
@IsDateString()
date: string;

@IsNotEmpty()
max_human_count: number;

@IsNotEmpty()
address: string;

@IsOptional()
@IsEnum(MogacoStatus, { message: 'Invalid status' })
status?: string;
}
2 changes: 2 additions & 0 deletions app/backend/src/mogaco/dto/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './create-mogaco.dto';
export * from './mogaco.dto';
5 changes: 5 additions & 0 deletions app/backend/src/mogaco/dto/mogaco-status.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum MogacoStatus {
RECRUITING = '모집 중',
CLOSED = '모집 마감',
COMPLETED = '종료',
}
10 changes: 10 additions & 0 deletions app/backend/src/mogaco/dto/mogaco.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export class MogacoDto {
id: bigint;
group_id: bigint;
title: string;
contents: string;
date: Date;
max_human_count: number;
address: string;
status: string;
}
39 changes: 39 additions & 0 deletions app/backend/src/mogaco/mogaco.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from '@nestjs/common';
import { MogacoService } from './mogaco.service';
import { Mogaco } from '@prisma/client';
import { CreateMogacoDto, MogacoDto } from './dto';
import { MogacoStatusValidationPipe } from './pipes/mogaco-status-validation.pipe';
import { MogacoStatus } from './dto/mogaco-status.enum';

@Controller('mogaco')
export class MogacoController {
constructor(private readonly mogacoService: MogacoService) {}

@Get('/')
async getAllMogaco(): Promise<Mogaco[]> {
return this.mogacoService.getAllMogaco();
}

@Get('/:id')
async getMogacoById(@Param('id', ParseIntPipe) id: number): Promise<MogacoDto> {
return this.mogacoService.getMogacoById(id);
}

@Post('/')
async createMogaco(@Body() createMogacoDto: CreateMogacoDto): Promise<Mogaco> {
return this.mogacoService.createMogaco(createMogacoDto);
}

@Delete('/:id')
async deleteMogaco(@Param('id', ParseIntPipe) id: number): Promise<void> {
return this.mogacoService.deleteMogaco(id);
}

@Patch('/:id/status')
updateMogacoStatus(
@Param('id', ParseIntPipe) id: number,
@Body('status', MogacoStatusValidationPipe) status: MogacoStatus,
): Promise<Mogaco> {
return this.mogacoService.updateMogacoStatus(id, status);
}
}
11 changes: 11 additions & 0 deletions app/backend/src/mogaco/mogaco.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { MogacoService } from './mogaco.service';
import { MogacoController } from './mogaco.controller';
import { MogacoRepository } from './mogaco.repository';
import { PrismaService } from 'libs/utils/prisma.service';

@Module({
controllers: [MogacoController],
providers: [MogacoService, MogacoRepository, PrismaService],
})
export class MogacoModule {}
82 changes: 82 additions & 0 deletions app/backend/src/mogaco/mogaco.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../libs/utils/prisma.service';
import { Mogaco } from '@prisma/client';
import { MogacoStatus } from './dto/mogaco-status.enum';
import { CreateMogacoDto, MogacoDto } from './dto';

@Injectable()
export class MogacoRepository {
constructor(private prisma: PrismaService) {}

async getAllMogaco(): Promise<Mogaco[]> {
return this.prisma.mogaco.findMany();
}

async getMogacoById(id: number): Promise<MogacoDto> {
const mogaco = await this.prisma.mogaco.findUnique({
where: { id },
});

if (!mogaco) {
throw new NotFoundException(`Mogaco with id ${id} not found`);
}

return {
id: mogaco.id,
group_id: mogaco.group_id,
title: mogaco.title,
contents: mogaco.contents,
date: mogaco.date,
max_human_count: mogaco.max_human_count,
address: mogaco.address,
status: mogaco.status,
};
}

async createMogaco(createMogacoDto: CreateMogacoDto): Promise<Mogaco> {
try {
const { group_id, title, contents, max_human_count, address, date } = createMogacoDto;

const mogaco = await this.prisma.mogaco.create({
data: {
group_id,
title,
contents,
max_human_count,
address,
status: MogacoStatus.RECRUITING,
date: new Date(date),
},
});

return mogaco;
} catch (error) {
throw new Error(`Failed to create Mogaco: ${error.message}`);
}
}

async deleteMogaco(id: number): Promise<void> {
const mogaco = await this.prisma.mogaco.findUnique({
where: { id },
});

if (!mogaco) {
throw new NotFoundException(`Mogaco with id ${id} not found`);
}

await this.prisma.mogaco.delete({
where: { id },
});
}

async updateMogacoStatus(mogaco: MogacoDto): Promise<Mogaco> {
try {
return await this.prisma.mogaco.update({
where: { id: mogaco.id },
data: { status: mogaco.status },
});
} catch (error) {
throw new Error(`Failed to update Mogaco status: ${error.message}`);
}
}
}
32 changes: 32 additions & 0 deletions app/backend/src/mogaco/mogaco.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Injectable } from '@nestjs/common';
import { MogacoRepository } from './mogaco.repository';
import { Mogaco } from '@prisma/client';
import { CreateMogacoDto, MogacoDto } from './dto';
import { MogacoStatus } from './dto/mogaco-status.enum';

@Injectable()
export class MogacoService {
constructor(private mogacoRepository: MogacoRepository) {}

async getAllMogaco(): Promise<Mogaco[]> {
return this.mogacoRepository.getAllMogaco();
}

async getMogacoById(id: number): Promise<MogacoDto> {
return this.mogacoRepository.getMogacoById(id);
}

async createMogaco(createMogaco: CreateMogacoDto): Promise<Mogaco> {
return this.mogacoRepository.createMogaco(createMogaco);
}

async deleteMogaco(id: number): Promise<void> {
return this.mogacoRepository.deleteMogaco(id);
}

async updateMogacoStatus(id: number, status: MogacoStatus): Promise<Mogaco> {
const mogaco = await this.getMogacoById(id);
mogaco.status = status;
return this.mogacoRepository.updateMogacoStatus(mogaco);
}
}
21 changes: 21 additions & 0 deletions app/backend/src/mogaco/pipes/mogaco-status-validation.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { BadRequestException, PipeTransform } from '@nestjs/common';
import { MogacoStatus } from '../dto/mogaco-status.enum';

export class MogacoStatusValidationPipe implements PipeTransform {
readonly StatusOptions = [MogacoStatus.RECRUITING, MogacoStatus.CLOSED, MogacoStatus.COMPLETED];

transform(value: any) {
value = value.toUpperCase();

if (!this.isStatusValid(value)) {
throw new BadRequestException(`${value} isn't in the status options`);
}

return value;
}

private isStatusValid(status: any) {
const index = this.StatusOptions.indexOf(status);
return index !== -1;
}
}

0 comments on commit 7e046d1

Please sign in to comment.