- 일정 생성 기능 1차 구현
This commit is contained in:
geonhee-min
2025-12-10 17:14:09 +09:00
parent 9578b37c64
commit bb79557876
8 changed files with 210 additions and 29 deletions

View File

@@ -1,17 +1,14 @@
import { IsArray, IsDate, IsString } from '@nestjs/class-validator'; import { IsArray, IsDateString, IsString } from '@nestjs/class-validator';
export class CreateRequestDto { export class CreateRequestDto {
@IsString() @IsString()
name: string; name: string;
@IsDate() @IsDateString()
startDate: Date; startDate: string;
@IsDate() @IsDateString()
endDate: Date; endDate: string;
@IsString()
status: string;
@IsString() @IsString()
content: string; content: string;

View File

@@ -0,0 +1,3 @@
import { BaseResponseDto } from "src/common/dto/base-response.dto";
export class CreateResponseDto extends BaseResponseDto {}

View File

@@ -0,0 +1,7 @@
export { CreateRequestDto as CreateRequest } from './create/create-request.dto';
export { CreateResponseDto as CreateResponse } from './create/create-response.dto'
export { ListRequestDto as ListRequest } from './list/list-request.dto';
export { ListResponseDto as ListResponse } from './list/list-response.dto';
export { DetailResponseDto as DetailResponse } from './detail/detail-response.dto';

View File

@@ -0,0 +1,27 @@
import { Body, Controller, Get, Param, Post, Req, UseGuards } from "@nestjs/common";
import { JwtAccessAuthGuard } from "src/middleware/auth/guard/access-token.guard";
import { ScheduleService } from "./schedule.service";
import * as DTO from './dto';
@UseGuards(JwtAccessAuthGuard)
@Controller('schedule')
export class ScheduleController {
constructor(private readonly scheduleService: ScheduleService) {}
@Post('/')
async getList(@Req() req, @Body() data: DTO.ListRequest): Promise<DTO.ListResponse> {
const result = await this.scheduleService.getList(req.user.id, data);
return result;
}
@Get('/:id')
async getDetail(@Param('id') id: string): Promise<DTO.DetailResponse> {
const result = await this.scheduleService.getDetail(id);
return result;
}
@Post('/create')
async create(@Req() req, @Body() data: DTO.CreateRequest): Promise<DTO.CreateResponse> {
const result = await this.scheduleService.create(req.user.id, data);
return result;
}
}

View File

@@ -0,0 +1,13 @@
import { forwardRef, Module } from "@nestjs/common";
import { AuthModule } from "src/middleware/auth/auth.module";
import { ScheduleController } from "./schedule.controller";
import { ScheduleService } from "./schedule.service";
import { ScheduleRepo } from "./schedule.repo";
@Module({
imports: [forwardRef(() => AuthModule)],
controllers: [ScheduleController],
providers: [ScheduleService, ScheduleRepo],
exports: [ScheduleService, ScheduleRepo]
})
export class ScheduleModule {}

View File

@@ -1,43 +1,99 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import * as schema from 'drizzle/schema'; import * as schema from 'drizzle/schema';
import { countDistinct, and, eq } from 'drizzle-orm'; import { countDistinct, and, eq, gt, gte, lte, like, inArray } from 'drizzle-orm';
import { NodePgDatabase } from 'drizzle-orm/node-postgres'; import { NodePgDatabase } from 'drizzle-orm/node-postgres';
import * as DTO from './dto';
import { Converter } from 'src/util/converter';
@Injectable() @Injectable()
export class ScheduleRepo { export class ScheduleRepo {
constructor(@Inject('DRIZZLE') private readonly db: NodePgDatabase<typeof schema>) {} constructor(@Inject('DRIZZLE') private readonly db: NodePgDatabase<typeof schema>) {}
async getList(accountId: string) { async getList(accountId: string, data: DTO.ListRequest) {
const { startDate, endDate, name, status, styleList, typeList } = data;
const schedule = schema.schedule;
const result = await this
.db
.select({
id: schedule.id,
name: schedule.name,
startDate: schedule.startDate,
endDate: schedule.endDate,
status: schedule.status,
style: schedule.style,
type: schedule.style,
})
.from(schedule)
.where(
and(
eq(schedule.owner, accountId),
startDate ? gte(schedule.startDate, Converter.formatDateToSqlDate(startDate)) : undefined,
endDate ? lte(schedule.endDate, Converter.formatDateToSqlDate(endDate)) : undefined,
name ? like(schedule.name, `%${name}%`) : undefined,
(typeList && typeList.length > 0) ? inArray(schedule.type, typeList) : undefined,
(styleList && styleList.length > 0) ? inArray(schedule.style, styleList) : undefined,
status ? eq(schedule.status, status) : undefined,
eq(schedule.isDeleted, false)
)
)
const resultData = result.map((schedule) => {
return {
id: schedule.id,
name: schedule.name,
type: schedule.type,
style: schedule.style,
status: schedule.status,
startDate: new Date(schedule.startDate),
endDate: new Date(schedule.endDate)
}
})
return resultData;
}
async getDetail(id: string) {
const schedule = schema.schedule;
const result = await this const result = await this
.db .db
.select() .select()
.from(schema.schedule) .from(schedule)
.where( .where(
and( and(
eq(schema.schedule.owner, accountId), eq(schedule.id, id),
eq(schema.schedule.isDeleted, false) eq(schedule.isDeleted, false)
) )
); );
return result; return result;
} }
async getDetail(id: string) { async create(
const result = await this accountId: string,
name: string,
startDate: string,
endDate: string,
startTime: string,
endTime: string,
style: string,
content: string,
type: string
) {
return await this
.db .db
.select() .insert(schema.schedule)
.from(schema.schedule) .values({
.where( name: name,
and( content: content,
eq(schema.schedule.id, id), owner: accountId,
eq(schema.schedule.isDeleted, false) startDate: startDate,
) endDate: endDate,
); startTime: startTime,
endTime: endTime,
return result[0]; status: 'yet',
} style: style,
type: type
async create() { });
} }
} }

View File

@@ -0,0 +1,69 @@
import { Injectable } from "@nestjs/common";
import { ScheduleRepo } from "./schedule.repo";
import * as DTO from './dto';
@Injectable()
export class ScheduleService {
constructor(
private readonly scheduleRepo: ScheduleRepo
) {}
async getList(accountId: string, data: DTO.ListRequest): Promise<DTO.ListResponse> {
const result = await this.scheduleRepo.getList(accountId, data);
return {
success: true,
data: result
};
}
async getDetail(id: string) {
const result = await this.scheduleRepo.getDetail(id);
if (result.length < 1) {
return {
success: false,
message: '존재하지 않는 일정입니다.'
};
}
const data = {
...result[0],
startDate: new Date(result[0].startDate),
endDate: new Date(result[0].endDate)
}
return {
success: true,
data: data
};
}
async create(accountId: string, data: DTO.CreateRequest): Promise<DTO.CreateResponse> {
const { name, content, startDate, endDate, startTime, endTime, style, type } = data;
const result = await this.scheduleRepo.create(
accountId,
name,
startDate,
endDate,
startTime,
endTime,
style,
content,
type
);
if (result.rowCount) {
return {
success: true,
message: "일정이 생성되었습니다."
};
} else {
return {
success: false,
message: "일정 생성에 실패하였습니다."
}
}
}
}

View File

@@ -8,4 +8,13 @@ export class Converter {
static comparePassword(rawPassword: string, hashedPassword: string) { static comparePassword(rawPassword: string, hashedPassword: string) {
return bcrypt.compareSync(rawPassword, hashedPassword); return bcrypt.compareSync(rawPassword, hashedPassword);
} }
static formatDateToSqlDate(date: string): string {
const targetDate = new Date(date);
const year = targetDate.getUTCFullYear();
const month = (targetDate.getUTCMonth() + 1).toString().padStart(2, '0');
const day = (targetDate.getUTCDate()).toString().padStart(2, '0');
return `${year}-${month}-${day}`;
}
} }