Skip to content
Snippets Groups Projects
Commit 12de45f3 authored by tpgus2603's avatar tpgus2603
Browse files

bugfix: chatroom 관련 오류해결(#21)

parent 74962fc2
No related branches found
No related tags found
2 merge requests!31Develop,!28[#21] bugfix: chatroom 관련 오류해결
const mongoose = require('mongoose');
// MongoDB 채팅방 스키마 수정 (FCM 토큰을 배열로 관리)
const chatRoomsSchema = new mongoose.Schema({
chatRoomId: { type: String, required: true, unique: true },
chatRoomName: { type: String, required: true },
messages: [{
sender: String,
message: String,
timestamp: Date,
type: { type: String, default: 'message' }, // 기본값은 'message', 다른 값으로 'join', 'leave' 가능
}],
participants: [{
name: { type: String, required: true },
fcmTokens: { type: [String], default: [] }, // FCM 토큰 배열
}],
lastReadAt: { type: Map, of: Date },
lastReadLogId: { type: Map, of: String },
isOnline: { type: Map, of: Boolean },
}, { collection: 'chatrooms' });
const ChatRoom = mongoose.model('ChatRooms', chatRoomsSchema);
module.exports = ChatRoom;
\ No newline at end of file
......@@ -7,7 +7,7 @@ const Meeting = require('./Meeting');
const Friend = require('./Friend');
const FcmToken = require('./fcmToken');
const MeetingParticipant = require('./MeetingParticipant');
const ChatRooms = require('./ChatRooms');
// const ChatRooms = require('./ChatRooms');
// 관계 설정
Friend.belongsTo(User, { foreignKey: 'requester_id', as: 'requester' }); // 친구 요청을 보낸 사용자
......@@ -35,12 +35,6 @@ module.exports = {
Schedule,
Meeting,
MeetingParticipant,
ChatRooms,
sequelize,
User,
Schedule,
Meeting,
MeetingParticipant,
Friend,
FcmToken,
};
......@@ -11447,7 +11447,7 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz",
"integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==",
"dev": true,
"devOptional": true,
"funding": [
{
"type": "github",
......@@ -11986,6 +11986,7 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
"integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"peer": true,
......@@ -12001,6 +12002,7 @@
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
"integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"peer": true,
......@@ -13270,7 +13272,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
......@@ -17498,7 +17499,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
......@@ -20299,7 +20300,7 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/stubs": {
......@@ -21140,7 +21141,6 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD"
},
"node_modules/tsutils": {
......@@ -22140,7 +22140,7 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10"
......
......@@ -20,7 +20,7 @@ router.get('/all', ScheduleController.getAllSchedules);
* 개별 스케줄 조회
* Get /api/schedule/:id
*/
router.get('/:id', ScheduleController.getScheduleById);
router.get('/:id', ScheduleController.getScheduleByTimeIdx);
/**
* 스케줄 생성
......@@ -32,13 +32,13 @@ router.post('/', ScheduleController.createSchedule);
* 스케줄 수정
* PUT /api/schedule/:id
*/
router.put('/:id', ScheduleController.updateSchedule);
router.put('/:id', ScheduleController.updateSchedules);
/**
* 스케줄 삭제
* DELETE /api/schedule/:id
*/
router.delete('/:id', ScheduleController.deleteSchedule);
router.delete('/:id', ScheduleController.deleteSchedules);
module.exports = router;
\ No newline at end of file
// schemas/ChatRoom.js
const mongoose = require('mongoose');
const ChatRoomSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
meeting_id: {
type: Number, // SQL의 Meetings 테이블 ID 참조
default: null,
},
type: {
type: String,
enum: ['OPEN', 'CLOSE'],
required: true,
},
created_by: {
type: Number, // SQL의 Users 테이블 ID 참조
required: true,
},
}, {
timestamps: true, // createdAt, updatedAt 자동 관리
});
// MongoDB 채팅방 스키마 수정 (FCM 토큰을 배열로 관리)
const chatRoomsSchema = new mongoose.Schema({
chatRoomId: { type: String, required: true, unique: true },
chatRoomName: { type: String, required: true },
messages: [{
sender: String,
message: String,
timestamp: Date,
type: { type: String, default: 'message' }, // 기본값은 'message', 다른 값으로 'join', 'leave' 가능
}],
participants: [{
name: { type: String, required: true },
fcmTokens: { type: [String], default: [] }, // FCM 토큰 배열
}],
lastReadAt: { type: Map, of: Date },
lastReadLogId: { type: Map, of: String },
isOnline: { type: Map, of: Boolean },
}, { collection: 'chatrooms' });
module.exports = mongoose.model('ChatRoom', ChatRoomSchema);
const ChatRooms = mongoose.model('ChatRooms', chatRoomsSchema);
module.exports = ChatRooms;
\ No newline at end of file
const ChatRoom = require('../models/ChatRooms');
const ChatRooms = require('../schemas/ChatRooms');
const { v4: uuidv4 } = require('uuid');
class ChatService {
......@@ -6,7 +6,7 @@ class ChatService {
async createChatRoom({ meeting_id, participants, chatRoomName }) {
try {
const chatRoomId = uuidv4();
const newRoom = new ChatRoom({
const newRoom = new ChatRooms({
chatRoomId,
chatRoomName,
meeting_id,
......@@ -31,7 +31,7 @@ class ChatService {
// 채팅방 목록 조회
async getChatRooms() {
const rooms = await ChatRoom.find({}, { chatRoomId: 1, chatRoomName: 1, messages: { $slice: -1 } });
const rooms = await ChatRooms.find({}, { chatRoomId: 1, chatRoomName: 1, messages: { $slice: -1 } });
return rooms.map(room => {
const lastMessage = room.messages[0] || {};
return {
......@@ -48,7 +48,7 @@ class ChatService {
// 사용자 상태 업데이트
async updateStatus(chatRoomId, nickname, isOnline) {
await ChatRoom.updateOne(
await ChatRooms.updateOne(
{ chatRoomId, "participants.name": nickname },
{ $set: { [`isOnline.${nickname}`]: isOnline } }
);
......@@ -57,7 +57,7 @@ class ChatService {
// 읽음 상태 업데이트
async updateReadStatus(chatRoomId, nickname) {
const now = new Date();
await ChatRoom.updateOne(
await ChatRooms.updateOne(
{ chatRoomId, "participants.name": nickname },
{ $set: { [`lastReadAt.${nickname}`]: now } }
);
......@@ -65,14 +65,14 @@ class ChatService {
// 읽지 않은 메시지 조회
async getUnreadMessages(nickname) {
const chatRooms = await ChatRoom.find({ "participants.name": nickname });
return await Promise.all(chatRooms.map(async (chatRoom) => {
const lastReadAt = chatRoom.lastReadAt.get(nickname) || new Date(0);
const unreadMessagesCount = chatRoom.messages.filter(message =>
const chatRooms = await ChatRooms.find({ "participants.name": nickname });
return await Promise.all(chatRooms.map(async (chatRooms) => {
const lastReadAt = chatRooms.lastReadAt.get(nickname) || new Date(0);
const unreadMessagesCount = chatRooms.messages.filter(message =>
message.timestamp > lastReadAt
).length;
return {
chatRoomId: chatRoom.chatRoomId,
chatRoomId: chatRooms.chatRoomId,
unreadCount: unreadMessagesCount,
};
}));
......@@ -80,14 +80,14 @@ class ChatService {
// 읽지 않은 메시지 수 조회
async getUnreadCount(chatRoomId) {
const chatRoom = await ChatRoom.findOne({ chatRoomId });
if (!chatRoom) {
const chatRooms = await ChatRooms.findOne({ chatRoomId });
if (!chatRooms) {
throw new Error('Chat room not found');
}
const unreadCounts = chatRoom.participants
.filter(participant => chatRoom.lastReadLogId.has(participant.name)) // Map에 존재하는 키만 처리
.map(participant => chatRoom.lastReadLogId.get(participant.name)) // lastReadLogId 값 추출
const unreadCounts = chatRooms.participants
.filter(participant => chatRooms.lastReadLogId.has(participant.name)) // Map에 존재하는 키만 처리
.map(participant => chatRooms.lastReadLogId.get(participant.name)) // lastReadLogId 값 추출
.reduce((acc, logId) => {
acc[logId] = (acc[logId] || 0) + 1; // logId 기준으로 등장 횟수 누적
return acc;
......@@ -107,7 +107,7 @@ class ChatService {
// 읽은 메시지 로그 ID 업데이트
async updateReadLogId(chatRoomId, nickname, logId) {
await ChatRoom.updateOne(
await ChatRooms.updateOne(
{ chatRoomId, "participants.name": nickname },
{ $set: { [`lastReadLogId.${nickname}`]: logId } }
);
......@@ -115,16 +115,16 @@ class ChatService {
// FCM 토큰 업데이트
async updateFcmToken(chatRoomId, nickname, fcmToken) {
const chatRoom = await ChatRoom.findOne({ chatRoomId, "participants.name": nickname });
if (!chatRoom) {
const chatRooms = await ChatRooms.findOne({ chatRoomId, "participants.name": nickname });
if (!chatRooms) {
throw new Error('Chat room or participant not found');
}
const participant = chatRoom.participants.find(p => p.name === nickname);
const participant = chatRooms.participants.find(p => p.name === nickname);
if (participant) {
if (!participant.fcmTokens.includes(fcmToken)) {
participant.fcmTokens.push(fcmToken);
await chatRoom.save();
await chatRooms.save();
}
}
}
......@@ -134,13 +134,13 @@ class ChatService {
let finalLogId = logId;
if (!isOnline && logId === null) {
const chatRoom = await ChatRoom.findOne({ chatRoomId });
if (chatRoom && chatRoom.messages.length > 0) {
finalLogId = chatRoom.messages[chatRoom.messages.length - 1]._id;
const chatRooms = await ChatRooms.findOne({ chatRoomId });
if (chatRooms && chatRooms.messages.length > 0) {
finalLogId = chatRooms.messages[chatRooms.messages.length - 1]._id;
}
}
await ChatRoom.updateOne(
await ChatRooms.updateOne(
{ chatRoomId, "participants.name": nickname },
{
$set: {
......@@ -155,8 +155,8 @@ class ChatService {
async sendMessage(chatRoomId, sender, messageContent) {
try {
// 채팅방 조회
const chatRoom = await ChatRoom.findOne({ chatRoomId });
if (!chatRoom) {
const chatRooms = await ChatRooms.findOne({ chatRoomId });
if (!chatRooms) {
throw new Error('Chat room not found');
}
......@@ -167,12 +167,12 @@ class ChatService {
timestamp: new Date(),
type: 'message',
};
chatRoom.messages.push(newMessage);
await chatRoom.save();
chatRooms.messages.push(newMessage);
await chatRooms.save();
// 오프라인 사용자 찾기
const offlineParticipants = chatRoom.participants.filter(
participant => !chatRoom.isOnline[participant.name]
const offlineParticipants = chatRooms.participants.filter(
participant => !chatRooms.isOnline[participant.name]
);
// 오프라인 사용자들에게 FCM 푸시 알림 전송
......@@ -181,7 +181,7 @@ class ChatService {
if (tokens.length > 0) {
const message = {
notification: {
title: `새 메시지: ${chatRoom.chatRoomName}`,
title: `새 메시지: ${chatRooms.chatRoomName}`,
body: `${sender}: ${messageContent}`,
},
tokens,
......
......@@ -7,7 +7,7 @@ const { v4: uuidv4 } = require('uuid');
const { Op } = require('sequelize');
const sequelize = require('../config/sequelize'); // 트랜잭션 관리를 위해 sequelize 인스턴스 필요
const { Meeting, MeetingParticipant, User, Schedule, Invite, Friend } = require('../models');
const ChatRooms = require('../models/ChatRooms');
const ChatRooms = require('../schemas/ChatRooms');
const MeetingResponseDTO = require('../dtos/MeetingResponseDTO');
const MeetingDetailResponseDTO = require('../dtos/MeetingDetailResponseDTO');
const CreateMeetingRequestDTO = require('../dtos/CreateMeetingRequestDTO');
......@@ -51,16 +51,6 @@ class MeetingService {
const user = await this._findUserWithFcmTokens(created_by);
const userFcmTokens = user.fcmTokenList.map((fcmToken) => fcmToken.token);
// 스케줄 충돌 확인
// const hasConflict = await ScheduleService.checkScheduleOverlap(
// created_by,
// new Date(start_time),
// new Date(end_time)
// );
// if (hasConflict) {
// throw new Error('스케줄이 겹칩니다. 다른 시간을 선택해주세요.');
// }
const hasConflict = await ScheduleService.checkScheduleOverlapByTime(
created_by,
......
const User = require('../models/User');
const FcmToken = require('../models/fcmToken');
const ChatRoom = require('../models/chatRooms');
const ChatRooms = require('../schemas/ChatRooms');
class MemberService {
async registerToken(email, fcmToken) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment