Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a8426de
feat: CS 게시글에 관리자 공지사항 타입 추가
hjlee5701 Feb 2, 2025
62cfee2
feat: CSBoard 댓글 생성/삭제에 따른 게시글 업데이트트
hjlee5701 Feb 2, 2025
13b515d
Merge branch 'main' of https://github.com/coding-jjun/Giftogether_bac…
hjlee5701 Mar 8, 2025
a1e1cd9
refactor: CsBoard.create 반환타입 DTO 로 수정 및 fundUuid 추가
hjlee5701 Mar 15, 2025
2dc3756
Merge branch 'main' of https://github.com/coding-jjun/Giftogether_bac…
hjlee5701 Mar 15, 2025
4392837
feat: CsBoard.uptAt 추가
hjlee5701 Mar 15, 2025
ef70cf2
refactor: CsComment.create 로직 개선
hjlee5701 Mar 15, 2025
590b912
refactor : CsBoard.delete 요청 시, 댓글 포함한 삭제 처리
hjlee5701 Mar 15, 2025
da468ec
refactor: CsBoard.findOne 반환타입 및 비밀글 유효성 검사 추가가
hjlee5701 Mar 15, 2025
491e4f2
fix: CreateCsBoard 의 fundUuid optional 처리리
hjlee5701 Mar 15, 2025
10d37c9
refactor: CsBoard.update 반환 타입 수정 및 수정 요청 중 fundUuid 추가
hjlee5701 Mar 15, 2025
ae44d91
feat: CsBoardNotFound, CsCommentNotFound 예외 추가가
hjlee5701 Mar 15, 2025
2162c66
refactor: CsComment.update 로직 개선
hjlee5701 Mar 15, 2025
22169e5
refactor: CsCommnet.delete 로직 개선
hjlee5701 Mar 15, 2025
1a06098
refactor: CsBoard.findAll 반환타입 DTO 로 수정
hjlee5701 Mar 15, 2025
1526ed9
feat: 마감 처리된 CsBoard 에 댓글 생성 막기 (예외 처리)
hjlee5701 Mar 15, 2025
6ff7e2c
feat: 마감 처리된 CsBoard 의 업데이트 막기
hjlee5701 Mar 15, 2025
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
14 changes: 13 additions & 1 deletion src/entities/cs-board.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CsType } from "src/enums/cs-type.enum";
import { Column, CreateDateColumn, DeleteDateColumn, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { Column, CreateDateColumn, DeleteDateColumn, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
import { CsComment } from "./cs-comment.entity";
import { User } from "./user.entity";

Expand Down Expand Up @@ -29,6 +29,9 @@
@OneToMany(() => CsComment, (csComment) => csComment.csBoard)
csComments: CsComment[];

@Column('bool', { default: true }) // 마지막 댓글 작성자가 관리자인지 여부에 따라 업데이트 (관리자 페이지)
isUserWaiting: boolean;

@Column({default: false})
isSecret: boolean;

Expand All @@ -37,8 +40,17 @@

@Column('bool', { default: false })
isDel: boolean;

@Column({nullable: true})
fundUuid: string;

@CreateDateColumn()
regAt: Date;

@UpdateDateColumn()
uptAt: Date;

@Column({ type: 'timestamp', nullable: true }) // 마지막 댓글의 생성 날짜 (관리자 페이지)
lastComAt: Date;

}
2 changes: 2 additions & 0 deletions src/enums/cs-type.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export enum CsType {
Payment='payment',
Delivery='delivery',
Extra='extra',
Announcement = 'announcement',
Refund = 'refund',


}
5 changes: 5 additions & 0 deletions src/enums/error-code.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,9 @@ export enum ErrorCode {
InconsistentAggregationError = '1700',
InvalidPage = '1701',
InvalidLimit = '1702',

// CsBoard & CsComment
CsBoardNotFound = "1900",
CsCommentNotFound = "1901",
CsBoardIsComplete = "1902",
}
5 changes: 5 additions & 0 deletions src/enums/error-message.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,9 @@ export enum ErrorMsg {
InconsistentAggregationError = '애그리게이션이 일관적이지 않습니다.',
InvalidPage = '잘못된 페이지 번호입니다.',
InvalidLimit = '잘못된 페이지 크기입니다.',

// CsBoard & CsComment
CsBoardNotFound = '문의 게시글이 존재하지 않습니다.',
CsCommentNotFound = '문의 댓글이 존재하지 않습니다.',
CsBoardIsComplete = '마감된 문의 게시글입니다.'
}
12 changes: 8 additions & 4 deletions src/features/cs-board/cs-board.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class CsBoardController {
const user = req.user as { user: User } as any;
return {
message: "CS 게시글 조회 완료",
data: await this.csService.findOneCsBoard(csId, user.userId),
data: await this.csService.findOne(csId, user),
}
}

Expand All @@ -35,9 +35,10 @@ export class CsBoardController {

return {
message: "CS 게시글 전체 조회 완료",
data: await this.csService.findAllCsBoards(csType),
data: await this.csService.findAll(csType),
}
}

@Post()
@UseGuards(JwtExtendedAuthGuard)
async createCsBoard(
Expand All @@ -62,17 +63,20 @@ export class CsBoardController {
const user = req.user as { user: User } as any;
return {
message: "CS 게시글 수정 완료",
data: await this.csService.update(csId, updateCsBoard, user.userId),
data: await this.csService.update(csId, updateCsBoard, user),
}
}

@Delete(':csId')
@UseGuards(JwtExtendedAuthGuard)
async deleteCsBoard(
@Req() req: Request,
@Param('csId', ParseIntPipe) csId: number,
): Promise<CommonResponse>{
const user = req.user as { user: User } as any;
return {
message: "CS 게시글 삭제 완료",
data: await this.csService.delete(csId),
data: await this.csService.delete(csId, user),
}
}

Expand Down
195 changes: 124 additions & 71 deletions src/features/cs-board/cs-board.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,81 @@ import { GiftogetherExceptions } from 'src/filters/giftogether-exception';
import { UpdateCsBoardDto } from './dto/update-cs-board.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { CsType } from 'src/enums/cs-type.enum';

import { CsComment } from 'src/entities/cs-comment.entity';
import { CsCommentDto } from '../cs-comment/dto/cs-comment.dto';


function convertToCsBoardDto(csBoard: CsBoard, csComments: CsCommentDto[]): CsBoardDto {

return new CsBoardDto(
csBoard.csId,
csBoard.csUser.userNick,
csBoard.csTitle,
csBoard.csCont,
csBoard.csType,
csBoard.isSecret,
csBoard.isUserWaiting,
csBoard.isComplete,
csBoard.regAt,
csBoard.uptAt,
csBoard.fundUuid,
csComments
);
}
function convertToCsCommentsDto(csComment: CsComment): CsCommentDto {
return new CsCommentDto(
csComment.csComId,
csComment.csComUser.userNick,
csComment.csComCont,
csComment.regAt,
csComment.isMod
)
}
@Injectable()
export class CsBoardService {
constructor(
@InjectRepository(CsBoard)
private readonly csRepository: Repository<CsBoard>,
@InjectRepository(CsComment)
private readonly csComRepository: Repository<CsComment>,
private readonly validCheck: ValidCheck,
private readonly g2gException: GiftogetherExceptions

){}

async findCsBoardByCsId(csId: number, userId: number) {
const csBoard = await this.csRepository.findOne({
where: { csId },
relations: ['csUser', 'csComments']
});
// 비밀글
if(csBoard.isSecret){
// 작성자 & 관리자가 아닐 경우
if(csBoard.csUser.userId != userId && ! csBoard.csUser.isAdmin) {
// throw this.g2gException.NoPermissionCsBoard;
}
// 상세 조회
async findOne(csId: number, user: User) {
const csBoard = await this.csRepository
.createQueryBuilder('csBoard')
.leftJoinAndSelect('csBoard.csUser', 'csUser')
.leftJoinAndSelect('csBoard.csComments', 'csComments', 'csComments.isDel = false')
.leftJoinAndSelect('csComments.csComUser', 'csComUser')
.where('csBoard.csId = :csId AND csBoard.isDel = false', { csId })
.getOne();

if (csBoard.isSecret && user.isAdmin) {
await this.validCheck.verifyUserMatch(csBoard.csUser.userId, user.userId);
}
return csBoard;
}

//
async findOneCsBoard(csId: number, userId: number) {
const csBoard = await this.findCsBoardByCsId(csId, userId);
const responseBoard = new CsBoardDto();
responseBoard.userNick = csBoard.csUser.userNick;
return Object.assign(responseBoard, csBoard);
const csCommentsDto = csBoard?.csComments.map(convertToCsCommentsDto) ?? [];
return convertToCsBoardDto(csBoard, csCommentsDto);
}


// TODO 카테고리 조회
async findAllCsBoards(csType:CsType) {
console.log(csType);
return await this.csRepository
.createQueryBuilder('csBoard')
.leftJoinAndSelect('csBoard.csUser', 'csUser')
.where('csBoard.csType = :csType', { csType })
.andWhere('csBoard.isDel = :isDel', { isDel: false })
.getMany();
// console.log(">>>>> csBoard " , csBoards);
// const result = csBoards.map(() => new CsBoardDto());

// console.log("result >>>>> ", result)

// return result;

async findAll(csType: CsType | null): Promise<CsBoardDto[]> {
const query = this.csRepository.createQueryBuilder('csBoard')
.leftJoinAndSelect('csBoard.csUser', 'csUser')
.andWhere('csBoard.isDel = false');

if (csType !== null) {
query.andWhere('csBoard.csType = :csType', { csType });
} else {
query.andWhere('csBoard.csType IS NULL');
}

const csBoards = await query.getMany();
return csBoards?.map(csBoard => convertToCsBoardDto(csBoard, null)) ?? [];
}


async create(createCsBoard: CreateCsBoardDto, user: User) {

Expand All @@ -69,52 +92,82 @@ export class CsBoardService {

// 게시자가 관리자일 경우 : 댓글 막기
if(user.isAdmin){
csBoard.isComplete = true;
}
const newBoard = await this.csRepository.save(csBoard);
console.log("Save new Board >>> ", newBoard);
return newBoard
csBoard.isComplete = true;
}
// 관리자 공지사항
if(CsType.Announcement == createCsBoard.csType) {
csBoard.isComplete = true;
csBoard.isUserWaiting = false;
}
const savedBoard = await this.csRepository.save(csBoard);
return convertToCsBoardDto(savedBoard, null)
}

async update(csId: number, updateCsBoardDto: UpdateCsBoardDto, userId: number) {
async update(csId: number, updateCsBoardDto: UpdateCsBoardDto, user: User) {

const beforeCsBoard = await this.csRepository.findOne({
where: { csId },
relations: ['csUser']
});
console.log("find target csBoard >>> ", beforeCsBoard);
await this.validCheck.verifyUserMatch(beforeCsBoard.csUser.userId, userId);
const csBoard = await this.csRepository
.createQueryBuilder('csBoard')
.leftJoinAndSelect('csBoard.csUser', 'csUser')
.where('csBoard.csId = :csId', { csId })
.andWhere('csBoard.isDel = false')
.andWhere('csBoard.isComplete = false')
.getOne();

if (!csBoard) {
throw this.g2gException.CsBoardNotFound;
}

if (!beforeCsBoard) {
throw this.g2gException.AccountNotFound;
if (!user.isAdmin && csBoard.isComplete) {
throw this.g2gException.CsBoardIsComplete;
}

Object.assign(beforeCsBoard, updateCsBoardDto);
console.log("find target csBoard.csId >>> ", csBoard.csId);
if (!user.isAdmin) {
await this.validCheck.verifyUserMatch(csBoard.csUser.userId, user.userId);
}

Object.assign(csBoard, updateCsBoardDto);

console.log("After update csBoard >>> ", beforeCsBoard);
await this.csRepository.save(csBoard);

return await this.csRepository.save(beforeCsBoard);
}

async delete(csId: number) {
const userId = 1;
console.log("Success update csBoard >>> ", csId);

return convertToCsBoardDto(csBoard, null)
}

async delete(csId: number, user: User) {
const csBoard = await this.csRepository.findOne({
where: { csId },
// relations: ['csUser']
});
// return await this.csRepository.delete(csBoard);
return await this.csRepository.delete({
csId: csId
where: { csId, isDel: false } ,
relations: ['csUser', 'csComments', 'csComments.csComUser']
});
// console.log("find target csBoard >>> ", csBoard);
// await this.validCheck.verifyUserMatch(csBoard.csUser.userId, userId);

// if (!csBoard) {
// throw this.g2gException.AccountNotFound;
// }
if (!csBoard) {
throw this.g2gException.CsBoardNotFound;
}

console.log("find target csBoard before Delete >>> ", csBoard.csId);
if (!user.isAdmin) {
await this.validCheck.verifyUserMatch(csBoard.csUser.userId, user.userId);
}

csBoard.isDel = true;
const csComments = csBoard.csComments;

for (let csComment of csComments) {
csComment.isDel = true;
}

await this.csComRepository.save(csComments)
await this.csRepository.save(csBoard);

console.log("Success Delete CsBoard >> ", csBoard.csId);
const convertCsComments: CsCommentDto[] = [];
for (const csComment of csComments) {
convertCsComments.push(convertToCsCommentsDto(csComment));
}

// csBoard.isDel = true;
// return await this.csRepository.save(csBoard);
return convertToCsBoardDto(csBoard, convertCsComments);
}
}

}
5 changes: 4 additions & 1 deletion src/features/cs-board/dto/create-cs-board.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsNotEmpty } from "class-validator";
import { IsNotEmpty, IsOptional } from "class-validator";
import { CsType } from "src/enums/cs-type.enum";

export class CreateCsBoardDto {
Expand All @@ -14,4 +14,7 @@ export class CreateCsBoardDto {
@IsNotEmpty()
isSecret: boolean;

@IsOptional()
fundUuid?: string

}
Loading