diff --git a/main-project/src/chats/chats-controller.service.ts b/main-project/src/chats/chats-controller.service.ts index 71ccf9f2..807c6aae 100644 --- a/main-project/src/chats/chats-controller.service.ts +++ b/main-project/src/chats/chats-controller.service.ts @@ -11,6 +11,7 @@ import { BoardsRepository } from 'src/boards/repository/board.repository'; import { NoticeType } from 'src/common/configs/notice-type.config'; import { UserType } from 'src/common/configs/user-type.config'; import { NoticeChats } from 'src/notices/entity/notice-chat.entity'; +import { Notices } from 'src/notices/entity/notices.entity'; import { NoticeChatsRepository } from 'src/notices/repository/notices-chats.repository'; import { NoticesRepository } from 'src/notices/repository/notices.repository'; import { EntityManager, Timestamp } from 'typeorm'; @@ -295,13 +296,12 @@ export class ChatsControllerService { ? NoticeType.INVITE_HOST : NoticeType.INVITE_GUEST; - const noticeChat: NoticeChats = - await this.noticeChatsRepository.getNoticeChat({ - userNo, - targetUserNo, - type: noticeType, - chatRoomNo, - }); + const noticeChat: Notices = await this.noticeChatsRepository.getNotice({ + userNo, + targetUserNo, + type: noticeType, + chatRoomNo, + }); if (noticeChat) { throw new BadRequestException('이미 초대를 보낸 상태입니다.'); } @@ -332,15 +332,17 @@ export class ChatsControllerService { async acceptInvitation( userNo: number, + manager: EntityManager, chatRoomNo: number, - { senderNo, receiverNo, type }: AcceptInvitationDto, + { senderNo, type }: AcceptInvitationDto, ): Promise { - if (userNo !== receiverNo) { - throw new BadRequestException(`초대받은 유저만 수락할 수 있습니다.`); - } - if (type !== NoticeType.INVITE_HOST && type !== NoticeType.INVITE_GUEST) { - throw new BadRequestException(`잘못된 Notice 타입입니다.`); - } + const noticeNo: number = await this.checkChatNotice( + userNo, + senderNo, + chatRoomNo, + type, + ); + const userType = type === NoticeType.INVITE_HOST ? UserType.HOST : UserType.GUEST; @@ -356,15 +358,66 @@ export class ChatsControllerService { isNeededUser: false, }); - await this.joinChatRoom({ userNo, chatRoomNo, userType }); + await this.joinChatRoom(manager, { userNo, chatRoomNo, userType }); + await this.deleteNotice(manager, noticeNo); + } + + private async checkChatNotice( + userNo: number, + senderNo: number, + chatRoomNo: number, + type: number, + ): Promise { + const notice: Notices = await this.noticeChatsRepository.getNotice({ + userNo, + targetUserNo: senderNo, + type, + chatRoomNo, + }); + if (!notice) { + throw new NotFoundException(`초대 정보가 존재하지 않습니다.`); + } + return notice.no; } - private async joinChatRoom(chatUserInfo: ChatUser): Promise { + private async joinChatRoom( + manager: EntityManager, + chatUserInfo: ChatUser, + ): Promise { const user = [chatUserInfo]; - const affectedRow = await this.chatUsersRepository.createChatUsers(user); + const affectedRow: number = await manager + .getCustomRepository(ChatUsersRepository) + .createChatUsers(user); if (!affectedRow) { throw new InternalServerErrorException(`채팅방 유저 추가 오류입니다.`); } } + + private async deleteNotice(manager: EntityManager, noticeNo: number) { + const deleteResult: number = await manager + .getCustomRepository(NoticesRepository) + .deleteNotice(noticeNo); + if (!deleteResult) { + throw new InternalServerErrorException(`알림 삭제에 실패했습니다.`); + } + } + + async rejecteInvitation( + manager: EntityManager, + userNo: number, + chatRoomNo: number, + { senderNo, type }: AcceptInvitationDto, + ): Promise { + const noticeNo: number = await this.checkChatNotice( + userNo, + senderNo, + chatRoomNo, + type, + ); + if (!noticeNo) { + throw new NotFoundException(`초대 정보가 존재하지 않습니다.`); + } + await this.deleteNotice(manager, noticeNo); + } } diff --git a/main-project/src/chats/chats.controller.ts b/main-project/src/chats/chats.controller.ts index 56e4ae78..d971405b 100644 --- a/main-project/src/chats/chats.controller.ts +++ b/main-project/src/chats/chats.controller.ts @@ -19,7 +19,7 @@ import { APIResponse } from 'src/common/interface/interface'; import { TransactionInterceptor } from 'src/common/interceptor/transaction-interceptor'; import { TransactionDecorator } from 'src/common/decorator/transaction-manager.decorator'; import { EntityManager } from 'typeorm'; -import { UseGuards } from '@nestjs/common/decorators'; +import { Delete, UseGuards } from '@nestjs/common/decorators'; import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guard'; import { GetUser } from 'src/common/decorator/get-user.decorator'; import { ApiGetPreviousChatLog } from './swagger/get-previous-chat-log.decorator'; @@ -28,6 +28,8 @@ import { ApiInviteUser } from './swagger/invite-user.decorator'; import { ApiAcceptInvitation } from './swagger/accept-invitation.decorator'; import { APiUploadFile } from './swagger/upload-file.decorator'; import { ApiCreateChatRoom } from './swagger/create-chat-room.decorator'; +import { ApiRejecteInvitation } from './swagger/rejected-invitation.decorator'; + @Controller('chats') @ApiTags('채팅 APi') @@ -111,13 +113,16 @@ export class ChatsController { @Patch('/:chatRoomNo/invitation') @ApiAcceptInvitation() @UseGuards(JwtAuthGuard) + @UseInterceptors(TransactionInterceptor) async acceptInvitation( @GetUser() userNo: number, + @TransactionDecorator() manager: EntityManager, @Param('chatRoomNo', ParseIntPipe) chatRoomNo: number, @Body() invitation: AcceptInvitationDto, ): Promise { await this.chatControllerService.acceptInvitation( userNo, + manager, chatRoomNo, invitation, ); @@ -127,6 +132,25 @@ export class ChatsController { }; } + @Delete('/:chatRoomNo/invitation') + @ApiRejecteInvitation() + @UseGuards(JwtAuthGuard) + @UseInterceptors(TransactionInterceptor) + async rejecteInvitation( + @GetUser() userNo: number, + @TransactionDecorator() manager: EntityManager, + @Param('chatRoomNo', ParseIntPipe) chatRoomNo: number, + @Body() invitation: AcceptInvitationDto, + ): Promise { + await this.chatControllerService.rejecteInvitation( + manager, + userNo, + chatRoomNo, + invitation, + ); + return { msg: '채팅방 초대 거절 성공' }; + } + @Post('/:chatRoomNo/files') @APiUploadFile() @UseInterceptors(FilesInterceptor('files', 10)) // 10은 최대파일개수 diff --git a/main-project/src/chats/dto/accept-invitation.dto.ts b/main-project/src/chats/dto/accept-invitation.dto.ts index dad0bbb8..80dfa1b1 100644 --- a/main-project/src/chats/dto/accept-invitation.dto.ts +++ b/main-project/src/chats/dto/accept-invitation.dto.ts @@ -5,10 +5,6 @@ export class AcceptInvitationDto { @IsNotEmpty() senderNo: number; - @IsNumber() - @IsNotEmpty() - receiverNo: number; - @IsNumber() @IsNotEmpty() type: number; diff --git a/main-project/src/chats/swagger/accept-invitation.decorator.ts b/main-project/src/chats/swagger/accept-invitation.decorator.ts index 0e080740..1e24fc76 100644 --- a/main-project/src/chats/swagger/accept-invitation.decorator.ts +++ b/main-project/src/chats/swagger/accept-invitation.decorator.ts @@ -7,14 +7,13 @@ import { ApiOkResponse, ApiOperation, } from '@nestjs/swagger'; -import { number } from 'joi'; import { SwaggerApiResponse } from 'src/common/swagger/api-response.swagger'; export function ApiAcceptInvitation() { return applyDecorators( ApiOperation({ summary: '채팅방 초대 수락 ', - description: '유저 번호, 타입, 채팅방 번호를 통해 초대 수락', + description: '유저 번호, notice타입, 채팅방 번호를 통해 초대 수락', }), ApiBearerAuth(), ApiBody({ @@ -28,13 +27,6 @@ export function ApiAcceptInvitation() { nullable: false, description: '초대한 유저의 userNo', }, - receiverNo: { - type: 'number', - minLength: 1, - example: 9, - nullable: false, - description: '초대받은 유저의 userNo', - }, type: { type: 'number', maxLength: 1, @@ -49,6 +41,10 @@ export function ApiAcceptInvitation() { ), ApiNotFoundResponse( SwaggerApiResponse.exception([ + { + name: 'noticeNotFound', + example: { msg: '초대 정보가 존재하지 않습니다.' }, + }, { name: 'chatRoomNotFound', example: { msg: '존재하지 않는 채팅방입니다.' }, diff --git a/main-project/src/chats/swagger/rejected-invitation.decorator.ts b/main-project/src/chats/swagger/rejected-invitation.decorator.ts new file mode 100644 index 00000000..ddebb703 --- /dev/null +++ b/main-project/src/chats/swagger/rejected-invitation.decorator.ts @@ -0,0 +1,50 @@ +import { applyDecorators } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiBody, + ApiNotFoundResponse, + ApiOkResponse, + ApiOperation, +} from '@nestjs/swagger'; +import { SwaggerApiResponse } from 'src/common/swagger/api-response.swagger'; + +export function ApiRejecteInvitation() { + return applyDecorators( + ApiOperation({ + summary: '채팅방 초대 거절', + description: '유저 번호, notice타입, 채팅방 번호를 통해 초대 거절', + }), + ApiBearerAuth(), + ApiBody({ + schema: { + type: 'object', + properties: { + senderNo: { + type: 'number', + minLength: 1, + example: 9, + nullable: false, + description: '초대한 유저의 userNo', + }, + type: { + type: 'number', + maxLength: 1, + nullable: false, + description: '알람 typeNo', + }, + }, + }, + }), + ApiOkResponse( + SwaggerApiResponse.success('채팅방 초대 거절', '채팅방 초대 거절 성공'), + ), + ApiNotFoundResponse( + SwaggerApiResponse.exception([ + { + name: 'noticeNotFound', + example: { msg: '초대 정보가 존재하지 않습니다.' }, + }, + ]), + ), + ); +} diff --git a/main-project/src/notices/repository/notices-chats.repository.ts b/main-project/src/notices/repository/notices-chats.repository.ts index a56b737c..284eac6c 100644 --- a/main-project/src/notices/repository/notices-chats.repository.ts +++ b/main-project/src/notices/repository/notices-chats.repository.ts @@ -6,6 +6,7 @@ import { } from 'src/chats/interface/chat.interface'; import { EntityRepository, InsertResult, Repository } from 'typeorm'; import { NoticeChats } from '../entity/notice-chat.entity'; +import { Notices } from '../entity/notices.entity'; import { NoticeChatsInfo } from '../interface/notice.interface'; ``; @EntityRepository(NoticeChats) @@ -28,22 +29,20 @@ export class NoticeChatsRepository extends Repository { } } - async getNoticeChat( - ChatRoomInvitation: ChatRoomInvitation, - ): Promise { + async getNotice(ChatRoomInvitation: ChatRoomInvitation): Promise { try { - const noticeChat: NoticeChats = await this.createQueryBuilder( - 'notice_chats', - ) + const notice: Notices = await this.createQueryBuilder('notice_chats') .leftJoin('notice_chats.noticeNo', 'notices') - .select(['notices.* ']) + .select(['notices.no as no ']) .where( - 'notice_chats.chatRoomNo = :chatRoomNo AND notices.userNo = :userNo AND notices.type = :type AND notices.targetUserNo = :targetUserNo', + `notice_chats.chatRoomNo = :chatRoomNo + AND notices.userNo = :userNo AND notices.type = :type + AND notices.targetUserNo = :targetUserNo`, ChatRoomInvitation, ) .getRawOne(); - return noticeChat; + return notice; } catch (error) { throw new InternalServerErrorException( `${error} 채팅 알람 확인 에러(checkNoticeChat): 알 수 없는 서버 오류입니다.`,