Select Git revision
schedule.test.js
eventController.js 9.02 KiB
const Event = require('../models/Event');
const EventParticipants = require('../models/EventParticipants');
const {Op} = require('sequelize');
const moment = require('moment'); // 날짜 포맷팅 라이브러리
const UserEvent = require('../models/UserEvent.js');
const {redisClient, capCheckLuaScript} = require("../datastore/redis");
const UserCrew = require("../models/UserCrew");
// 한 페이지당 기본 아이템 수
const itemsPerPage = 10;
const countKeyPattern = 'event:${eventID}:participant_count';
// 이벤트 목록 조회 (단일 엔드포인트)
exports.getEvents = async (req, res) => {
console.log('이벤트 목록 조회 컨트롤러 실행'); // 로그 확인용
try {
const {sportTypeId, regionID, eventDate, page = 1} = req.query; // 쿼리 파라미터 가져오기
const offset = (page - 1) * itemsPerPage; // 시작 지점 계산
const where = {};
// 쿼리 파라미터 조건 추가
if (sportTypeId) where.sportTypeId = sportTypeId;
if (regionID) where.regionID = regionID;
if (eventDate) where.eventDate = eventDate;
// 이벤트 데이터 가져오기
const {rows: events, count: total} = await Event.findAndCountAll({
where,
limit: itemsPerPage,
offset,
});
// 응답 데이터 반환
res.status(200).json({
events,
total, // 조건에 맞는 총 이벤트 개수
itemsPerPage, // 페이지당 이벤트 수
});
} catch (error) {
console.error('이벤트 목록 조회 중 오류:', error);
res.status(500).json({error: '이벤트 목록 조회 중 오류가 발생했습니다.'});
}
};
// 이벤트 생성 컨트롤러
exports.createEvent = async (req, res) => {
try {
const {
crewID,
regionID,
name,
sportTypeId,
eventDate,
capacity,
feeCondition,
} = req.body;
const userID = req.user.userID;
// TODO: 클라이언트에게 누락된 필드 정보를 명시적으로 전달하지 못하는 패턴입니다.
// 추후 리팩터링 시 누락된 필드를 클라이언트에 명확히 알려주는 로직으로 개선할 필요가 있습니다.
if (!regionID || !sportTypeId) {
return res.status(400).json({error: '필수 필드가 누락되었습니다.'});
}
const newEvent = await Event.create({
crewID,
regionID,
name,
sportTypeId,
eventDate,
capacity,
feeCondition,
userID,
});
res.status(201).json(newEvent);
} catch (error) {
console.error('이벤트 생성 중 오류:', error);
res.status(500).json({error: '이벤트 생성 중 오류가 발생했습니다.'});
}
};
// 특정 이벤트 조회 컨트롤러
exports.getEventById = async (req, res) => {
try {
const {eventID} = req.params;
// 이벤트 정보 조회
const event = await Event.findByPk(eventID, {
attributes: [
'eventID',
'regionID',
'name',
'sportTypeId',
'eventDate',
'capacity',
'feeCondition',
'userID',
'createdDate',
],
});
if (!event) {
return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
}
// 현재 참여한 인원 수 계산
const currentMemberCount = redisClient.get(countKeyPattern).then((result) => {
return parseInt(result, 10);
}).catch((error) => {
console.error('이벤트 참여자 수 조회중 오류', error);
return UserEvent.count({
where: {eventID: event.eventID},
});
});
// 이벤트 데이터에 현재 참여한 인원 수 추가
const response = {
...event.toJSON(),
currentMemberCount, // 현재 참여한 인원 수
};
res.status(200).json(response);
} catch (error) {
console.error('이벤트 조회 중 오류:', error);
res.status(500).json({error: '이벤트 조회 중 오류가 발생했습니다.'});
}
};
// 이벤트 수정 컨트롤러
exports.updateEvent = async (req, res) => {
try {
const {eventID} = req.params;
const updateData = req.body;
const userID = req.user.userID;
const event = await Event.findByPk(eventID);
if (!event) {
return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
}
if (event.userID !== userID) {
return res.status(403).json({error: '이벤트 수정 권한이 없습니다.'});
}
await event.update(updateData);
res.status(200).json({updatedEvent: event});
} catch (error) {
console.error('이벤트 수정 중 오류:', error);
res.status(500).json({error: '이벤트 수정 중 오류가 발생했습니다.'});
}
};
// 이벤트 삭제 컨트롤러
exports.deleteEvent = async (req, res) => {
try {
const {eventID} = req.params;
const userID = req.user.userID;
const event = await Event.findByPk(eventID);
if (!event) {
return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
}
if (event.userID !== userID) {
return res.status(403).json({error: '이벤트 삭제 권한이 없습니다.'});
}
await event.destroy();
res.status(200).json({message: '이벤트가 성공적으로 삭제되었습니다.'});
} catch (error) {
console.error('이벤트 삭제 중 오류:', error);
res.status(500).json({error: '이벤트 삭제 중 오류가 발생했습니다.'});
}
};
// 이벤트 참여 컨트롤러
exports.participateEvent = async (req, res) => {
const {eventID} = req.params;
const userID = req.user.userID;
if (!eventID || !userID) {
return res.status(400).json({error: '필수 데이터가 누락되었습니다.'});
}
const event = await Event.findByPk(eventID);
if (!event) {
return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
}
const existingParticipant = await EventParticipants.findOne({where: {eventID, userID}});
if (existingParticipant) {
return res.status(409).json({error: '이미 이벤트에 참여 중입니다.'});
}
const capacity = parseInt(event.capacity, 10);
try {
const result = await redisClient.sendCommand([
'EVAL',
capCheckLuaScript,
'1',
countKeyPattern,
capacity.toString()
]);
// 인원이 초과하지 않은 경우, 참여 진행.
if (result === 1) {
const newParticipant = await EventParticipants.create({
userID,
eventID,
participationDate: new Date(),
status: 'attending',
});
res.status(201).json(newParticipant);
} else {
return res.status(409).json({error: '이벤트의 최대 참여 인원 수를 초과했습니다.'});
}
} catch (error) {
// 참여 실패시 가입 카운트를 감소시킴.
await redisClient.decr(countKeyPattern);
console.error('이벤트 참여 중 오류:', error);
res.status(500).json({error: '이벤트 참여 중 오류가 발생했습니다.'});
}
};
// 이벤트 참여 취소 컨트롤러
exports.cancelParticipation = async (req, res) => {
try {
const {eventID} = req.params; // URL에서 eventID 가져오기
const userID = req.user.userID;
// 필수 데이터 검증
if (!eventID || !userID) {
return res.status(400).json({error: '필수 데이터가 누락되었습니다.'});
}
// 이벤트 존재 여부 확인
const event = await Event.findByPk(eventID);
if (!event) {
return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
}
// 참여 기록 확인
const participant = await EventParticipants.findOne({where: {eventID, userID}});
if (!participant) {
return res.status(404).json({error: '참여 기록이 존재하지 않습니다.'});
}
// 상태 변경 (참여 취소)
participant.status = 'canceled';
await participant.save();
// 참여 인원 카운트 감소
await redisClient.decr(countKeyPattern);
res.status(200).json({
message: '이벤트 참여가 성공적으로 취소되었습니다.',
participant,
});
} catch (error) {
console.error('이벤트 참여 취소 중 오류:', error);
res.status(500).json({error: '이벤트 참여 취소 중 오류가 발생했습니다.'});
}
};