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

test: 미팅서비스 코드 및 dto 개선(#13)

parent 45c683c7
No related branches found
No related tags found
2 merge requests!31Develop,!23[#13] 스케쥴 서비스 코드 로직 대폭 수정 및 미팅서비스 테스트 완료
...@@ -3,14 +3,16 @@ const Joi = require('joi'); ...@@ -3,14 +3,16 @@ const Joi = require('joi');
class CreateMeetingRequestDTO { class CreateMeetingRequestDTO {
constructor({ title, description, time_idx_start, time_idx_end, location, time_idx_deadline, type, created_by }) { constructor({ title, description, time_idx_start, time_idx_end, location, time_idx_deadline, type, created_by }) {
this.title = title; this.data = {
this.description = description; title,
this.time_idx_start = time_idx_start; description,
this.time_idx_end = time_idx_end; time_idx_start,
this.location = location; time_idx_end,
this.time_idx_deadline = time_idx_deadline; location,
this.type = type; time_idx_deadline,
this.created_by = created_by; type,
created_by,
};
} }
validate() { validate() {
...@@ -22,13 +24,13 @@ class CreateMeetingRequestDTO { ...@@ -22,13 +24,13 @@ class CreateMeetingRequestDTO {
location: Joi.string().allow('', null).optional(), location: Joi.string().allow('', null).optional(),
time_idx_deadline: Joi.number().integer().min(0).less(Joi.ref('time_idx_start')).optional(), time_idx_deadline: Joi.number().integer().min(0).less(Joi.ref('time_idx_start')).optional(),
type: Joi.string().valid('OPEN', 'CLOSE').required(), type: Joi.string().valid('OPEN', 'CLOSE').required(),
created_by: Joi.number().integer().positive().required() created_by: Joi.number().integer().positive().required(),
}); });
const { error } = schema.validate(this, { abortEarly: false }); const { error } = schema.validate(this.data, { abortEarly: false });
if (error) { if (error) {
const errorMessages = error.details.map(detail => detail.message).join(', '); const errorMessages = error.details.map((detail) => detail.message).join(', ');
throw new Error(`Validation error: ${errorMessages}`); throw new Error(`Validation error: ${errorMessages}`);
} }
......
...@@ -4,6 +4,7 @@ const { Op } = require('sequelize'); ...@@ -4,6 +4,7 @@ const { Op } = require('sequelize');
const sequelize = require('../config/sequelize'); // 트랜잭션 관리를 위해 sequelize 인스턴스 필요 const sequelize = require('../config/sequelize'); // 트랜잭션 관리를 위해 sequelize 인스턴스 필요
const { Meeting, MeetingParticipant, User, Schedule } = require('../models'); const { Meeting, MeetingParticipant, User, Schedule } = require('../models');
const ChatRooms = require('../models/ChatRooms'); const ChatRooms = require('../models/ChatRooms');
const MeetingResponseDTO = require('../dtos/MeetingResponseDTO'); const MeetingResponseDTO = require('../dtos/MeetingResponseDTO');
const MeetingDetailResponseDTO = require('../dtos/MeetingDetailResponseDTO'); const MeetingDetailResponseDTO = require('../dtos/MeetingDetailResponseDTO');
const CreateMeetingRequestDTO = require('../dtos/CreateMeetingRequestDTO'); const CreateMeetingRequestDTO = require('../dtos/CreateMeetingRequestDTO');
...@@ -36,7 +37,16 @@ class MeetingService { ...@@ -36,7 +37,16 @@ class MeetingService {
const createMeetingDTO = new CreateMeetingRequestDTO(meetingData); const createMeetingDTO = new CreateMeetingRequestDTO(meetingData);
createMeetingDTO.validate(); createMeetingDTO.validate();
const { title, description, time_idx_start, time_idx_end, location, time_idx_deadline, type, created_by } = meetingData; const {
title,
description,
time_idx_start,
time_idx_end,
location,
time_idx_deadline,
type,
created_by,
} = meetingData;
// 사용자 존재 여부 확인 // 사용자 존재 여부 확인
const user = await User.findOne({ where: { id: created_by } }); const user = await User.findOne({ where: { id: created_by } });
...@@ -54,13 +64,14 @@ class MeetingService { ...@@ -54,13 +64,14 @@ class MeetingService {
messages: [], messages: [],
lastReadAt: {}, lastReadAt: {},
lastReadLogId: {}, lastReadLogId: {},
isOnline: {} isOnline: {},
}; };
const chatRoom = new ChatRooms(chatRoomData); const chatRoom = new ChatRooms(chatRoomData);
await chatRoom.save(); await chatRoom.save();
// 모임 생성 // 모임 생성
const newMeeting = await Meeting.create({ const newMeeting = await Meeting.create(
{
title, title,
description, description,
time_idx_start, time_idx_start,
...@@ -70,24 +81,34 @@ class MeetingService { ...@@ -70,24 +81,34 @@ class MeetingService {
type, type,
created_by, created_by,
chatRoomId, chatRoomId,
}, { transaction }); },
{ transaction }
);
// 모임 참가자 추가 (생성자 자신) // 모임 참가자 추가 (생성자 자신)
await MeetingParticipant.create({ await MeetingParticipant.create(
{
meeting_id: newMeeting.id, meeting_id: newMeeting.id,
user_id: created_by, user_id: created_by,
}, { transaction }); },
{ transaction }
);
// 스케줄 생성 // 스케줄 생성 (모임 시간 범위 내 모든 time_idx에 대해 생성)
await ScheduleService.createSchedules({ const events = [];
for (let idx = time_idx_start; idx <= time_idx_end; idx++) {
events.push({ time_idx: idx });
}
await ScheduleService.createSchedules(
{
userId: created_by, userId: created_by,
title: `번개 모임: ${title}`, title: `번개 모임: ${title}`,
is_fixed: true, is_fixed: false,
events: [ events: events,
{ time_idx: time_idx_start }, },
{ time_idx: time_idx_end }, transaction
], );
}, transaction);
return { meeting_id: newMeeting.id, chatRoomId }; return { meeting_id: newMeeting.id, chatRoomId };
}); });
...@@ -102,7 +123,16 @@ class MeetingService { ...@@ -102,7 +123,16 @@ class MeetingService {
*/ */
async getMeetings(userId) { async getMeetings(userId) {
const meetings = await Meeting.findAll({ const meetings = await Meeting.findAll({
attributes: ['id', 'title', 'description', 'time_idx_start', 'time_idx_end', 'location', 'time_idx_deadline', 'type'], attributes: [
'id',
'title',
'description',
'time_idx_start',
'time_idx_end',
'location',
'time_idx_deadline',
'type',
],
include: [ include: [
{ {
model: User, model: User,
...@@ -119,14 +149,11 @@ class MeetingService { ...@@ -119,14 +149,11 @@ class MeetingService {
return meetings.map((meeting) => { return meetings.map((meeting) => {
const creatorName = meeting.creator ? meeting.creator.name : 'Unknown'; const creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
const isParticipant = meeting.participants.some(participant => participant.user_id === parseInt(userId, 10)); const isParticipant = meeting.participants.some(
(participant) => participant.user_id === parseInt(userId, 10)
return new MeetingResponseDTO(
meeting,
isParticipant,
false,
creatorName
); );
return new MeetingResponseDTO(meeting, isParticipant, false, creatorName);
}); });
} }
...@@ -168,13 +195,13 @@ class MeetingService { ...@@ -168,13 +195,13 @@ class MeetingService {
if (meeting.time_idx_deadline !== undefined) { if (meeting.time_idx_deadline !== undefined) {
const currentTimeIdx = this.getCurrentTimeIdx(); // 현재 시간 인덱스 const currentTimeIdx = this.getCurrentTimeIdx(); // 현재 시간 인덱스
if (currentTimeIdx > meeting.time_idx_deadline) { if (currentTimeIdx >= meeting.time_idx_deadline) {
throw new Error('참가 신청이 마감되었습니다.'); throw new Error('참가 신청이 마감되었습니다.');
} }
} }
const existingParticipant = await MeetingParticipant.findOne({ const existingParticipant = await MeetingParticipant.findOne({
where: { meeting_id: meetingId, user_id: userId } where: { meeting_id: meetingId, user_id: userId },
}); });
if (existingParticipant) { if (existingParticipant) {
...@@ -183,9 +210,6 @@ class MeetingService { ...@@ -183,9 +210,6 @@ class MeetingService {
// 트랜잭션을 사용하여 참가자 추가 및 스케줄 업데이트를 원자적으로 처리 // 트랜잭션을 사용하여 참가자 추가 및 스케줄 업데이트를 원자적으로 처리
await sequelize.transaction(async (transaction) => { await sequelize.transaction(async (transaction) => {
// 참가자 추가
await MeetingParticipant.create({ meeting_id: meetingId, user_id: userId }, { transaction });
// 스케줄 충돌 확인 // 스케줄 충돌 확인
const hasConflict = await ScheduleService.checkScheduleOverlapByTime( const hasConflict = await ScheduleService.checkScheduleOverlapByTime(
userId, userId,
...@@ -197,16 +221,27 @@ class MeetingService { ...@@ -197,16 +221,27 @@ class MeetingService {
throw new Error('스케줄이 겹칩니다. 다른 모임에 참가하세요.'); throw new Error('스케줄이 겹칩니다. 다른 모임에 참가하세요.');
} }
// 스케줄 추가 // 참가자 추가
await ScheduleService.createSchedules({ await MeetingParticipant.create(
{ meeting_id: meetingId, user_id: userId },
{ transaction }
);
// 스케줄 생성 (모임 시간 범위 내 모든 time_idx에 대해 생성)
const events = [];
for (let idx = meeting.time_idx_start; idx <= meeting.time_idx_end; idx++) {
events.push({ time_idx: idx });
}
await ScheduleService.createSchedules(
{
userId: userId, userId: userId,
title: `번개 모임: ${meeting.title}`, title: `번개 모임: ${meeting.title}`,
is_fixed: true, is_fixed: true,
events: [ events: events,
{ time_idx: meeting.time_idx_start }, },
{ time_idx: meeting.time_idx_end }, transaction
], );
}, transaction);
// 채팅방 참가 (MongoDB) // 채팅방 참가 (MongoDB)
const user = await User.findOne({ where: { id: userId }, transaction }); const user = await User.findOne({ where: { id: userId }, transaction });
...@@ -233,7 +268,7 @@ class MeetingService { ...@@ -233,7 +268,7 @@ class MeetingService {
{ {
model: User, model: User,
as: 'creator', as: 'creator',
attributes: ['name'] attributes: ['name'],
}, },
{ {
model: MeetingParticipant, model: MeetingParticipant,
...@@ -242,11 +277,11 @@ class MeetingService { ...@@ -242,11 +277,11 @@ class MeetingService {
{ {
model: User, model: User,
as: 'participantUser', as: 'participantUser',
attributes: ['name', 'email'] attributes: ['name', 'email'],
} },
] ],
} },
] ],
}); });
if (!meeting) { if (!meeting) {
......
This diff is collapsed.
...@@ -136,20 +136,9 @@ class ScheduleService { ...@@ -136,20 +136,9 @@ class ScheduleService {
const overlappingSchedule = await Schedule.findOne({ const overlappingSchedule = await Schedule.findOne({
where: { where: {
user_id: userId, user_id: userId,
[Op.or]: [ time_idx: {
{ [Op.between]: [time_idx_start, time_idx_end]
time_idx_start: { [Op.between]: [time_idx_start, time_idx_end] }
},
{
time_idx_end: { [Op.between]: [time_idx_start, time_idx_end] }
},
{
[Op.and]: [
{ time_idx_start: { [Op.lte]: time_idx_start } },
{ time_idx_end: { [Op.gte]: time_idx_end } }
]
} }
]
}, },
transaction, transaction,
}); });
...@@ -157,6 +146,7 @@ class ScheduleService { ...@@ -157,6 +146,7 @@ class ScheduleService {
return !!overlappingSchedule; return !!overlappingSchedule;
} }
/** /**
* 만료된 스케줄 삭제 * 만료된 스케줄 삭제
*/ */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment