diff --git a/main-project/src/chats/chats-gateway.service.ts b/main-project/src/chats/chats-gateway.service.ts index 7c691740..68bf5222 100644 --- a/main-project/src/chats/chats-gateway.service.ts +++ b/main-project/src/chats/chats-gateway.service.ts @@ -9,11 +9,15 @@ import { Socket } from 'socket.io'; import { Boards } from 'src/boards/entity/board.entity'; import { BoardsRepository } from 'src/boards/repository/board.repository'; import { UserType } from 'src/common/configs/user-type.config'; +import { Meetings } from 'src/meetings/entity/meeting.entity'; +import { MeetingRepository } from 'src/meetings/repository/meeting.repository'; import { EntityManager } from 'typeorm'; import { CreateChatDto } from './dto/create-chat.dto'; import { MessagePayloadDto } from './dto/message-payload.dto'; +import { SendMeetingDto } from './dto/send-meeting.dto'; import { ChatList } from './entity/chat-list.entity'; import { + ChatMessage, ChatRoom, ChatRoomBeforeCreate, ChatRoomOfBoard, @@ -32,7 +36,7 @@ export class ChatsGatewayService { private readonly chatListRepository: ChatListRepository, private readonly chatUsersRepository: ChatUsersRepository, private readonly chatLogRepository: ChatLogRepository, - private readonly boardRepository: BoardsRepository, + private readonly meetingRepository: MeetingRepository, ) {} async initSocket(socket, userNo: number): Promise { @@ -71,8 +75,7 @@ export class ChatsGatewayService { const { chatRoomNo, message }: MessagePayloadDto = messagePayload; await this.checkChatRoom(chatRoomNo, userNo); - - await this.saveMessage(messagePayload); + await this.saveMessage({ chatRoomNo, userNo, message }); socket.broadcast.to(`${chatRoomNo}`).emit('message', { message, @@ -91,10 +94,10 @@ export class ChatsGatewayService { await this.checkChatRoom(chatRoomNo, userNo); - const chatLogNo: number = await this.saveMessageByEntityManager( - manager, - messagePayload, - ); + const chatLogNo: number = await this.saveMessageByEntityManager(manager, { + chatRoomNo, + userNo, + }); await this.saveFileUrls(manager, messagePayload, chatLogNo); @@ -107,7 +110,7 @@ export class ChatsGatewayService { private async saveMessageByEntityManager( manager: EntityManager, - messagePayload: MessagePayloadDto, + messagePayload: ChatMessage, ): Promise { const insertId: number = await manager .getCustomRepository(ChatLogRepository) @@ -139,7 +142,7 @@ export class ChatsGatewayService { } } - private async saveMessage(messagePayload: MessagePayloadDto): Promise { + private async saveMessage(messagePayload: ChatMessage): Promise { const insertId: number = await this.chatLogRepository.saveMessage( messagePayload, ); @@ -167,6 +170,7 @@ export class ChatsGatewayService { throw new BadRequestException('채팅방에 유저의 정보가 없습니다.'); } } + async leaveChatRoom( userNo: number, socket: Socket, @@ -180,4 +184,30 @@ export class ChatsGatewayService { .to(`${chatRoomNo}`) .emit('message', { message: `${userNo}가 나갔습니다.` }); } + + async sendMeetingMessage( + socket: Socket, + userNo: number, + messagePayload: SendMeetingDto, + ) { + const { location, time, chatRoomNo, meetingNo } = messagePayload; + + await this.checkMeetingExistence(meetingNo, chatRoomNo); + await this.saveMessage({ chatRoomNo, userNo, meetingNo }); + + socket.broadcast + .to(`${chatRoomNo}`) + .emit('message', { meeting: { location, time } }); + } + + private async checkMeetingExistence(meetingNo, chatRoomNo): Promise { + const meeting: Meetings = + await this.meetingRepository.getMeetingByChatRoomAndMeetingNumber( + meetingNo, + chatRoomNo, + ); + if (!meeting) { + throw new NotFoundException(`해당하는 약속 정보를 찾을 수 없습니다.`); + } + } } diff --git a/main-project/src/chats/chats.controller.ts b/main-project/src/chats/chats.controller.ts index 99553f5f..d0ef4561 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 { Delete, UseGuards } from '@nestjs/common/decorators'; +import { 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'; @@ -37,23 +37,18 @@ export class ChatsController { private readonly chatControllerService: ChatsControllerService, private readonly awsService: AwsService, ) {} - @Post('/:boardNo/:guestTeamNo') - @ApiCreateChatRoom() + + @Get('/:chatRoomNo/chat-log') + @ApiGetCurrentChatLog() @UseGuards(JwtAuthGuard) - @UseInterceptors(TransactionInterceptor) - async createChatRoom( + async getCurrentChatLog( @GetUser() userNo: number, - @TransactionDecorator() manager: EntityManager, - @Param('boardNo', ParseIntPipe) boardNo: number, - @Param('guestTeamNo', ParseIntPipe) guestTeamNo: number, + @Param('chatRoomNo', ParseIntPipe) chatRoomNo: number, ): Promise { - await this.chatControllerService.createChatRoom( - userNo, - manager, - boardNo, - guestTeamNo, - ); - return { msg: '여름 신청 수락' }; + const currentChatLog: ChatLog[] = + await this.chatControllerService.getCurrentChatLog(userNo, chatRoomNo); + + return { response: { currentChatLog } }; } @Get('/:chatRoomNo/chat-log/:currentChatLogNo') @@ -74,39 +69,23 @@ export class ChatsController { return { response: { previousChatLog } }; } - @Get('/:chatRoomNo/chat-log') - @ApiGetCurrentChatLog() - @UseGuards(JwtAuthGuard) - async getCurrentChatLog( - @GetUser() userNo: number, - @Param('chatRoomNo', ParseIntPipe) chatRoomNo: number, - ): Promise { - const currentChatLog: ChatLog[] = - await this.chatControllerService.getCurrentChatLog(userNo, chatRoomNo); - - return { response: { currentChatLog } }; - } - - @Post('/:chatRoomNo/invitation/:userNo') + @Post('/:chatRoomNo/invitation') + @ApiRejecteInvitation() @UseGuards(JwtAuthGuard) @UseInterceptors(TransactionInterceptor) - @ApiInviteUser() - async inviteUser( - @GetUser() targetUserNo: number, + async rejecteInvitation( + @GetUser() userNo: number, @TransactionDecorator() manager: EntityManager, @Param('chatRoomNo', ParseIntPipe) chatRoomNo: number, - @Param('userNo', ParseIntPipe) userNo: number, + @Body() invitation: AcceptInvitationDto, ): Promise { - await this.chatControllerService.inviteUser( - userNo, + await this.chatControllerService.rejecteInvitation( manager, - targetUserNo, + userNo, chatRoomNo, + invitation, ); - - return { - msg: '채팅방 초대 성공', - }; + return { msg: '채팅방 초대 거절 성공' }; } @Patch('/:chatRoomNo/invitation') @@ -131,23 +110,26 @@ export class ChatsController { }; } - @Post('/:chatRoomNo/invitation') - @ApiRejecteInvitation() + @Post('/:chatRoomNo/invitation/:userNo') @UseGuards(JwtAuthGuard) @UseInterceptors(TransactionInterceptor) - async rejecteInvitation( - @GetUser() userNo: number, + @ApiInviteUser() + async inviteUser( + @GetUser() targetUserNo: number, @TransactionDecorator() manager: EntityManager, @Param('chatRoomNo', ParseIntPipe) chatRoomNo: number, - @Body() invitation: AcceptInvitationDto, + @Param('userNo', ParseIntPipe) userNo: number, ): Promise { - await this.chatControllerService.rejecteInvitation( - manager, + await this.chatControllerService.inviteUser( userNo, + manager, + targetUserNo, chatRoomNo, - invitation, ); - return { msg: '채팅방 초대 거절 성공' }; + + return { + msg: '채팅방 초대 성공', + }; } @Post('/:chatRoomNo/files') @@ -167,4 +149,23 @@ export class ChatsController { response: { uploadedFileUrlList }, }; } + + @Post('/:boardNo/:guestTeamNo') + @ApiCreateChatRoom() + @UseGuards(JwtAuthGuard) + @UseInterceptors(TransactionInterceptor) + async createChatRoom( + @GetUser() userNo: number, + @TransactionDecorator() manager: EntityManager, + @Param('boardNo', ParseIntPipe) boardNo: number, + @Param('guestTeamNo', ParseIntPipe) guestTeamNo: number, + ): Promise { + await this.chatControllerService.createChatRoom( + userNo, + manager, + boardNo, + guestTeamNo, + ); + return { msg: '여름 신청 수락' }; + } } diff --git a/main-project/src/chats/chats.gateway.ts b/main-project/src/chats/chats.gateway.ts index 10929f49..53109ad0 100644 --- a/main-project/src/chats/chats.gateway.ts +++ b/main-project/src/chats/chats.gateway.ts @@ -1,4 +1,4 @@ -import { Logger, UseInterceptors } from '@nestjs/common'; +import { Logger, UseInterceptors, ValidationPipe } from '@nestjs/common'; import { ConnectedSocket, MessageBody, @@ -6,7 +6,7 @@ import { WebSocketGateway, WebSocketServer, } from '@nestjs/websockets'; -import { UseGuards } from '@nestjs/common/decorators'; +import { UseFilters, UseGuards, UsePipes } from '@nestjs/common/decorators'; import { AsyncApiSub } from 'nestjs-asyncapi'; import { Namespace, Socket } from 'socket.io'; import { WebSocketAuthGuard } from 'src/common/guards/ws-jwt-auth.guard'; @@ -18,11 +18,16 @@ import { WebSocketGetUser } from 'src/common/decorator/ws-get-user.decorator'; import { WebSocketTransactionManager } from 'src/common/decorator/ws-transaction-manager.decorator'; import { WebSocketTransactionInterceptor } from 'src/common/interceptor/ws-transaction-interceptor'; import { EntityManager } from 'typeorm'; +import { SendMeetingDto } from './dto/send-meeting.dto'; +import { WebSocketExceptionFilter } from 'src/common/exceptions/ws-exception-filter'; +import { number } from 'joi'; @WebSocketGateway(4000, { namespace: 'chat', cors: true, }) +@UsePipes(new ValidationPipe()) +@UseFilters(new WebSocketExceptionFilter()) export class ChatsGateway { constructor(private readonly chatGatewayService: ChatsGatewayService) {} @@ -42,10 +47,6 @@ export class ChatsGateway { this.logger.log(`"Socket:${id}"이 "Room:${room}"에서 나갔습니다.`); }); - this.nsp.adapter.on('delete-room', (roomName) => { - this.logger.log(`"Room:${roomName}"이 삭제되었습니다.`); - }); - this.logger.log('웹소켓 서버 초기화'); } @@ -59,8 +60,14 @@ export class ChatsGateway { @SubscribeMessage('init-socket') @AsyncApiSub({ - description: `소켓 초기화 socket auth 헤더 token으로 전달 - response: [{ roomName: string, chatRoomNo: number, users:[{userNo:number, nickname:string, profileImage:string}] }] 반환`, + description: ` + *소켓 초기화* + + 클라이언트 + 소켓 초기화 socket auth 헤더 token으로 토큰 전달 + + 서버 + [{ roomName: string, chatRoomNo: number, users:[{userNo:number, nickname:string, profileImage:string}] }] 반환`, channel: 'init-socket', message: { payload: InitSocketDto, @@ -76,35 +83,43 @@ export class ChatsGateway { return { response: { chatRooms } }; } - @SubscribeMessage('message') + @SubscribeMessage('send-message') @AsyncApiSub({ description: ` - 메세지 전송 채팅일때 response: + *주의 서버로 보내는 이벤트는 send-message 서버에서 클라이언트로 받는 이벤트는 message* + + 서버 + message이벤트로 emit하는 내용 + 채팅일때: { "userNo": 1, "chatRoomNo": 3, "message": 3, } - 이미지일때 + + 이미지일때: { "userNo": 1, "chatRoomNo": 3, "uploadedFileUrls": [ "http", "http" ] - }반환`, - channel: 'message', + }`, + channel: 'send-message', message: { payload: MessagePayloadDto, }, }) - @UseGuards(WebSocketAuthGuard) + // @UseGuards(WebSocketAuthGuard) @UseInterceptors(WebSocketTransactionInterceptor) async handleSendMessage( - @WebSocketGetUser() userNo: number, + // @WebSocketGetUser() userNo: number, @WebSocketTransactionManager() manager: EntityManager, @ConnectedSocket() socket: Socket, @MessageBody() messagePayload: MessagePayloadDto, ): Promise { + const userNo = 29; + console.log(29); + messagePayload.hasOwnProperty('message') ? await this.chatGatewayService.sendChat(socket, messagePayload, userNo) : await this.chatGatewayService.sendFile( @@ -117,6 +132,21 @@ export class ChatsGateway { } @SubscribeMessage('leave-room') + @AsyncApiSub({ + description: ` + *채팅방 나가기* + + 클라이언트 + socket auth 헤더 token으로 토큰 전달 + message body에 chatRoomNo 전달 + + 서버 + success: true, msg: 채팅방 나가기 완료`, + channel: 'leave-room', + message: { + payload: MessagePayloadDto, + }, + }) @UseGuards(WebSocketAuthGuard) async handleLeaveRoom( @WebSocketGetUser() userNo: number, @@ -127,4 +157,37 @@ export class ChatsGateway { return { msg: '채팅방 나가기 완료' }; } + + @SubscribeMessage('send-meeting') + @AsyncApiSub({ + description: ` + *약속 전송* + + 클라이언트 + socket auth 헤더 token으로 토큰 전달 + body로 약속정보 전달 (SendMeetingDto 참고) + + 서버 + response: success: true반환 + + 이벤트 message를 통해 + meeting: { location: string, time:date } 전달`, + channel: 'send-meeting', + message: { + payload: SendMeetingDto, + }, + }) + @UseGuards(WebSocketAuthGuard) + async handleSendMeeting( + @WebSocketGetUser() userNo: number, + @ConnectedSocket() socket: Socket, + @MessageBody() messagePayload: SendMeetingDto, + ) { + await this.chatGatewayService.sendMeetingMessage( + socket, + userNo, + messagePayload, + ); + return { success: true }; + } } diff --git a/main-project/src/chats/dto/get-chat-log.dto.ts b/main-project/src/chats/dto/get-chat-log.dto.ts index 5d40d774..0e3ec141 100644 --- a/main-project/src/chats/dto/get-chat-log.dto.ts +++ b/main-project/src/chats/dto/get-chat-log.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsNumber, IsOptional } from 'class-validator'; +import { IsNumber, IsOptional } from 'class-validator'; export class GetChatLogDto { @IsNumber() diff --git a/main-project/src/chats/dto/message-payload.dto.ts b/main-project/src/chats/dto/message-payload.dto.ts index 13fea469..18ed20dc 100644 --- a/main-project/src/chats/dto/message-payload.dto.ts +++ b/main-project/src/chats/dto/message-payload.dto.ts @@ -1,5 +1,11 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsNumber, IsString } from 'class-validator'; +import { + IsArray, + IsNotEmpty, + IsNumber, + IsOptional, + IsString, +} from 'class-validator'; export class MessagePayloadDto { @IsNotEmpty() @@ -9,17 +15,18 @@ export class MessagePayloadDto { }) chatRoomNo: number; - @IsNotEmpty() @IsString() + @IsOptional() @ApiProperty({ - example: 3, + example: '안녕하세요', }) - message?: string; + message: string; - @IsNotEmpty() - @IsString() + @IsArray() + @IsString({ each: true }) + @IsOptional() @ApiProperty({ example: ['http', 'http'], }) - uploadedFileUrls?: string[]; + uploadedFileUrls: string[]; } diff --git a/main-project/src/chats/dto/send-meeting.dto.ts b/main-project/src/chats/dto/send-meeting.dto.ts new file mode 100644 index 00000000..4457328a --- /dev/null +++ b/main-project/src/chats/dto/send-meeting.dto.ts @@ -0,0 +1,42 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsDate, IsInt, IsNotEmpty, IsString } from 'class-validator'; + +export class SendMeetingDto { + @ApiProperty({ + example: '경기도', + description: '약속 장소', + required: true, + }) + @IsString() + @IsNotEmpty() + location: string; + + @ApiProperty({ + example: '2022-06-27 15:22:31', + description: '약속 시간', + required: true, + }) + @IsDate() + @Type(() => Date) + @IsNotEmpty() + time: Date; + + @ApiProperty({ + example: 1, + description: '채팅방 번호', + required: true, + }) + @IsInt() + @IsNotEmpty() + chatRoomNo: number; + + @ApiProperty({ + example: 1, + description: '약속 번호', + required: true, + }) + @IsInt() + @IsNotEmpty() + meetingNo: number; +} diff --git a/main-project/src/chats/entity/chat-log.entity.ts b/main-project/src/chats/entity/chat-log.entity.ts index d92b8ff3..120a7a43 100644 --- a/main-project/src/chats/entity/chat-log.entity.ts +++ b/main-project/src/chats/entity/chat-log.entity.ts @@ -1,3 +1,5 @@ +import { type } from 'os'; +import { Meetings } from 'src/meetings/entity/meeting.entity'; import { Users } from 'src/users/entity/user.entity'; import { BaseEntity, @@ -7,6 +9,7 @@ import { JoinColumn, ManyToOne, OneToMany, + OneToOne, PrimaryGeneratedColumn, } from 'typeorm'; import { ChatFileUrls } from './chat-file-urls.entity'; @@ -27,6 +30,12 @@ export class ChatLog extends BaseEntity { @JoinColumn({ name: 'user_no' }) userNo: number; + @OneToOne(() => Meetings, (meetings) => meetings.chatLogNo, { + nullable: true, + }) + @JoinColumn({ name: 'meeting_no' }) + meetingNo: number; + @Column({ nullable: true }) message: string; diff --git a/main-project/src/chats/interface/chat.interface.ts b/main-project/src/chats/interface/chat.interface.ts index e8577b1f..9a876e42 100644 --- a/main-project/src/chats/interface/chat.interface.ts +++ b/main-project/src/chats/interface/chat.interface.ts @@ -45,3 +45,10 @@ export interface FileUrl { export interface BoardGuestTeam { teamNo: number; } + +export interface ChatMessage { + chatRoomNo: number; + userNo: number; + message?: string; + meetingNo?: number; +} diff --git a/main-project/src/chats/repository/chat-log.repository.ts b/main-project/src/chats/repository/chat-log.repository.ts index 222f8b2f..62800791 100644 --- a/main-project/src/chats/repository/chat-log.repository.ts +++ b/main-project/src/chats/repository/chat-log.repository.ts @@ -2,10 +2,11 @@ import { InternalServerErrorException } from '@nestjs/common'; import { EntityRepository, InsertResult, Repository } from 'typeorm'; import { MessagePayloadDto } from '../dto/message-payload.dto'; import { ChatLog } from '../entity/chat-log.entity'; +import { ChatMessage } from '../interface/chat.interface'; @EntityRepository(ChatLog) export class ChatLogRepository extends Repository { - async saveMessage(messagePayload: MessagePayloadDto): Promise { + async saveMessage(messagePayload: ChatMessage): Promise { try { const { raw }: InsertResult = await this.createQueryBuilder() .insert() @@ -29,14 +30,29 @@ export class ChatLogRepository extends Repository { const previousChatLog = await this.createQueryBuilder('chat_log') .leftJoin('chat_log.userNo', 'user') .leftJoin('chat_log.chatFileUrl', 'chatFileUrl') + .leftJoin('chat_log.meetingNo', 'meeting') .select([ 'chat_log.no AS chatLogNo', 'user.no AS userNo', 'chat_log.sended_time AS sendedTime', - `IFNULL(chat_log.message ,chatFileUrl.file_url) AS message`, ]) + .addSelect( + `CASE + WHEN chat_log.message IS NOT NULL THEN chat_log.message + WHEN chat_log.meetingNo IS NOT NULL THEN CONCAT(meeting.location, '/', meeting.time) + ELSE GROUP_CONCAT(chatFileUrl.fileUrl SEPARATOR ', ') END`, + `field`, + ) + .addSelect( + `CASE + WHEN chat_log.message IS NOT NULL THEN 'Message' + WHEN chat_log.meetingNo IS NOT NULL THEN 'Meeting' + ELSE 'ImageUrl' END`, + `type`, + ) .where('chat_log.chat_room_no = :chatRoomNo', { chatRoomNo }) .andWhere(`chat_log.no < :currentChatLogNo`, { currentChatLogNo }) + .groupBy('chat_log.no') .orderBy('chat_log.no', 'DESC') .limit(30) .getRawMany(); @@ -56,13 +72,28 @@ export class ChatLogRepository extends Repository { ) .leftJoin('chat_log.userNo', 'user') .leftJoin('chat_log.chatFileUrl', 'chatFileUrl') + .leftJoin('chat_log.meetingNo', 'meeting') .select([ 'chat_log.no AS chatLogNo', 'user.no AS userNo', - `IFNULL(chat_log.message ,chatFileUrl.file_url) AS message`, 'chat_log.sended_time AS sendedTime', ]) + .addSelect( + `CASE + WHEN chat_log.message IS NOT NULL THEN chat_log.message + WHEN chat_log.meetingNo IS NOT NULL THEN CONCAT(meeting.location, '/', meeting.time) + ELSE GROUP_CONCAT(chatFileUrl.fileUrl SEPARATOR ', ') END`, + `field`, + ) + .addSelect( + `CASE + WHEN chat_log.message IS NOT NULL THEN 'Message' + WHEN chat_log.meetingNo IS NOT NULL THEN 'Meeting' + ELSE 'ImageUrl' END`, + `type`, + ) .where('chat_log.chat_room_no = :chatRoomNo', { chatRoomNo }) + .groupBy('chat_log.no') .orderBy('chat_log.no', 'DESC') .limit(30) .getRawMany(); diff --git a/main-project/src/chats/swagger/get-current-chat-log.decorator.ts b/main-project/src/chats/swagger/get-current-chat-log.decorator.ts index fb7004ff..2c614b72 100644 --- a/main-project/src/chats/swagger/get-current-chat-log.decorator.ts +++ b/main-project/src/chats/swagger/get-current-chat-log.decorator.ts @@ -19,130 +19,54 @@ export function ApiGetCurrentChatLog() { SwaggerApiResponse.success('현재 채팅 내역 반환', undefined, { currentChatLog: [ { - chatLogNo: 37, - userNo: 10, - message: 'adad', - sendedTime: '2023-02-06T23:02:11.953Z', + chatLogNo: 72, + userNo: 29, + sendedTime: '2023-03-18T14:44:50.351Z', + field: + 'https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221129_152252544.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221129_102053704.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221201_154004656.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221129_104117642.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221128_203528865.jpg', + type: 'ImageUrl', }, { - chatLogNo: 36, - userNo: 9, - message: 'adad', - sendedTime: '2023-02-06T23:02:09.926Z', + chatLogNo: 71, + userNo: 30, + sendedTime: '2023-03-15T10:42:19.534Z', + field: '노원역 어딘가/2023-03-15 18:32:22', + type: 'Meeting', }, { - chatLogNo: 35, - userNo: 9, - message: '123123', - sendedTime: '2023-02-06T23:02:00.969Z', + chatLogNo: 68, + userNo: 29, + sendedTime: '2023-03-15T10:35:42.385Z', + field: '테테테테테테', + type: 'Message', }, { - chatLogNo: 34, - userNo: 10, - message: 'asd', - sendedTime: '2023-02-06T22:59:18.973Z', + chatLogNo: 67, + userNo: 29, + sendedTime: '2023-03-15T10:35:26.741Z', + field: '테스트트트', + type: 'Message', }, { - chatLogNo: 33, - userNo: 9, - message: 'asd', - sendedTime: '2023-02-06T22:59:17.696Z', + chatLogNo: 66, + userNo: 29, + sendedTime: '2023-03-15T10:34:18.314Z', + field: 'ㅁㅇㅁㅇ', + type: 'Message', }, { - chatLogNo: 29, - userNo: 10, - message: '안녕하세요', - sendedTime: '2023-02-02T22:22:49.545Z', + chatLogNo: 65, + userNo: 29, + sendedTime: '2023-03-15T10:04:03.419Z', + field: '이것은 테스트이다', + type: 'Message', }, { - chatLogNo: 28, - userNo: 9, - message: '하이 ㅋㅋ', - sendedTime: '2023-02-02T22:22:44.489Z', - }, - { - chatLogNo: 27, - userNo: 10, - message: '아아아아아아아', - sendedTime: '2023-02-02T22:20:22.787Z', - }, - { - chatLogNo: 26, - userNo: 10, - message: '테스트 테스트 ', - sendedTime: '2023-02-02T22:20:21.146Z', - }, - { - chatLogNo: 25, - userNo: 9, - message: '님은 뭐함? ㅋㅋ', - sendedTime: '2023-02-02T22:20:15.510Z', - }, - { - chatLogNo: 24, - userNo: 9, - message: '밥먹음 ', - sendedTime: '2023-02-02T22:20:13.068Z', - }, - { - chatLogNo: 23, - userNo: 10, - message: '님 뭐함?', - sendedTime: '2023-02-02T22:20:09.128Z', - }, - { - chatLogNo: 22, - userNo: 10, - message: '하이 ㅋㅋㅋ', - sendedTime: '2023-02-02T22:20:04.534Z', - }, - { - chatLogNo: 21, - userNo: 9, - message: '하이 ㅋㅋ', - sendedTime: '2023-02-02T22:20:01.517Z', - }, - { - chatLogNo: 20, - userNo: 9, - message: 'ㅁㅇ', - sendedTime: '2023-02-02T22:19:58.958Z', - }, - { - chatLogNo: 19, - userNo: 10, - message: 'ㅁㅇ', - sendedTime: '2023-02-02T22:19:57.628Z', - }, - { - chatLogNo: 18, - userNo: null, - message: 'ㅁㅇㅁㅇ', - sendedTime: '2023-02-02T22:19:45.623Z', - }, - { - chatLogNo: 17, - userNo: 9, - message: 'ㅁㅇㅁㅇ', - sendedTime: '2023-02-02T22:19:37.296Z', - }, - { - chatLogNo: 16, - userNo: null, - message: 'ㅇㅁㅇ', - sendedTime: '2023-02-02T22:19:35.222Z', - }, - { - chatLogNo: 14, - userNo: 9, - message: '55', - sendedTime: '2023-02-02T22:19:25.359Z', - }, - { - chatLogNo: 13, - userNo: 9, - message: 'ad', - sendedTime: '2023-02-01T17:44:39.928Z', + chatLogNo: 57, + userNo: 21, + sendedTime: '2023-03-02T05:53:10.319Z', + field: '헤헤헿', + type: 'Message', }, ], }), diff --git a/main-project/src/chats/swagger/get-previous-chat-log.decorator.ts b/main-project/src/chats/swagger/get-previous-chat-log.decorator.ts index 642d0c67..28b72163 100644 --- a/main-project/src/chats/swagger/get-previous-chat-log.decorator.ts +++ b/main-project/src/chats/swagger/get-previous-chat-log.decorator.ts @@ -20,40 +20,33 @@ export function ApiGetPreviousChatLog() { SwaggerApiResponse.success('이전 채팅 내역 반환', undefined, { previousChatLog: [ { - chatLogNo: 19, - userNo: 10, - sendedTime: '2023-02-02T22:19:57.628Z', - message: 'ㅁㅇ', + chatLogNo: 72, + userNo: 29, + sendedTime: '2023-03-18T14:44:50.351Z', + field: + 'https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221129_152252544.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221129_102053704.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221201_154004656.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221129_104117642.jpg, https://4term-main-project.s3.ap-northeast-2.amazonaws.com/chat/5/1671005210331_KakaoTalk_20221128_203528865.jpg', + type: 'ImageUrl', }, { - chatLogNo: 18, - userNo: null, - sendedTime: '2023-02-02T22:19:45.623Z', - message: 'ㅁㅇㅁㅇ', + chatLogNo: 71, + userNo: 30, + sendedTime: '2023-03-15T10:42:19.534Z', + field: '노원역 어딘가/2023-03-15 18:32:22', + type: 'Meeting', }, { - chatLogNo: 17, - userNo: 9, - sendedTime: '2023-02-02T22:19:37.296Z', - message: 'ㅁㅇㅁㅇ', + chatLogNo: 68, + userNo: 29, + sendedTime: '2023-03-15T10:35:42.385Z', + field: '테테테테테테', + type: 'Message', }, { - chatLogNo: 16, - userNo: null, - sendedTime: '2023-02-02T22:19:35.222Z', - message: 'ㅇㅁㅇ', - }, - { - chatLogNo: 14, - userNo: 9, - sendedTime: '2023-02-02T22:19:25.359Z', - message: '55', - }, - { - chatLogNo: 13, - userNo: 9, - sendedTime: '2023-02-01T17:44:39.928Z', - message: 'ad', + chatLogNo: 67, + userNo: 29, + sendedTime: '2023-03-15T10:35:26.741Z', + field: '테스트트트', + type: 'Message', }, ], }), diff --git a/main-project/src/common/exceptions/ws-exception-filter.ts b/main-project/src/common/exceptions/ws-exception-filter.ts new file mode 100644 index 00000000..73e63a80 --- /dev/null +++ b/main-project/src/common/exceptions/ws-exception-filter.ts @@ -0,0 +1,23 @@ +import { + ArgumentsHost, + Catch, + ExceptionFilter, + HttpStatus, +} from '@nestjs/common'; +import { Socket } from 'socket.io'; + +@Catch() +export class WebSocketExceptionFilter implements ExceptionFilter { + catch(exception, host: ArgumentsHost) { + const ctx = host.switchToWs(); + const client = ctx.getClient(); + + client.emit('error', { + error: + exception instanceof Error + ? exception.message + : 'Internal server error', + message: exception.response.message, + }); + } +} diff --git a/main-project/src/meetings/entity/meeting.entity.ts b/main-project/src/meetings/entity/meeting.entity.ts index e58925bd..d78efa11 100644 --- a/main-project/src/meetings/entity/meeting.entity.ts +++ b/main-project/src/meetings/entity/meeting.entity.ts @@ -1,4 +1,5 @@ import { ChatList } from 'src/chats/entity/chat-list.entity'; +import { ChatLog } from 'src/chats/entity/chat-log.entity'; import { BaseEntity, Column, @@ -44,4 +45,7 @@ export class Meetings extends BaseEntity { }) @JoinColumn({ name: 'chat_room_no' }) chatRoomNo: number; + + @OneToOne(() => ChatLog, (chatLog) => chatLog.meetingNo) + chatLogNo; } diff --git a/main-project/src/meetings/repository/meeting.repository.ts b/main-project/src/meetings/repository/meeting.repository.ts index 1b6839aa..0c55f350 100644 --- a/main-project/src/meetings/repository/meeting.repository.ts +++ b/main-project/src/meetings/repository/meeting.repository.ts @@ -203,4 +203,24 @@ export class MeetingRepository extends Repository { ); } } + + async getMeetingByChatRoomAndMeetingNumber( + meetingNo, + chatRoomNo, + ): Promise { + try { + const meeting: Meetings = await this.createQueryBuilder() + .where('no = :meetingNo AND chat_room_no= :chatRoomNo', { + meetingNo, + chatRoomNo, + }) + .getRawOne(); + + return meeting; + } catch (error) { + throw new InternalServerErrorException( + `${error} 약속 조회(getMeetingByChatRoomAndMeetingNumber): 알 수 없는 서버 에러입니다.`, + ); + } + } } diff --git a/main-project/src/notices/repository/notices-friend.repository.ts b/main-project/src/notices/repository/notices-friend.repository.ts index b506b99c..9995ce31 100644 --- a/main-project/src/notices/repository/notices-friend.repository.ts +++ b/main-project/src/notices/repository/notices-friend.repository.ts @@ -28,8 +28,6 @@ export class NoticeFriendsRepository extends Repository { } async getNotice(request: FriendNotice): Promise { try { - console.log(request); - const notice: FriendNotice = await this.createQueryBuilder( 'notice_friends', )