From 61cf3945cc33eac2db369fe8a452e7208383d953 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 16 Oct 2023 17:22:27 +0900 Subject: [PATCH 01/24] =?UTF-8?q?feat(#39):=20=EC=95=8C=EB=9E=8C=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 ++ src/notification/notification.controller.ts | 4 ++++ src/notification/notification.module.ts | 9 +++++++++ src/notification/notification.service.ts | 4 ++++ 4 files changed, 19 insertions(+) create mode 100644 src/notification/notification.controller.ts create mode 100644 src/notification/notification.module.ts create mode 100644 src/notification/notification.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 4505fd4..73521c2 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -19,6 +19,7 @@ import { EventsModule } from './events/events.module'; import * as mongoose from 'mongoose'; import { UserImageRepository } from './users/repositories/user-image.repository'; import { TokenRepository } from './auth/repositories/token.repository'; +import { NotificationModule } from './notification/notification.module'; @Module({ imports: [ @@ -41,6 +42,7 @@ import { TokenRepository } from './auth/repositories/token.repository'; FriendModule, NoticeModule, EventsModule, + NotificationModule, ], // providers: [ TokenService, diff --git a/src/notification/notification.controller.ts b/src/notification/notification.controller.ts new file mode 100644 index 0000000..b15a214 --- /dev/null +++ b/src/notification/notification.controller.ts @@ -0,0 +1,4 @@ +import { Controller } from '@nestjs/common'; + +@Controller('notification') +export class NotificationController {} diff --git a/src/notification/notification.module.ts b/src/notification/notification.module.ts new file mode 100644 index 0000000..d54d1ee --- /dev/null +++ b/src/notification/notification.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { NotificationController } from './notification.controller'; +import { NotificationService } from './notification.service'; + +@Module({ + controllers: [NotificationController], + providers: [NotificationService] +}) +export class NotificationModule {} diff --git a/src/notification/notification.service.ts b/src/notification/notification.service.ts new file mode 100644 index 0000000..e62ac5a --- /dev/null +++ b/src/notification/notification.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class NotificationService {} From 87b47f611984d068d6f4b415ef19a155443748f4 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 16 Oct 2023 23:14:49 +0900 Subject: [PATCH 02/24] =?UTF-8?q?modify(#39):=20mo,=20co,=20s=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 ++ src/notice/controllers/notice.controller.ts | 4 ++++ src/notice/notice.module.ts | 7 ++++++- .../services/notice.service.ts} | 2 +- src/notification/notification.controller.ts | 4 ---- src/notification/notification.module.ts | 9 --------- 6 files changed, 13 insertions(+), 15 deletions(-) create mode 100644 src/notice/controllers/notice.controller.ts rename src/{notification/notification.service.ts => notice/services/notice.service.ts} (62%) delete mode 100644 src/notification/notification.controller.ts delete mode 100644 src/notification/notification.module.ts diff --git a/src/app.module.ts b/src/app.module.ts index 73521c2..a835aaf 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -20,6 +20,7 @@ import * as mongoose from 'mongoose'; import { UserImageRepository } from './users/repositories/user-image.repository'; import { TokenRepository } from './auth/repositories/token.repository'; import { NotificationModule } from './notification/notification.module'; +import { NoticeeService } from './noticee/noticee.service'; @Module({ imports: [ @@ -51,6 +52,7 @@ import { NotificationModule } from './notification/notification.module'; UserImageRepository, S3Service, EventsGateway, + NoticeeService, ], }) export class AppModule implements NestModule { diff --git a/src/notice/controllers/notice.controller.ts b/src/notice/controllers/notice.controller.ts new file mode 100644 index 0000000..b57cc5c --- /dev/null +++ b/src/notice/controllers/notice.controller.ts @@ -0,0 +1,4 @@ +import { Controller } from '@nestjs/common'; + +@Controller('notice') +export class NoticeController {} diff --git a/src/notice/notice.module.ts b/src/notice/notice.module.ts index 3a6b56d..1260ac0 100644 --- a/src/notice/notice.module.ts +++ b/src/notice/notice.module.ts @@ -1,4 +1,9 @@ import { Module } from '@nestjs/common'; +import { NoticeController } from './controllers/notice.controller'; +import { NoticeService } from './services/notice.service'; -@Module({}) +@Module({ + controllers: [NoticeController], + providers: [NoticeService], +}) export class NoticeModule {} diff --git a/src/notification/notification.service.ts b/src/notice/services/notice.service.ts similarity index 62% rename from src/notification/notification.service.ts rename to src/notice/services/notice.service.ts index e62ac5a..6f0c04e 100644 --- a/src/notification/notification.service.ts +++ b/src/notice/services/notice.service.ts @@ -1,4 +1,4 @@ import { Injectable } from '@nestjs/common'; @Injectable() -export class NotificationService {} +export class NoticeService {} diff --git a/src/notification/notification.controller.ts b/src/notification/notification.controller.ts deleted file mode 100644 index b15a214..0000000 --- a/src/notification/notification.controller.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Controller } from '@nestjs/common'; - -@Controller('notification') -export class NotificationController {} diff --git a/src/notification/notification.module.ts b/src/notification/notification.module.ts deleted file mode 100644 index d54d1ee..0000000 --- a/src/notification/notification.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; -import { NotificationController } from './notification.controller'; -import { NotificationService } from './notification.service'; - -@Module({ - controllers: [NotificationController], - providers: [NotificationService] -}) -export class NotificationModule {} From 3522cc46217e5442e89358271add8e7540e288ad Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Tue, 17 Oct 2023 17:55:45 +0900 Subject: [PATCH 03/24] =?UTF-8?q?modify(#39):=20app.module=20=EC=9D=B4?= =?UTF-8?q?=EC=83=81=ED=95=9C=20=EA=B2=BD=EB=A1=9C=20import=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index a835aaf..4505fd4 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -19,8 +19,6 @@ import { EventsModule } from './events/events.module'; import * as mongoose from 'mongoose'; import { UserImageRepository } from './users/repositories/user-image.repository'; import { TokenRepository } from './auth/repositories/token.repository'; -import { NotificationModule } from './notification/notification.module'; -import { NoticeeService } from './noticee/noticee.service'; @Module({ imports: [ @@ -43,7 +41,6 @@ import { NoticeeService } from './noticee/noticee.service'; FriendModule, NoticeModule, EventsModule, - NotificationModule, ], // providers: [ TokenService, @@ -52,7 +49,6 @@ import { NoticeeService } from './noticee/noticee.service'; UserImageRepository, S3Service, EventsGateway, - NoticeeService, ], }) export class AppModule implements NestModule { From dd22d549239a9f20a4fca65155fa99480a068c53 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Wed, 18 Oct 2023 14:26:00 +0900 Subject: [PATCH 04/24] =?UTF-8?q?feat(#39):=20sse=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EC=97=B0=EA=B2=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8(do?= =?UTF-8?q?ne)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/chat.module.ts | 3 ++- src/chat/controllers/chat.controller.ts | 12 +++++++++- src/chat/services/notification.service.ts | 29 +++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/chat/services/notification.service.ts diff --git a/src/chat/chat.module.ts b/src/chat/chat.module.ts index 9433d6e..dae78ad 100644 --- a/src/chat/chat.module.ts +++ b/src/chat/chat.module.ts @@ -12,6 +12,7 @@ import { import { EventsModule } from 'src/events/events.module'; import { S3Module } from 'src/common/s3/s3.module'; import { ChatRepository } from './repositories/chat.repository'; +import { NotificationService } from './services/notification.service'; @Module({ imports: [ @@ -25,6 +26,6 @@ import { ChatRepository } from './repositories/chat.repository'; S3Module, ], controllers: [ChatController], - providers: [ChatService, ChatRepository], + providers: [ChatService, ChatRepository, NotificationService], }) export class ChatModule {} diff --git a/src/chat/controllers/chat.controller.ts b/src/chat/controllers/chat.controller.ts index 68d7350..4dd43dd 100644 --- a/src/chat/controllers/chat.controller.ts +++ b/src/chat/controllers/chat.controller.ts @@ -5,6 +5,7 @@ import { Get, Param, Post, + Sse, UploadedFile, UseInterceptors, UsePipes, @@ -19,12 +20,21 @@ import { FileInterceptor } from '@nestjs/platform-express'; import { Users } from 'src/common/decorators/user.decorator'; import { User } from 'src/users/entities/user.entity'; import { ParseObjectIdPipe } from '../parse-object-id.pipe'; +import { NotificationService } from '../services/notification.service'; @ApiTags('CHAT') @Controller('chat-room') @UsePipes(ValidationPipe) export class ChatController { - constructor(private chatService: ChatService) {} + constructor( + private chatService: ChatService, + private notificationService: NotificationService, + ) {} + + @Sse('listener') + notificationListener() { + return this.notificationService.notificationListener(); + } @ApiOperation({ summary: '채팅방 전체 조회' }) @Get() diff --git a/src/chat/services/notification.service.ts b/src/chat/services/notification.service.ts new file mode 100644 index 0000000..63df97a --- /dev/null +++ b/src/chat/services/notification.service.ts @@ -0,0 +1,29 @@ +import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { Subject, map } from 'rxjs'; +import { ChatNotification } from '../schemas/chat-notifiation.schemas'; +import mongoose from 'mongoose'; + +@Injectable() +export class NotificationService { + private readonly logger = new Logger(NotificationService.name); + private readonly subject = new Subject(); + + constructor( + @InjectModel(ChatNotification.name) + private readonly chatNotification: mongoose.Model, + ) {} + + notificationListener() { + try { + return this.subject + .asObservable() + .pipe( + map((notification: Notification) => JSON.stringify(notification)), + ); + } catch (error) { + this.logger.error('notificationListener : ' + error.message); + throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} From 65e051341bfe5aac65148f6d898a4a64e882d1b8 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Wed, 18 Oct 2023 16:28:37 +0900 Subject: [PATCH 05/24] =?UTF-8?q?feat(#39):=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EC=95=8C=EB=9E=8C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20SSE=EB=A5=BC=20=ED=86=B5=ED=95=B4=20?= =?UTF-8?q?=EC=8B=A4=EC=8B=9C=EA=B0=84=20=EC=95=8C=EB=9E=8C=20=EB=A1=9C?= =?UTF-8?q?=EC=9A=B0=20=EB=B0=9B=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/controllers/chat.controller.ts | 7 ++-- src/chat/services/chat.service.ts | 39 +++++++++++++++++++++++ src/chat/services/notification.service.ts | 24 +++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/chat/controllers/chat.controller.ts b/src/chat/controllers/chat.controller.ts index 4dd43dd..5705123 100644 --- a/src/chat/controllers/chat.controller.ts +++ b/src/chat/controllers/chat.controller.ts @@ -33,7 +33,7 @@ export class ChatController { @Sse('listener') notificationListener() { - return this.notificationService.notificationListener(); + return this.chatService.notificationListener(); } @ApiOperation({ summary: '채팅방 전체 조회' }) @@ -75,8 +75,9 @@ export class ChatController { } @ApiOperation({ summary: '특정 채팅방 채팅 생성' }) - @Post(':roomId/chat') + @Post(':roomId/chat/:testUser') async createChat( + @Param('testUser') testUser: number, @Users() user: User, @Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId, @Body() body: PostChatDto, @@ -84,7 +85,7 @@ export class ChatController { return this.chatService.createChat( roomId, body.content, - user.id, + testUser, body.receiverId, ); } diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 35b5957..4fb581f 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -1,7 +1,10 @@ import { ChatRepository } from '../repositories/chat.repository'; import { ConflictException, + HttpException, + HttpStatus, Injectable, + Logger, NotFoundException, } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; @@ -9,17 +12,38 @@ import { ChatRoom } from '../schemas/chat-room.schemas'; import * as mongoose from 'mongoose'; import { EventsGateway } from 'src/events/events.gateway'; import { S3Service } from 'src/common/s3/s3.service'; +import { NotificationService } from './notification.service'; +import { ChatNotification } from '../schemas/chat-notifiation.schemas'; +import { Subject, map } from 'rxjs'; @Injectable() export class ChatService { + private readonly logger = new Logger(ChatService.name); + private readonly subject = new Subject(); constructor( private readonly s3Service: S3Service, + private readonly notificationService: NotificationService, private readonly chatRepository: ChatRepository, @InjectModel(ChatRoom.name) private readonly chatRoomModel: mongoose.Model, private readonly eventsGateway: EventsGateway, + @InjectModel(ChatNotification.name) + private readonly chatNotificationModel: mongoose.Model, ) {} + notificationListener() { + try { + return this.subject + .asObservable() + .pipe( + map((notification: Notification) => JSON.stringify(notification)), + ); + } catch (error) { + this.logger.error('notificationListener : ' + error.message); + throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + async getChatRooms(myId: number) { const chatRoom = await this.chatRepository.getChatRooms(myId); @@ -139,7 +163,22 @@ export class ChatService { const socketRoomId = returnedChat.chatroom_id.toString(); this.eventsGateway.server.to(`ch-${socketRoomId}`).emit('message', chat); + const notification = await new this.chatNotificationModel({ + chat_id: returnedChat.id, + // title: createNotificationsDto.title, + // isSeen: false, + }) + .save() + .catch((error) => { + throw new Error(error); + }); + + // send notification + if (notification) this.subject.next(notification); + return chat; + + return { message: 'notification sent successfully' }; } async createChatImage( diff --git a/src/chat/services/notification.service.ts b/src/chat/services/notification.service.ts index 63df97a..82679a9 100644 --- a/src/chat/services/notification.service.ts +++ b/src/chat/services/notification.service.ts @@ -11,7 +11,7 @@ export class NotificationService { constructor( @InjectModel(ChatNotification.name) - private readonly chatNotification: mongoose.Model, + private readonly chatNotificationModel: mongoose.Model, ) {} notificationListener() { @@ -26,4 +26,26 @@ export class NotificationService { throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); } } + + async createNotification(createNotificationsDto: number) { + try { + const notification = await new this.chatNotificationModel({ + // description: createNotificationsDto.description, + // title: createNotificationsDto.title, + isSeen: false, + }) + .save() + .catch((error) => { + throw new Error(error); + }); + + // send notification + if (notification) this.subject.next(notification); + + return { message: 'notification sent successfully' }; + } catch (error) { + this.logger.error('createNotification : ' + error.message); + throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); + } + } } From 5ee614ab925ddf421319f81af1653c2d6685bf03 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Wed, 18 Oct 2023 18:03:16 +0900 Subject: [PATCH 06/24] =?UTF-8?q?feat(#39):=20test=EC=9A=A9=20index.html?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80(=EC=B6=94=ED=9B=84=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/services/chat.service.ts | 2 -- src/index.html | 49 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/index.html diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 4fb581f..b5488d1 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -177,8 +177,6 @@ export class ChatService { if (notification) this.subject.next(notification); return chat; - - return { message: 'notification sent successfully' }; } async createChatImage( diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..7fdb19e --- /dev/null +++ b/src/index.html @@ -0,0 +1,49 @@ + + + + WebSocket Example + + +
+ + + + + + From e497c7076b0c62f5433b2cd6fc00f569ae744b1b Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 19 Oct 2023 19:35:21 +0900 Subject: [PATCH 07/24] =?UTF-8?q?feat(#39):=20socket=20test=EC=9A=A9=20?= =?UTF-8?q?=ED=94=84=EB=A1=A0=ED=8A=B8=20=EC=B6=94=EA=B0=80(=EB=AF=B8?= =?UTF-8?q?=EC=9E=91=EB=8F=99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 +- src/client.js | 29 ++++++++++++++++++++ src/config/typeorm.config.ts | 2 +- src/index.html | 53 ++++++------------------------------ 4 files changed, 39 insertions(+), 47 deletions(-) create mode 100644 src/client.js diff --git a/src/app.module.ts b/src/app.module.ts index 4505fd4..e678178 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -27,7 +27,7 @@ import { TokenRepository } from './auth/repositories/token.repository'; UserModule, TypeOrmModule.forRoot({ ...TypeORMconfig, // TypeORM 설정 객체 확장 - synchronize: true, // DB 동기화 여부 설정 + synchronize: false, // DB 동기화 여부 설정 }), // TypeOrmModule.forFeature([Image]), ConfigModule.forRoot({ diff --git a/src/client.js b/src/client.js new file mode 100644 index 0000000..c411b40 --- /dev/null +++ b/src/client.js @@ -0,0 +1,29 @@ +const namespaceURL = 'http://localhost:3000/ch-650bde3798dd4c34439c30dc'; +const socket = io(namespaceURL); + +socket.on('connect', () => { + console.log('Connected to WebSocket server'); + + // 예제로 'login' 이벤트를 보내는 방법 + socket.emit('login', { id: 1, rooms: [`ch-650bde3798dd4c34439c30dc`] }); +}); + +socket.on('hello', (data) => { + console.log('Received hello message:', data); +}); + +socket.on('msgNoti', (data) => { + console.log('Received message notification:', data); +}); + +socket.on('disconnect', () => { + console.log('Disconnected from WebSocket server'); +}); + +// 해당 네임스페이스의 이벤트를 수신 +socket.on('message', (data) => { + console.log( + 'Received message notification in the specified namespace:', + data, + ); +}); diff --git a/src/config/typeorm.config.ts b/src/config/typeorm.config.ts index 23847be..eac7daa 100644 --- a/src/config/typeorm.config.ts +++ b/src/config/typeorm.config.ts @@ -40,5 +40,5 @@ export const TypeORMconfig: TypeOrmModuleOptions = { CommentNotification, // BoardRepository, ], // 여기에 엔티티들을 추가해야 합니다. - synchronize: process.env.NODE_ENV === 'true', + synchronize: process.env.NODE_ENV === 'false', }; diff --git a/src/index.html b/src/index.html index 7fdb19e..25876ad 100644 --- a/src/index.html +++ b/src/index.html @@ -1,49 +1,12 @@ - + WebSocket Example - - -
- - - - - + + +

WebSocket Example

+ + + + From 7e6a74c23103eb89b8e494aa8c36041f730dbb8f Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 19 Oct 2023 20:49:32 +0900 Subject: [PATCH 08/24] =?UTF-8?q?feat(#39):=20chat=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?socket.to()=20=EC=A3=BC=EC=86=8C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20chat-notification=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/schemas/chat-notifiation.schemas.ts | 17 ++++++++++++++++- src/chat/services/chat.service.ts | 4 +++- src/client.js | 5 ++++- src/events/events.gateway.ts | 7 +++---- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/chat/schemas/chat-notifiation.schemas.ts b/src/chat/schemas/chat-notifiation.schemas.ts index aac1563..48e4821 100644 --- a/src/chat/schemas/chat-notifiation.schemas.ts +++ b/src/chat/schemas/chat-notifiation.schemas.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose'; import * as mongoose from 'mongoose'; import { Chat } from './chat.schemas'; -import { IsMongoId, IsNotEmpty } from 'class-validator'; +import { IsBoolean, IsMongoId, IsNotEmpty, IsNumber } from 'class-validator'; const options: SchemaOptions = { collection: 'ChatNotification', @@ -14,6 +14,21 @@ export class ChatNotification { @IsNotEmpty() @Prop({ type: mongoose.Types.ObjectId, ref: Chat.name }) chat_id: mongoose.Types.ObjectId; + + @IsNumber() + @IsNotEmpty() + @Prop({ required: true }) + sender: number; + + @IsNumber() + @IsNotEmpty() + @Prop({ required: true }) + receiver: number; + + @IsBoolean() + @IsNotEmpty() + @Prop({ required: true, default: false }) + isSeen: boolean; } export const ChatNotificationSchema = diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index b5488d1..82368a3 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -161,7 +161,9 @@ export class ChatService { }; const socketRoomId = returnedChat.chatroom_id.toString(); - this.eventsGateway.server.to(`ch-${socketRoomId}`).emit('message', chat); + this.eventsGateway.server + .to(`/ch-${socketRoomId}-${socketRoomId}`) + .emit('message', chat); const notification = await new this.chatNotificationModel({ chat_id: returnedChat.id, diff --git a/src/client.js b/src/client.js index c411b40..3d6913d 100644 --- a/src/client.js +++ b/src/client.js @@ -5,7 +5,10 @@ socket.on('connect', () => { console.log('Connected to WebSocket server'); // 예제로 'login' 이벤트를 보내는 방법 - socket.emit('login', { id: 1, rooms: [`ch-650bde3798dd4c34439c30dc`] }); + socket.emit('login', { + id: 1, + rooms: ['650bde3798dd4c34439c30dc'.toString()], + }); }); socket.on('hello', (data) => { diff --git a/src/events/events.gateway.ts b/src/events/events.gateway.ts index 1af933e..32a8fd7 100644 --- a/src/events/events.gateway.ts +++ b/src/events/events.gateway.ts @@ -11,8 +11,7 @@ import { import { Server, Socket } from 'socket.io'; import mongoose from 'mongoose'; -@WebSocketGateway({ namespace: /\/ch-\d+/, cors: true }) -// @WebSocketGateway({ namespace: '/ch123' }) +@WebSocketGateway({ namespace: /\/ch-.+/, cors: true }) export class EventsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { @@ -25,13 +24,12 @@ export class EventsGateway @SubscribeMessage('login') handleLogin( - // @MessageBody() data: { id: number; roomId: number[] }, @MessageBody() data: { id: number; rooms: mongoose.Types.ObjectId[] }, @ConnectedSocket() socket: Socket, ) { console.log('login', data.id); data.rooms.forEach((room) => { - socket.join(`${room}`); + socket.join(room.toString()); console.log('join', room); }); } @@ -50,6 +48,7 @@ export class EventsGateway const userName = data.id; socket.data.userName = userName; }); + socket.on('notification', () => {}); socket.on('message', (data) => { const userId = data.id; const chat = data.message; From 739779b51a0f4b5c0bcf625a93f00fdb795bdea4 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 19 Oct 2023 21:17:12 +0900 Subject: [PATCH 09/24] =?UTF-8?q?feat(#39):=20board-notice=20entity=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/notice/entities/board-notice.entity.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/notice/entities/board-notice.entity.ts b/src/notice/entities/board-notice.entity.ts index f470c55..4cb81ef 100644 --- a/src/notice/entities/board-notice.entity.ts +++ b/src/notice/entities/board-notice.entity.ts @@ -1,4 +1,5 @@ import { Board } from 'src/boards/entities/board.entity'; +import { User } from 'src/users/entities/user.entity'; import { CreateDateColumn, Entity, @@ -16,6 +17,14 @@ export class BoardNotification { @JoinColumn({ name: 'board_id' }) boardId: Board; + @ManyToOne(() => User) + @JoinColumn({ name: 'sender_id' }) + senderId: User; + + @ManyToOne(() => User) + @JoinColumn({ name: 'receiver_id' }) + receiverId: User; + @CreateDateColumn({ name: 'create_at' }) createAt: Date; } From b03a31587f03c97730cc98de7558fbd8633566ec Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Fri, 20 Oct 2023 10:56:46 +0900 Subject: [PATCH 10/24] =?UTF-8?q?feat(#39):=20=EC=95=8C=EB=9E=8C=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20entity=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 +- src/config/typeorm.config.ts | 2 +- src/notice/entities/comment-notice.entity.ts | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index da70845..c08a31c 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -27,7 +27,7 @@ import { TokenRepository } from './auth/repositories/token.repository'; UserModule, TypeOrmModule.forRoot({ ...TypeORMconfig, // TypeORM 설정 객체 확장 - synchronize: false, // DB 동기화 여부 설정 + synchronize: true, // DB 동기화 여부 설정 }), // TypeOrmModule.forFeature([Image]), ConfigModule.forRoot({ diff --git a/src/config/typeorm.config.ts b/src/config/typeorm.config.ts index 13336a4..d39206e 100644 --- a/src/config/typeorm.config.ts +++ b/src/config/typeorm.config.ts @@ -40,5 +40,5 @@ export const TypeORMconfig: TypeOrmModuleOptions = { CommentNotification, // BoardRepository, ], // 여기에 엔티티들을 추가해야 합니다. - synchronize: process.env.NODE_ENV === 'false', + synchronize: process.env.NODE_ENV === 'true', }; diff --git a/src/notice/entities/comment-notice.entity.ts b/src/notice/entities/comment-notice.entity.ts index 30d77bd..4cadbbe 100644 --- a/src/notice/entities/comment-notice.entity.ts +++ b/src/notice/entities/comment-notice.entity.ts @@ -1,4 +1,5 @@ import { Comment } from 'src/comments/entities/comment.entity'; +import { User } from 'src/users/entities/user.entity'; import { CreateDateColumn, Entity, @@ -16,6 +17,14 @@ export class CommentNotification { @JoinColumn({ name: 'comment_id' }) commentId: Comment; + @ManyToOne(() => User) + @JoinColumn({ name: 'sender_id' }) + senderId: User; + + @ManyToOne(() => User) + @JoinColumn({ name: 'receiver_id' }) + receiverId: User; + @CreateDateColumn({ name: 'create_at' }) createAt: Date; } From 8ef8525a0a0035ce377e8c353de9dfa9e635f744 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Fri, 20 Oct 2023 14:29:05 +0900 Subject: [PATCH 11/24] =?UTF-8?q?feat(#39):=20synchronize:=20false,=20sock?= =?UTF-8?q?et=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95(=EC=8B=A4=ED=8C=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 +- src/chat/services/chat.service.ts | 5 +++-- src/client.js | 12 ++++++------ src/config/typeorm.config.ts | 2 +- src/events/events.gateway.ts | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index c08a31c..da70845 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -27,7 +27,7 @@ import { TokenRepository } from './auth/repositories/token.repository'; UserModule, TypeOrmModule.forRoot({ ...TypeORMconfig, // TypeORM 설정 객체 확장 - synchronize: true, // DB 동기화 여부 설정 + synchronize: false, // DB 동기화 여부 설정 }), // TypeOrmModule.forFeature([Image]), ConfigModule.forRoot({ diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 82368a3..c1aa88e 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -164,11 +164,12 @@ export class ChatService { this.eventsGateway.server .to(`/ch-${socketRoomId}-${socketRoomId}`) .emit('message', chat); + console.log(`Message sent to room: ch-${socketRoomId}-${socketRoomId}`); const notification = await new this.chatNotificationModel({ chat_id: returnedChat.id, - // title: createNotificationsDto.title, - // isSeen: false, + sender: returnedChat.sender, + receiver: returnedChat.receiver, }) .save() .catch((error) => { diff --git a/src/client.js b/src/client.js index 3d6913d..a029b68 100644 --- a/src/client.js +++ b/src/client.js @@ -7,8 +7,11 @@ socket.on('connect', () => { // 예제로 'login' 이벤트를 보내는 방법 socket.emit('login', { id: 1, - rooms: ['650bde3798dd4c34439c30dc'.toString()], + rooms: ['650bde3798dd4c34439c30dc'], }); + console.log(socket); + + // 해당 네임스페이스의 이벤트를 수신 }); socket.on('hello', (data) => { @@ -23,10 +26,7 @@ socket.on('disconnect', () => { console.log('Disconnected from WebSocket server'); }); -// 해당 네임스페이스의 이벤트를 수신 socket.on('message', (data) => { - console.log( - 'Received message notification in the specified namespace:', - data, - ); + console.log('Received message:', data); + // 여기에서 메시지를 처리하거나 화면에 표시하는 로직을 추가하세요. }); diff --git a/src/config/typeorm.config.ts b/src/config/typeorm.config.ts index d39206e..13336a4 100644 --- a/src/config/typeorm.config.ts +++ b/src/config/typeorm.config.ts @@ -40,5 +40,5 @@ export const TypeORMconfig: TypeOrmModuleOptions = { CommentNotification, // BoardRepository, ], // 여기에 엔티티들을 추가해야 합니다. - synchronize: process.env.NODE_ENV === 'true', + synchronize: process.env.NODE_ENV === 'false', }; diff --git a/src/events/events.gateway.ts b/src/events/events.gateway.ts index 32a8fd7..43a6ff7 100644 --- a/src/events/events.gateway.ts +++ b/src/events/events.gateway.ts @@ -29,8 +29,8 @@ export class EventsGateway ) { console.log('login', data.id); data.rooms.forEach((room) => { - socket.join(room.toString()); - console.log('join', room); + console.log('join', socket.nsp.name, room); + socket.join(`${socket.nsp.name.toString()}-${room.toString()}`); }); } From 97393d75f1efc5023dad3a0c2a7d51aec2db893d Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 03:48:55 +0900 Subject: [PATCH 12/24] =?UTF-8?q?feat(#60):=20socket-service-repository=20?= =?UTF-8?q?=EC=88=9C=EC=9C=BC=EB=A1=9C=20=EC=B1=84=ED=8C=85=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 5 +---- src/chat/chat.module.ts | 5 ++--- src/chat/controllers/chat.controller.ts | 30 ++++++++++++------------- src/chat/dto/post-chat.dto.ts | 19 +++++++++++++++- src/{ => chat}/events/events.gateway.ts | 22 +++++++++++++++++- src/chat/services/chat.service.ts | 26 +++++++-------------- src/client.js | 6 ++++- src/events/events.gateway.spec.ts | 18 --------------- src/events/events.module.ts | 8 ------- src/events/onlineMap.ts | 1 - 10 files changed, 70 insertions(+), 70 deletions(-) rename src/{ => chat}/events/events.gateway.ts (68%) delete mode 100644 src/events/events.gateway.spec.ts delete mode 100644 src/events/events.module.ts delete mode 100644 src/events/onlineMap.ts diff --git a/src/app.module.ts b/src/app.module.ts index da70845..91aadf6 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -14,8 +14,7 @@ import { S3Service } from './common/s3/s3.service'; import { BoardsModule } from './boards/boards.module'; import { FriendsModule } from './friends/friends.module'; import { NoticeModule } from './notice/notice.module'; -import { EventsGateway } from './events/events.gateway'; -import { EventsModule } from './events/events.module'; +import { EventsGateway } from './chat/events/events.gateway'; import * as mongoose from 'mongoose'; import { UserImageRepository } from './users/repositories/user-image.repository'; import { TokenRepository } from './auth/repositories/token.repository'; @@ -40,7 +39,6 @@ import { TokenRepository } from './auth/repositories/token.repository'; BoardsModule, FriendsModule, NoticeModule, - EventsModule, ], // providers: [ TokenService, @@ -48,7 +46,6 @@ import { TokenRepository } from './auth/repositories/token.repository'; UserImageService, UserImageRepository, S3Service, - EventsGateway, ], }) export class AppModule implements NestModule { diff --git a/src/chat/chat.module.ts b/src/chat/chat.module.ts index dae78ad..4013c41 100644 --- a/src/chat/chat.module.ts +++ b/src/chat/chat.module.ts @@ -9,10 +9,10 @@ import { ChatNotification, ChatNotificationSchema, } from './schemas/chat-notifiation.schemas'; -import { EventsModule } from 'src/events/events.module'; import { S3Module } from 'src/common/s3/s3.module'; import { ChatRepository } from './repositories/chat.repository'; import { NotificationService } from './services/notification.service'; +import { EventsGateway } from './events/events.gateway'; @Module({ imports: [ @@ -22,10 +22,9 @@ import { NotificationService } from './services/notification.service'; { name: ChatImage.name, schema: ChatImageSchema }, { name: ChatNotification.name, schema: ChatNotificationSchema }, ]), - EventsModule, S3Module, ], controllers: [ChatController], - providers: [ChatService, ChatRepository, NotificationService], + providers: [ChatService, ChatRepository, NotificationService, EventsGateway], }) export class ChatModule {} diff --git a/src/chat/controllers/chat.controller.ts b/src/chat/controllers/chat.controller.ts index 5705123..3e81829 100644 --- a/src/chat/controllers/chat.controller.ts +++ b/src/chat/controllers/chat.controller.ts @@ -74,21 +74,21 @@ export class ChatController { return this.chatService.getChats(roomId); } - @ApiOperation({ summary: '특정 채팅방 채팅 생성' }) - @Post(':roomId/chat/:testUser') - async createChat( - @Param('testUser') testUser: number, - @Users() user: User, - @Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId, - @Body() body: PostChatDto, - ) { - return this.chatService.createChat( - roomId, - body.content, - testUser, - body.receiverId, - ); - } + // @ApiOperation({ summary: '특정 채팅방 채팅 생성' }) + // @Post(':roomId/chat/:testUser') + // async createChat( + // @Param('testUser') testUser: number, + // @Users() user: User, + // @Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId, + // @Body() body: PostChatDto, + // ) { + // return this.chatService.createChat( + // roomId, + // body.content, + // testUser, + // body.receiverId, + // ); + // } @ApiOperation({ summary: '특정 채팅방 채팅 이미지 생성' }) @Post(':roomId/chat/image') diff --git a/src/chat/dto/post-chat.dto.ts b/src/chat/dto/post-chat.dto.ts index e875920..d04b5b5 100644 --- a/src/chat/dto/post-chat.dto.ts +++ b/src/chat/dto/post-chat.dto.ts @@ -1,7 +1,16 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsNumber, IsString } from 'class-validator'; +import { IsMongoId, IsNotEmpty, IsNumber, IsString } from 'class-validator'; +import mongoose from 'mongoose'; export class PostChatDto { + @IsMongoId() + @IsNotEmpty() + @ApiProperty({ + example: '650bde3798dd4c34439c30dc', + description: '채팅을 전송하는 채팅방 id', + }) + roomId: mongoose.Types.ObjectId; + @ApiProperty({ example: '안녕하세요', description: '채팅 내용', @@ -12,6 +21,14 @@ export class PostChatDto { @ApiProperty({ example: '1', + description: '채팅을 보내는 유저 아이디', + }) + @IsNumber() + @IsNotEmpty() + senderId: number; + + @ApiProperty({ + example: '2', description: '채팅을 받는 유저 아이디', }) @IsNumber() diff --git a/src/events/events.gateway.ts b/src/chat/events/events.gateway.ts similarity index 68% rename from src/events/events.gateway.ts rename to src/chat/events/events.gateway.ts index 43a6ff7..ad69185 100644 --- a/src/events/events.gateway.ts +++ b/src/chat/events/events.gateway.ts @@ -10,11 +10,14 @@ import { } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import mongoose from 'mongoose'; +import { ChatService } from 'src/chat/services/chat.service'; +import { PostChatDto } from '../dto/post-chat.dto'; @WebSocketGateway({ namespace: /\/ch-.+/, cors: true }) export class EventsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { + constructor(private chatService: ChatService) {} @WebSocketServer() public server: Server; @SubscribeMessage('test') @@ -30,10 +33,23 @@ export class EventsGateway console.log('login', data.id); data.rooms.forEach((room) => { console.log('join', socket.nsp.name, room); - socket.join(`${socket.nsp.name.toString()}-${room.toString()}`); + socket.join(room.toString()); }); } + @SubscribeMessage('message') + handleMessage( + @MessageBody() postChatDto: PostChatDto, + @ConnectedSocket() socket: Socket, + ) { + this.chatService.createChat(postChatDto, socket); + // this.chats; + // const socketRoomId = data.roomId; + // console.log(data.roomId); + // socket.to(socketRoomId).emit('message', '설마성공?', data.message); + // this.server.to(socketRoomId).emit('message', '설마성공?', data.message); + } + afterInit(server: Server): any { console.log('websocketserver init'); } @@ -48,6 +64,10 @@ export class EventsGateway const userName = data.id; socket.data.userName = userName; }); + socket.on('asdf', (data) => { + console.log(data); + socket.to(`/ch-${socket.nsp.name}`).emit('message', data); + }); socket.on('notification', () => {}); socket.on('message', (data) => { const userId = data.id; diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index c1aa88e..92445be 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -10,11 +10,11 @@ import { import { InjectModel } from '@nestjs/mongoose'; import { ChatRoom } from '../schemas/chat-room.schemas'; import * as mongoose from 'mongoose'; -import { EventsGateway } from 'src/events/events.gateway'; import { S3Service } from 'src/common/s3/s3.service'; import { NotificationService } from './notification.service'; import { ChatNotification } from '../schemas/chat-notifiation.schemas'; import { Subject, map } from 'rxjs'; +import { Socket } from 'socket.io'; @Injectable() export class ChatService { @@ -26,7 +26,6 @@ export class ChatService { private readonly chatRepository: ChatRepository, @InjectModel(ChatRoom.name) private readonly chatRoomModel: mongoose.Model, - private readonly eventsGateway: EventsGateway, @InjectModel(ChatNotification.name) private readonly chatNotificationModel: mongoose.Model, ) {} @@ -124,21 +123,16 @@ export class ChatService { return returnedChat; } - async createChat( - roomId: mongoose.Types.ObjectId, - content: string, - myId: number, - receiverId: number, - ) { - await this.getOneChatRoom(myId, roomId); + async createChat({ roomId, content, senderId, receiverId }, socket: Socket) { + await this.getOneChatRoom(senderId, roomId); const isChatRoom = await this.chatRoomModel.findOne({ $or: [ { - $and: [{ host_id: myId }, { guest_id: receiverId }], + $and: [{ host_id: senderId }, { guest_id: receiverId }], }, { - $and: [{ host_id: receiverId }, { guest_id: myId }], + $and: [{ host_id: receiverId }, { guest_id: senderId }], }, ], }); @@ -150,7 +144,7 @@ export class ChatService { const returnedChat = await this.chatRepository.createChat( roomId, content, - myId, + senderId, receiverId, ); @@ -160,11 +154,7 @@ export class ChatService { receiver: returnedChat.receiver, }; - const socketRoomId = returnedChat.chatroom_id.toString(); - this.eventsGateway.server - .to(`/ch-${socketRoomId}-${socketRoomId}`) - .emit('message', chat); - console.log(`Message sent to room: ch-${socketRoomId}-${socketRoomId}`); + socket.to(returnedChat.chatroom_id.toString()).emit('message', chat); const notification = await new this.chatNotificationModel({ chat_id: returnedChat.id, @@ -221,7 +211,7 @@ export class ChatService { }; const socketRoomId = returnedChat.chatroom_id.toString(); - this.eventsGateway.server.to(`ch-${socketRoomId}`).emit('message', chat); + // this.eventsGateway.server.to(`ch-${socketRoomId}`).emit('message', chat); return chat; } diff --git a/src/client.js b/src/client.js index a029b68..974e0c6 100644 --- a/src/client.js +++ b/src/client.js @@ -9,7 +9,11 @@ socket.on('connect', () => { id: 1, rooms: ['650bde3798dd4c34439c30dc'], }); - console.log(socket); + // socket.emit('messages', { + // roomId: '650bde3798dd4c34439c30dc', + // message: 'asdf', + // }); + // console.log(socket); // 해당 네임스페이스의 이벤트를 수신 }); diff --git a/src/events/events.gateway.spec.ts b/src/events/events.gateway.spec.ts deleted file mode 100644 index f17cf2a..0000000 --- a/src/events/events.gateway.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { EventsGateway } from './events.gateway'; - -describe('EventsGateway', () => { - let gateway: EventsGateway; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [EventsGateway], - }).compile(); - - gateway = module.get(EventsGateway); - }); - - it('should be defined', () => { - expect(gateway).toBeDefined(); - }); -}); diff --git a/src/events/events.module.ts b/src/events/events.module.ts deleted file mode 100644 index d97b523..0000000 --- a/src/events/events.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Module } from '@nestjs/common'; -import { EventsGateway } from './events.gateway'; - -@Module({ - providers: [EventsGateway], - exports: [EventsGateway], -}) -export class EventsModule {} diff --git a/src/events/onlineMap.ts b/src/events/onlineMap.ts deleted file mode 100644 index 863ed88..0000000 --- a/src/events/onlineMap.ts +++ /dev/null @@ -1 +0,0 @@ -export const onlineMap = {}; From d2211a9bbb85a7466a6411bc4550b84326a6ad61 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 03:49:36 +0900 Subject: [PATCH 13/24] =?UTF-8?q?feat(#60):=20socket.emit=EC=9D=80=20gatew?= =?UTF-8?q?ay=EC=97=90=EC=84=9C=20=EC=8B=A4=ED=96=89=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/events/events.gateway.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chat/events/events.gateway.ts b/src/chat/events/events.gateway.ts index ad69185..3b3cf23 100644 --- a/src/chat/events/events.gateway.ts +++ b/src/chat/events/events.gateway.ts @@ -38,11 +38,13 @@ export class EventsGateway } @SubscribeMessage('message') - handleMessage( + async handleMessage( @MessageBody() postChatDto: PostChatDto, @ConnectedSocket() socket: Socket, ) { - this.chatService.createChat(postChatDto, socket); + const chat = await this.chatService.createChat(postChatDto, socket); + socket.to(postChatDto.roomId.toString()).emit('message', chat); + return chat; // this.chats; // const socketRoomId = data.roomId; // console.log(data.roomId); From fc2ff6afbf3f32a564cff1c51c7f34df28c837d0 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 04:00:51 +0900 Subject: [PATCH 14/24] =?UTF-8?q?feat(#60):=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/events/events.gateway.ts | 24 ------------------------ src/chat/services/chat.service.ts | 2 -- 2 files changed, 26 deletions(-) diff --git a/src/chat/events/events.gateway.ts b/src/chat/events/events.gateway.ts index 3b3cf23..3d5dfe1 100644 --- a/src/chat/events/events.gateway.ts +++ b/src/chat/events/events.gateway.ts @@ -44,12 +44,6 @@ export class EventsGateway ) { const chat = await this.chatService.createChat(postChatDto, socket); socket.to(postChatDto.roomId.toString()).emit('message', chat); - return chat; - // this.chats; - // const socketRoomId = data.roomId; - // console.log(data.roomId); - // socket.to(socketRoomId).emit('message', '설마성공?', data.message); - // this.server.to(socketRoomId).emit('message', '설마성공?', data.message); } afterInit(server: Server): any { @@ -59,24 +53,6 @@ export class EventsGateway handleConnection(@ConnectedSocket() socket: Socket): any { console.log('connected', socket.nsp.name); socket.emit('hello', socket.nsp.name); - socket.on('hello', (data) => { - console.log(data); - }); - socket.on('login', (data) => { - const userName = data.id; - socket.data.userName = userName; - }); - socket.on('asdf', (data) => { - console.log(data); - socket.to(`/ch-${socket.nsp.name}`).emit('message', data); - }); - socket.on('notification', () => {}); - socket.on('message', (data) => { - const userId = data.id; - const chat = data.message; - console.log('Received new chat message:', data.message); - socket.broadcast.emit('msgNoti', `${userId}의 message: ${chat}`); - }); } handleDisconnect(@ConnectedSocket() socket: Socket): any { diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 92445be..f49273a 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -154,8 +154,6 @@ export class ChatService { receiver: returnedChat.receiver, }; - socket.to(returnedChat.chatroom_id.toString()).emit('message', chat); - const notification = await new this.chatNotificationModel({ chat_id: returnedChat.id, sender: returnedChat.sender, From 95eb9de3eb46978fcd454e343809022cea5ad5e1 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 04:02:20 +0900 Subject: [PATCH 15/24] =?UTF-8?q?feat(#60):=20controller=20=EC=B1=84?= =?UTF-8?q?=ED=8C=85=EC=83=9D=EC=84=B1=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/controllers/chat.controller.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/chat/controllers/chat.controller.ts b/src/chat/controllers/chat.controller.ts index 3e81829..111b6ef 100644 --- a/src/chat/controllers/chat.controller.ts +++ b/src/chat/controllers/chat.controller.ts @@ -74,22 +74,6 @@ export class ChatController { return this.chatService.getChats(roomId); } - // @ApiOperation({ summary: '특정 채팅방 채팅 생성' }) - // @Post(':roomId/chat/:testUser') - // async createChat( - // @Param('testUser') testUser: number, - // @Users() user: User, - // @Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId, - // @Body() body: PostChatDto, - // ) { - // return this.chatService.createChat( - // roomId, - // body.content, - // testUser, - // body.receiverId, - // ); - // } - @ApiOperation({ summary: '특정 채팅방 채팅 이미지 생성' }) @Post(':roomId/chat/image') @UseInterceptors(FileInterceptor('file')) From b3dbf18650b015c02a8b8c04c7db6bef21dc7e0f Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 04:27:13 +0900 Subject: [PATCH 16/24] =?UTF-8?q?feat(#60):=20Dto=EC=97=90=20imageUrl?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20gateway=EC=97=90=EC=84=9C=20imageUpload?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80(=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=EB=8A=94=20=EC=95=84=EC=A7=81=20=EB=AF=B8?= =?UTF-8?q?=EC=99=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/controllers/chat.controller.ts | 1 - src/chat/dto/post-chat.dto.ts | 13 +++++++++++-- src/chat/events/events.gateway.ts | 4 +++- src/chat/services/chat.service.ts | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/chat/controllers/chat.controller.ts b/src/chat/controllers/chat.controller.ts index 111b6ef..24070af 100644 --- a/src/chat/controllers/chat.controller.ts +++ b/src/chat/controllers/chat.controller.ts @@ -14,7 +14,6 @@ import { import { ChatService } from '../services/chat.service'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ReceivedUserDto } from '../dto/received-user.dto'; -import { PostChatDto } from '../dto/post-chat.dto'; import mongoose from 'mongoose'; import { FileInterceptor } from '@nestjs/platform-express'; import { Users } from 'src/common/decorators/user.decorator'; diff --git a/src/chat/dto/post-chat.dto.ts b/src/chat/dto/post-chat.dto.ts index d04b5b5..e7a590e 100644 --- a/src/chat/dto/post-chat.dto.ts +++ b/src/chat/dto/post-chat.dto.ts @@ -1,5 +1,11 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsMongoId, IsNotEmpty, IsNumber, IsString } from 'class-validator'; +import { + IsMongoId, + IsNotEmpty, + IsNumber, + IsOptional, + IsString, +} from 'class-validator'; import mongoose from 'mongoose'; export class PostChatDto { @@ -16,7 +22,7 @@ export class PostChatDto { description: '채팅 내용', }) @IsString() - @IsNotEmpty() + @IsOptional() content: string; @ApiProperty({ @@ -34,4 +40,7 @@ export class PostChatDto { @IsNumber() @IsNotEmpty() receiverId: number; + + @IsOptional() + imageUrl: FormData[]; } diff --git a/src/chat/events/events.gateway.ts b/src/chat/events/events.gateway.ts index 3d5dfe1..8c1b892 100644 --- a/src/chat/events/events.gateway.ts +++ b/src/chat/events/events.gateway.ts @@ -42,7 +42,9 @@ export class EventsGateway @MessageBody() postChatDto: PostChatDto, @ConnectedSocket() socket: Socket, ) { - const chat = await this.chatService.createChat(postChatDto, socket); + const chat = postChatDto.hasOwnProperty('imageUrl') + ? await this.chatService.createChat(postChatDto) + : await this.chatService.createChatImage(postChatDto); socket.to(postChatDto.roomId.toString()).emit('message', chat); } diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index f49273a..7ccd315 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -123,7 +123,7 @@ export class ChatService { return returnedChat; } - async createChat({ roomId, content, senderId, receiverId }, socket: Socket) { + async createChat({ roomId, content, senderId, receiverId }) { await this.getOneChatRoom(senderId, roomId); const isChatRoom = await this.chatRoomModel.findOne({ From 1b91b283cf765485400c01dd29909f1451417504 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 17:39:48 +0900 Subject: [PATCH 17/24] =?UTF-8?q?feat(#60):=20swagger-custom-decorators=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=EB=93=A4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C(Socket.io=20=EB=B0=8F=20=EC=B1=97=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=83=9D=EC=84=B1=EC=9D=80=20=EC=95=84?= =?UTF-8?q?=EC=A7=81=20=EB=AF=B8=EA=B5=AC=ED=98=84=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=A7=80=20=EC=95=8A=EC=9D=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 1 - .../controllers/boards-like.controller.ts | 6 +- .../add-board-like.decorator.ts | 0 .../delete-board-like.decorator.ts | 0 .../get-board-like-count.decorator.ts | 0 src/chat/controllers/chat.controller.ts | 23 +++--- src/chat/dto/post-chat.dto.ts | 6 +- src/chat/events/events.gateway.ts | 4 +- src/chat/services/chat.service.ts | 1 - .../create-chat-room.decorator.ts | 54 +++++++++++++ .../delete-chat-room.decorator.ts | 62 +++++++++++++++ .../get-chat-notification.decorator.ts | 29 +++++++ .../get-chat-rooms.decorator.ts | 52 +++++++++++++ .../swagger-decorators/get-chats.decorator.ts | 77 +++++++++++++++++++ .../get-one-chat-room.decorator.ts | 54 +++++++++++++ 15 files changed, 350 insertions(+), 19 deletions(-) rename src/boards/{swagger-descorators => swagger-decorators}/add-board-like.decorator.ts (100%) rename src/boards/{swagger-descorators => swagger-decorators}/delete-board-like.decorator.ts (100%) rename src/boards/{swagger-descorators => swagger-decorators}/get-board-like-count.decorator.ts (100%) create mode 100644 src/chat/swagger-decorators/create-chat-room.decorator.ts create mode 100644 src/chat/swagger-decorators/delete-chat-room.decorator.ts create mode 100644 src/chat/swagger-decorators/get-chat-notification.decorator.ts create mode 100644 src/chat/swagger-decorators/get-chat-rooms.decorator.ts create mode 100644 src/chat/swagger-decorators/get-chats.decorator.ts create mode 100644 src/chat/swagger-decorators/get-one-chat-room.decorator.ts diff --git a/src/app.module.ts b/src/app.module.ts index 91aadf6..1eed4ff 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -14,7 +14,6 @@ import { S3Service } from './common/s3/s3.service'; import { BoardsModule } from './boards/boards.module'; import { FriendsModule } from './friends/friends.module'; import { NoticeModule } from './notice/notice.module'; -import { EventsGateway } from './chat/events/events.gateway'; import * as mongoose from 'mongoose'; import { UserImageRepository } from './users/repositories/user-image.repository'; import { TokenRepository } from './auth/repositories/token.repository'; diff --git a/src/boards/controllers/boards-like.controller.ts b/src/boards/controllers/boards-like.controller.ts index 07b2ec5..21bf591 100644 --- a/src/boards/controllers/boards-like.controller.ts +++ b/src/boards/controllers/boards-like.controller.ts @@ -12,9 +12,9 @@ import { BoardsLikeService } from '../services/boards-like.service'; import { Users } from 'src/common/decorators/user.decorator'; import { User } from 'src/users/entities/user.entity'; import { ApiTags } from '@nestjs/swagger'; -import { ApiAddBoardLike } from '../swagger-descorators/add-board-like.decorator'; -import { ApiGetBoardLikeCount } from '../swagger-descorators/get-board-like-count.decorator'; -import { ApiDeleteBoardLike } from '../swagger-descorators/delete-board-like.decorator'; +import { ApiAddBoardLike } from '../swagger-decorators/add-board-like.decorator'; +import { ApiGetBoardLikeCount } from '../swagger-decorators/get-board-like-count.decorator'; +import { ApiDeleteBoardLike } from '../swagger-decorators/delete-board-like.decorator'; @ApiTags('BOARDS-LIKE') @UsePipes(ValidationPipe) diff --git a/src/boards/swagger-descorators/add-board-like.decorator.ts b/src/boards/swagger-decorators/add-board-like.decorator.ts similarity index 100% rename from src/boards/swagger-descorators/add-board-like.decorator.ts rename to src/boards/swagger-decorators/add-board-like.decorator.ts diff --git a/src/boards/swagger-descorators/delete-board-like.decorator.ts b/src/boards/swagger-decorators/delete-board-like.decorator.ts similarity index 100% rename from src/boards/swagger-descorators/delete-board-like.decorator.ts rename to src/boards/swagger-decorators/delete-board-like.decorator.ts diff --git a/src/boards/swagger-descorators/get-board-like-count.decorator.ts b/src/boards/swagger-decorators/get-board-like-count.decorator.ts similarity index 100% rename from src/boards/swagger-descorators/get-board-like-count.decorator.ts rename to src/boards/swagger-decorators/get-board-like-count.decorator.ts diff --git a/src/chat/controllers/chat.controller.ts b/src/chat/controllers/chat.controller.ts index 24070af..2fba775 100644 --- a/src/chat/controllers/chat.controller.ts +++ b/src/chat/controllers/chat.controller.ts @@ -19,29 +19,32 @@ import { FileInterceptor } from '@nestjs/platform-express'; import { Users } from 'src/common/decorators/user.decorator'; import { User } from 'src/users/entities/user.entity'; import { ParseObjectIdPipe } from '../parse-object-id.pipe'; -import { NotificationService } from '../services/notification.service'; +import { ApiCreateChatRoom } from '../swagger-decorators/create-chat-room.decorator'; +import { ApiGetChatRooms } from '../swagger-decorators/get-chat-rooms.decorator'; +import { ApiGetOneChatRoom } from '../swagger-decorators/get-one-chat-room.decorator'; +import { ApiDeleteChatRoom } from '../swagger-decorators/delete-chat-room.decorator'; +import { ApiGetChats } from '../swagger-decorators/get-chats.decorator'; +import { ApiGetChatNotification } from '../swagger-decorators/get-chat-notification.decorator'; @ApiTags('CHAT') @Controller('chat-room') @UsePipes(ValidationPipe) export class ChatController { - constructor( - private chatService: ChatService, - private notificationService: NotificationService, - ) {} + constructor(private chatService: ChatService) {} + @ApiGetChatNotification() @Sse('listener') notificationListener() { return this.chatService.notificationListener(); } - @ApiOperation({ summary: '채팅방 전체 조회' }) + @ApiGetChatRooms() @Get() async getChatRooms(@Users() user: User) { return this.chatService.getChatRooms(user.id); } - @ApiOperation({ summary: '채팅방 단일 조회' }) + @ApiGetOneChatRoom() @Get(':roomId') async getOneChatRoom( @Users() user: User, @@ -50,13 +53,13 @@ export class ChatController { return this.chatService.getOneChatRoom(user.id, roomId); } - @ApiOperation({ summary: '채팅방 생성' }) + @ApiCreateChatRoom() @Post() async createChatRoom(@Users() user: User, @Body() body: ReceivedUserDto) { return this.chatService.createChatRoom(user.id, body.receiverId); } - @ApiOperation({ summary: '해당 채팅방 삭제' }) + @ApiDeleteChatRoom() @Delete(':roomId') async deleteChatRoom( @Users() user: User, @@ -65,7 +68,7 @@ export class ChatController { return this.chatService.deleteChatRoom(user.id, roomId); } - @ApiOperation({ summary: '특정 채팅방 채팅 전체 조회' }) + @ApiGetChats() @Get(':roomId/chat') async getChats( @Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId, diff --git a/src/chat/dto/post-chat.dto.ts b/src/chat/dto/post-chat.dto.ts index e7a590e..5a9a05e 100644 --- a/src/chat/dto/post-chat.dto.ts +++ b/src/chat/dto/post-chat.dto.ts @@ -41,6 +41,10 @@ export class PostChatDto { @IsNotEmpty() receiverId: number; + @ApiProperty({ + example: 'Key: file, Value: asd.png', + description: 'FormData. 이미지 파일', + }) @IsOptional() - imageUrl: FormData[]; + imageUrl: FormData; } diff --git a/src/chat/events/events.gateway.ts b/src/chat/events/events.gateway.ts index 8c1b892..2c394f8 100644 --- a/src/chat/events/events.gateway.ts +++ b/src/chat/events/events.gateway.ts @@ -42,9 +42,7 @@ export class EventsGateway @MessageBody() postChatDto: PostChatDto, @ConnectedSocket() socket: Socket, ) { - const chat = postChatDto.hasOwnProperty('imageUrl') - ? await this.chatService.createChat(postChatDto) - : await this.chatService.createChatImage(postChatDto); + const chat = await this.chatService.createChat(postChatDto); socket.to(postChatDto.roomId.toString()).emit('message', chat); } diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 7ccd315..2a2bb00 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -14,7 +14,6 @@ import { S3Service } from 'src/common/s3/s3.service'; import { NotificationService } from './notification.service'; import { ChatNotification } from '../schemas/chat-notifiation.schemas'; import { Subject, map } from 'rxjs'; -import { Socket } from 'socket.io'; @Injectable() export class ChatService { diff --git a/src/chat/swagger-decorators/create-chat-room.decorator.ts b/src/chat/swagger-decorators/create-chat-room.decorator.ts new file mode 100644 index 0000000..444fbb0 --- /dev/null +++ b/src/chat/swagger-decorators/create-chat-room.decorator.ts @@ -0,0 +1,54 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; + +export function ApiCreateChatRoom() { + return applyDecorators( + ApiOperation({ + summary: '채팅룸 생성', + description: 'Header - user-token, Body - received-user-dto', + }), + ApiResponse({ + status: 201, + description: '성공적으로 채팅방 생성', + content: { + JSON: { + example: { + host_id: 12345642, + guest_id: 123456427, + deleted_at: null, + _id: '653383a4468680bc4e9f8491', + createdAt: '2023-10-21T07:54:12.343Z', + updatedAt: '2023-10-21T07:54:12.343Z', + __v: 0, + }, + }, + }, + }), + ApiResponse({ + status: 409, + description: '해당 유저들의 채팅방이 이미 존재합니다.', + content: { + JSON: { + example: { + message: '해당 유저들의 채팅방이 이미 존재합니다.', + error: 'Conflict', + statusCode: 409, + }, + }, + }, + }), + ApiResponse({ + status: 409, + description: '채팅룸 생성 실패.', + content: { + JSON: { + example: { + message: '채팅룸 생성 실패. 서버에서 에러가 발생했습니다.', + error: 'Conflict', + statusCode: 409, + }, + }, + }, + }), + ); +} diff --git a/src/chat/swagger-decorators/delete-chat-room.decorator.ts b/src/chat/swagger-decorators/delete-chat-room.decorator.ts new file mode 100644 index 0000000..e0f5af3 --- /dev/null +++ b/src/chat/swagger-decorators/delete-chat-room.decorator.ts @@ -0,0 +1,62 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; + +export function ApiDeleteChatRoom() { + return applyDecorators( + ApiOperation({ + summary: '채팅룸 삭제', + description: 'Header - user-token, Param - room-id', + }), + ApiResponse({ + status: 200, + description: '성공적으로 채팅방 삭제', + content: { + JSON: { + example: { + success: true, + msg: '게시글 삭제 성공', + }, + }, + }, + }), + ApiResponse({ + status: 400, + description: '유효성 검사 실패', + content: { + JSON: { + example: { + message: '올바른 ObjectId 형식이 아닙니다.', + error: 'Bad Request', + statusCode: 400, + }, + }, + }, + }), + ApiResponse({ + status: 404, + description: '해당 채팅룸이 없습니다.', + content: { + JSON: { + example: { + message: '해당 채팅룸이 없습니다.', + error: 'Not Found', + statusCode: 404, + }, + }, + }, + }), + ApiResponse({ + status: 404, + description: '해당 유저는 채팅방에 속해있지 않습니다.', + content: { + JSON: { + example: { + message: '해당 유저는 채팅방에 속해있지 않습니다.', + error: 'Not Found', + statusCode: 404, + }, + }, + }, + }), + ); +} diff --git a/src/chat/swagger-decorators/get-chat-notification.decorator.ts b/src/chat/swagger-decorators/get-chat-notification.decorator.ts new file mode 100644 index 0000000..5060b27 --- /dev/null +++ b/src/chat/swagger-decorators/get-chat-notification.decorator.ts @@ -0,0 +1,29 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; + +export function ApiGetChatNotification() { + return applyDecorators( + ApiOperation({ + summary: '채팅 실시간 SSE 알람(미사용 예정)', + description: 'listener', + }), + ApiResponse({ + status: 200, + description: '성공적으로 SSE 연결 및 서버로부터 데이터 수신', + content: { + JSON: { + example: { + chat_id: '65338d7d1af00cf4e6964491', + sender: 12345642, + receiver: 123456427, + isSeen: false, + _id: '65338d7d1af00cf4e6964493', + createdAt: '2023-10-21T08:36:13.290Z', + updatedAt: '2023-10-21T08:36:13.290Z', + __v: 0, + }, + }, + }, + }), + ); +} diff --git a/src/chat/swagger-decorators/get-chat-rooms.decorator.ts b/src/chat/swagger-decorators/get-chat-rooms.decorator.ts new file mode 100644 index 0000000..91f5f40 --- /dev/null +++ b/src/chat/swagger-decorators/get-chat-rooms.decorator.ts @@ -0,0 +1,52 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; + +export function ApiGetChatRooms() { + return applyDecorators( + ApiOperation({ + summary: '채팅룸 조회', + description: 'Header - user-token', + }), + ApiResponse({ + status: 200, + description: '성공적으로 채팅방 조회', + content: { + JSON: { + example: [ + { + _id: '650bde3798dd4c34439c30dc', + host_id: 123, + guest_id: 1234, + deleted_at: null, + createdAt: '2023-09-21T06:09:59.724Z', + updatedAt: '2023-09-21T06:09:59.724Z', + __v: 0, + }, + { + _id: '6526a517b537b028e04ad45b', + host_id: 1234, + guest_id: 12345, + deleted_at: null, + createdAt: '2023-10-11T13:37:28.013Z', + updatedAt: '2023-10-11T13:37:28.013Z', + __v: 0, + }, + ], + }, + }, + }), + ApiResponse({ + status: 404, + description: '채팅룸 조회 실패.', + content: { + JSON: { + example: { + message: '해당 유저가 속한 채팅방이 없습니다.', + error: 'Not Found', + statusCode: 404, + }, + }, + }, + }), + ); +} diff --git a/src/chat/swagger-decorators/get-chats.decorator.ts b/src/chat/swagger-decorators/get-chats.decorator.ts new file mode 100644 index 0000000..9a2978a --- /dev/null +++ b/src/chat/swagger-decorators/get-chats.decorator.ts @@ -0,0 +1,77 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; + +export function ApiGetChats() { + return applyDecorators( + ApiOperation({ + summary: '해당 채팅룸 채팅 전체 조회', + description: 'Param - room-id', + }), + ApiResponse({ + status: 200, + description: '성공적으로 채팅방 채팅 조회', + content: { + JSON: { + example: [ + { + _id: '65338bc82d17fd935414495b', + chatroom_id: '653383a4468680bc4e9f8491', + sender: 12345642, + receiver: 123456427, + content: 'testtset', + createdAt: '2023-10-21T08:28:56.916Z', + updatedAt: '2023-10-21T08:28:56.916Z', + __v: 0, + }, + { + _id: '65338bec2d17fd9354144961', + chatroom_id: '653383a4468680bc4e9f8491', + sender: 12345642, + receiver: 123456427, + content: 'testtset12', + createdAt: '2023-10-21T08:29:32.578Z', + updatedAt: '2023-10-21T08:29:32.578Z', + __v: 0, + }, + { + _id: '65338bf12d17fd9354144967', + chatroom_id: '653383a4468680bc4e9f8491', + sender: 12345642, + receiver: 123456427, + content: 'testtset123', + createdAt: '2023-10-21T08:29:37.481Z', + updatedAt: '2023-10-21T08:29:37.481Z', + __v: 0, + }, + ], + }, + }, + }), + ApiResponse({ + status: 400, + description: '유효성 검사 실패', + content: { + JSON: { + example: { + message: '올바른 ObjectId 형식이 아닙니다.', + error: 'Bad Request', + statusCode: 400, + }, + }, + }, + }), + ApiResponse({ + status: 404, + description: '채팅 조회 실패.', + content: { + JSON: { + example: { + message: '해당 채팅룸이 없거나 채팅이 존재하지 않습니다.', + error: 'Not Found', + statusCode: 404, + }, + }, + }, + }), + ); +} diff --git a/src/chat/swagger-decorators/get-one-chat-room.decorator.ts b/src/chat/swagger-decorators/get-one-chat-room.decorator.ts new file mode 100644 index 0000000..b409b9c --- /dev/null +++ b/src/chat/swagger-decorators/get-one-chat-room.decorator.ts @@ -0,0 +1,54 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; + +export function ApiGetOneChatRoom() { + return applyDecorators( + ApiOperation({ + summary: '채팅룸 단일 조회', + description: 'Header - user-token, Param - board-id', + }), + ApiResponse({ + status: 200, + description: '성공적으로 채팅방 (단일)조회', + content: { + JSON: { + example: { + _id: '650bde3798dd4c34439c30dc', + host_id: 123, + guest_id: 1234, + deleted_at: null, + createdAt: '2023-09-21T06:09:59.724Z', + updatedAt: '2023-09-21T06:09:59.724Z', + __v: 0, + }, + }, + }, + }), + ApiResponse({ + status: 400, + description: '유효성 검사 실패', + content: { + JSON: { + example: { + message: '올바른 ObjectId 형식이 아닙니다.', + error: 'Bad Request', + statusCode: 400, + }, + }, + }, + }), + ApiResponse({ + status: 404, + description: '채팅룸 조회 실패.', + content: { + JSON: { + example: { + message: '해당 유저가 속한 채팅방이 없습니다.', + error: 'Not Found', + statusCode: 404, + }, + }, + }, + }), + ); +} From 5a9469fc5bf43023d4d879e9094781b798fb1a3b Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 17:40:17 +0900 Subject: [PATCH 18/24] =?UTF-8?q?refactor(#60):=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/services/chat.service.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 2a2bb00..b674ba6 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -207,9 +207,6 @@ export class ChatService { receiver: returnedChat.receiver, }; - const socketRoomId = returnedChat.chatroom_id.toString(); - // this.eventsGateway.server.to(`ch-${socketRoomId}`).emit('message', chat); - return chat; } } From b90d461a2aa9a10c607c06471698e030f0b1844c Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sat, 21 Oct 2023 18:08:44 +0900 Subject: [PATCH 19/24] =?UTF-8?q?modify(#60):=20synchronize:=20true?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 +- src/config/typeorm.config.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index 1eed4ff..cc72c01 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -25,7 +25,7 @@ import { TokenRepository } from './auth/repositories/token.repository'; UserModule, TypeOrmModule.forRoot({ ...TypeORMconfig, // TypeORM 설정 객체 확장 - synchronize: false, // DB 동기화 여부 설정 + synchronize: true, // DB 동기화 여부 설정 }), // TypeOrmModule.forFeature([Image]), ConfigModule.forRoot({ diff --git a/src/config/typeorm.config.ts b/src/config/typeorm.config.ts index 13336a4..d39206e 100644 --- a/src/config/typeorm.config.ts +++ b/src/config/typeorm.config.ts @@ -40,5 +40,5 @@ export const TypeORMconfig: TypeOrmModuleOptions = { CommentNotification, // BoardRepository, ], // 여기에 엔티티들을 추가해야 합니다. - synchronize: process.env.NODE_ENV === 'false', + synchronize: process.env.NODE_ENV === 'true', }; From af48d2d54d23693b10aad2097b2b1c20465e3f74 Mon Sep 17 00:00:00 2001 From: hobiJeong <137868493+hobiJeong@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:31:32 +0900 Subject: [PATCH 20/24] Update post-chat.dto.ts Co-authored-by: Lee seok ho --- src/chat/dto/post-chat.dto.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/chat/dto/post-chat.dto.ts b/src/chat/dto/post-chat.dto.ts index 5a9a05e..d4464f7 100644 --- a/src/chat/dto/post-chat.dto.ts +++ b/src/chat/dto/post-chat.dto.ts @@ -22,7 +22,14 @@ export class PostChatDto { description: '채팅 내용', }) @IsString() + @ApiPropertyOptional({ + example: '안녕하세요', + description: '채팅 내용', + }) + @IsString() + @IsNotEmpty() @IsOptional() + content?: string; content: string; @ApiProperty({ From eb287fb9d9a47dc4c00a1c24d33b50ca6b278666 Mon Sep 17 00:00:00 2001 From: hobiJeong <137868493+hobiJeong@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:32:28 +0900 Subject: [PATCH 21/24] Update post-chat.dto.ts Co-authored-by: Lee seok ho --- src/chat/dto/post-chat.dto.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/chat/dto/post-chat.dto.ts b/src/chat/dto/post-chat.dto.ts index d4464f7..f0b8bab 100644 --- a/src/chat/dto/post-chat.dto.ts +++ b/src/chat/dto/post-chat.dto.ts @@ -37,7 +37,6 @@ export class PostChatDto { description: '채팅을 보내는 유저 아이디', }) @IsNumber() - @IsNotEmpty() senderId: number; @ApiProperty({ From 3e04b19ecc9ff2c656383d461831ab677fe4d91e Mon Sep 17 00:00:00 2001 From: hobiJeong <137868493+hobiJeong@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:35:56 +0900 Subject: [PATCH 22/24] Update chat.service.ts Co-authored-by: Lee seok ho --- src/chat/services/chat.service.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index b674ba6..39906cd 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -30,18 +30,16 @@ export class ChatService { ) {} notificationListener() { - try { - return this.subject - .asObservable() - .pipe( - map((notification: Notification) => JSON.stringify(notification)), - ); - } catch (error) { - this.logger.error('notificationListener : ' + error.message); - throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); - } - } - + return this.subject + .asObservable() + .pipe( + map((notification: Notification) => JSON.stringify(notification)), + ) + .catchError((err) => { + this.logger.error('notificationListener : ' + error.message); + throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); + }) +} async getChatRooms(myId: number) { const chatRoom = await this.chatRepository.getChatRooms(myId); From ab19c270c6a2add7f270c1ba142a315d7bce77d9 Mon Sep 17 00:00:00 2001 From: hobiJeong <137868493+hobiJeong@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:37:14 +0900 Subject: [PATCH 23/24] Update chat.service.ts Co-authored-by: Lee seok ho --- src/chat/services/chat.service.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 39906cd..0dd75d9 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -157,9 +157,6 @@ export class ChatService { receiver: returnedChat.receiver, }) .save() - .catch((error) => { - throw new Error(error); - }); // send notification if (notification) this.subject.next(notification); From 3e53c29e9087f4c29d9b96a15cd71b55c02cf138 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 22 Oct 2023 21:10:57 +0900 Subject: [PATCH 24/24] =?UTF-8?q?refactor(#60):=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EB=82=B4=EC=9A=A9=20=EB=B0=98=EC=98=81=20=EB=B0=8F?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/dto/post-chat.dto.ts | 7 +++--- src/chat/schemas/chat-image.schemas.ts | 1 - src/chat/schemas/chat-notifiation.schemas.ts | 8 ++----- src/chat/schemas/chat-room.schemas.ts | 3 +++ src/chat/schemas/chat.schemas.ts | 6 +---- src/chat/services/chat.service.ts | 25 ++++++++++---------- 6 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/chat/dto/post-chat.dto.ts b/src/chat/dto/post-chat.dto.ts index f0b8bab..57f98ea 100644 --- a/src/chat/dto/post-chat.dto.ts +++ b/src/chat/dto/post-chat.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsMongoId, IsNotEmpty, @@ -22,7 +22,7 @@ export class PostChatDto { description: '채팅 내용', }) @IsString() - @ApiPropertyOptional({ + @ApiPropertyOptional({ example: '안녕하세요', description: '채팅 내용', }) @@ -30,7 +30,6 @@ export class PostChatDto { @IsNotEmpty() @IsOptional() content?: string; - content: string; @ApiProperty({ example: '1', @@ -52,5 +51,5 @@ export class PostChatDto { description: 'FormData. 이미지 파일', }) @IsOptional() - imageUrl: FormData; + imageUrl?: FormData; } diff --git a/src/chat/schemas/chat-image.schemas.ts b/src/chat/schemas/chat-image.schemas.ts index a010144..5f7f923 100644 --- a/src/chat/schemas/chat-image.schemas.ts +++ b/src/chat/schemas/chat-image.schemas.ts @@ -16,7 +16,6 @@ export class ChatImage { chat_id: mongoose.Types.ObjectId; @IsString() - @IsNotEmpty() @Prop({ required: true }) image_url: string; } diff --git a/src/chat/schemas/chat-notifiation.schemas.ts b/src/chat/schemas/chat-notifiation.schemas.ts index 354b295..c70181b 100644 --- a/src/chat/schemas/chat-notifiation.schemas.ts +++ b/src/chat/schemas/chat-notifiation.schemas.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose'; import * as mongoose from 'mongoose'; import { Chat } from './chat.schemas'; -import { IsBoolean, IsMongoId, IsNotEmpty, IsNumber } from 'class-validator'; +import { IsBoolean, IsMongoId, IsNumber } from 'class-validator'; const options: SchemaOptions = { collection: 'ChatNotification', @@ -11,25 +11,21 @@ const options: SchemaOptions = { @Schema(options) export class ChatNotification { @IsMongoId() - @IsNotEmpty() @Prop({ type: mongoose.Types.ObjectId, ref: Chat.name }) chat_id: mongoose.Types.ObjectId; @IsNumber() - @IsNotEmpty() @Prop({ required: true }) sender: number; @IsNumber() - @IsNotEmpty() @Prop({ required: true }) receiver: number; @IsBoolean() - @IsNotEmpty() @Prop({ required: true, default: false }) isSeen: boolean; } export const ChatNotificationSchema = - SchemaFactory.createForClass(ChatNotification); \ No newline at end of file + SchemaFactory.createForClass(ChatNotification); diff --git a/src/chat/schemas/chat-room.schemas.ts b/src/chat/schemas/chat-room.schemas.ts index e2b569b..fb1c2de 100644 --- a/src/chat/schemas/chat-room.schemas.ts +++ b/src/chat/schemas/chat-room.schemas.ts @@ -1,4 +1,5 @@ import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose'; +import { IsNumber } from 'class-validator'; const options: SchemaOptions = { collection: 'ChatRoom', @@ -7,9 +8,11 @@ const options: SchemaOptions = { @Schema(options) export class ChatRoom { + @IsNumber() @Prop({ required: true }) host_id: number; + @IsNumber() @Prop({ required: true }) guest_id: number; diff --git a/src/chat/schemas/chat.schemas.ts b/src/chat/schemas/chat.schemas.ts index 3fef581..fd3c263 100644 --- a/src/chat/schemas/chat.schemas.ts +++ b/src/chat/schemas/chat.schemas.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose'; import * as mongoose from 'mongoose'; import { ChatRoom } from './chat-room.schemas'; -import { IsMongoId, IsNotEmpty, IsNumber, IsString } from 'class-validator'; +import { IsMongoId, IsNumber, IsString } from 'class-validator'; const options: SchemaOptions = { collection: 'Chat', @@ -11,22 +11,18 @@ const options: SchemaOptions = { @Schema(options) export class Chat { @IsMongoId() - @IsNotEmpty() @Prop({ type: mongoose.Types.ObjectId, ref: ChatRoom.name }) chatroom_id: mongoose.Types.ObjectId; @IsNumber() - @IsNotEmpty() @Prop({ required: true }) sender: number; @IsNumber() - @IsNotEmpty() @Prop({ required: true }) receiver: number; @IsString() - @IsNotEmpty() @Prop({ required: true }) content: string; } diff --git a/src/chat/services/chat.service.ts b/src/chat/services/chat.service.ts index 0dd75d9..94bf1c3 100644 --- a/src/chat/services/chat.service.ts +++ b/src/chat/services/chat.service.ts @@ -13,7 +13,7 @@ import * as mongoose from 'mongoose'; import { S3Service } from 'src/common/s3/s3.service'; import { NotificationService } from './notification.service'; import { ChatNotification } from '../schemas/chat-notifiation.schemas'; -import { Subject, map } from 'rxjs'; +import { Subject, catchError, map } from 'rxjs'; @Injectable() export class ChatService { @@ -30,16 +30,18 @@ export class ChatService { ) {} notificationListener() { - return this.subject - .asObservable() - .pipe( - map((notification: Notification) => JSON.stringify(notification)), - ) - .catchError((err) => { - this.logger.error('notificationListener : ' + error.message); - throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); + return ( + this.subject + .asObservable() + .pipe( + map((notification: Notification) => JSON.stringify(notification)), + ), + catchError((err) => { + this.logger.error('notificationListener : ' + err.message); + throw new HttpException(err.message, HttpStatus.INTERNAL_SERVER_ERROR); }) -} + ); + } async getChatRooms(myId: number) { const chatRoom = await this.chatRepository.getChatRooms(myId); @@ -155,8 +157,7 @@ export class ChatService { chat_id: returnedChat.id, sender: returnedChat.sender, receiver: returnedChat.receiver, - }) - .save() + }).save(); // send notification if (notification) this.subject.next(notification);