From a6e3101d1fb64425993fa49351a3863ee52b3bf7 Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Fri, 25 Nov 2022 21:37:33 +0900 Subject: [PATCH 01/17] Add: change searchByUserHandler --- src/service/rooms.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/service/rooms.js b/src/service/rooms.js index 31607acc..789ec54b 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -351,6 +351,31 @@ const searchByUserHandler = async (req, res) => { }) .lean(); + // ongoingRoom 중 이미 출발했고, 혼자 참여중인 방은 + // 정산 상태를 완료로 바꾸고 doneRoom으로 옮긴다. + const moving = user.ongoingRoom.filter( + (room) => room.part.length === 1 && room.time < req.timestamp + ); + moving.forEach(async function (room) { + room.part.settlementStatus = "paid"; + room.settlementTotal = 1; + room.isDeparted = true; + await room.save(); + + user.doneRoom.push(room._id); + + const movingRoomIndex = user.ongoingRoom.indexOf(room._id); + if (movingRoomIndex === -1) { + await user.save(); + return res.status(500).json({ + error: "Rooms/searchByUser/:id : internal server error", + }); + } + user.ongoingRoom.splice(movingRoomIndex); + + await user.save(); + }); + // 정산완료여부 기준으로 진행중인 방과 완료된 방을 분리해서 응답을 전송합니다. const response = {}; response.ongoing = user.ongoingRoom.map((room) => From 2762abadbec60118294f7acc5cb76c9a5c24534e Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Fri, 25 Nov 2022 23:51:31 +0900 Subject: [PATCH 02/17] Fix: searchByUserHandler --- src/route/rooms.js | 2 +- src/service/rooms.js | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/route/rooms.js b/src/route/rooms.js index ca3d3cf7..4406b90e 100644 --- a/src/route/rooms.js +++ b/src/route/rooms.js @@ -70,7 +70,7 @@ router.get( ); // 로그인된 사용자의 모든 방들을 반환한다. -router.get("/searchByUser", roomHandlers.searchByUserHandler); +router.get("/searchByUser", setTimestamp, roomHandlers.searchByUserHandler); router.post( "/commitPayment", diff --git a/src/service/rooms.js b/src/service/rooms.js index 789ec54b..ca3e7953 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -354,13 +354,28 @@ const searchByUserHandler = async (req, res) => { // ongoingRoom 중 이미 출발했고, 혼자 참여중인 방은 // 정산 상태를 완료로 바꾸고 doneRoom으로 옮긴다. const moving = user.ongoingRoom.filter( - (room) => room.part.length === 1 && room.time < req.timestamp + (room) => room.part.length == 1 && room.time <= req.timestamp ); + moving.forEach(async function (room) { - room.part.settlementStatus = "paid"; - room.settlementTotal = 1; - room.isDeparted = true; - await room.save(); + let changingRoomObject = await roomModel + .findOneAndUpdate( + { _id: room._id }, + { + settlementTotal: 1, + isDeparted: true, + $set: { "part[0].settlementStatus": "paid" }, + }, + { raw: true } + ) + .lean() + .populate(roomPopulateOption); + + if (!changingRoomObject) { + return res.status(404).json({ + error: "Rooms/searchByUser/:id : cannot find settlement info", + }); + } user.doneRoom.push(room._id); @@ -371,7 +386,7 @@ const searchByUserHandler = async (req, res) => { error: "Rooms/searchByUser/:id : internal server error", }); } - user.ongoingRoom.splice(movingRoomIndex); + user.ongoingRoom.splice(movingRoomIndex, 1); await user.save(); }); From fa7f01f76de6f394d66749960989bed03ae93c7a Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Sat, 26 Nov 2022 23:32:30 +0900 Subject: [PATCH 03/17] Fix: searchByUserHandler app crash --- src/service/rooms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/rooms.js b/src/service/rooms.js index ca3e7953..4c390985 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -357,7 +357,7 @@ const searchByUserHandler = async (req, res) => { (room) => room.part.length == 1 && room.time <= req.timestamp ); - moving.forEach(async function (room) { + for (const room of moving) { let changingRoomObject = await roomModel .findOneAndUpdate( { _id: room._id }, @@ -389,7 +389,7 @@ const searchByUserHandler = async (req, res) => { user.ongoingRoom.splice(movingRoomIndex, 1); await user.save(); - }); + } // 정산완료여부 기준으로 진행중인 방과 완료된 방을 분리해서 응답을 전송합니다. const response = {}; From 98537e4a7588eeddcb535ae34d1f8ae60e343774 Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Sun, 27 Nov 2022 00:59:02 +0900 Subject: [PATCH 04/17] Fix: searchByUserHandler --- src/service/rooms.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/service/rooms.js b/src/service/rooms.js index 4c390985..ceb480f7 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -360,13 +360,21 @@ const searchByUserHandler = async (req, res) => { for (const room of moving) { let changingRoomObject = await roomModel .findOneAndUpdate( - { _id: room._id }, + { + _id: room._id, + part: { + $elemMatch: { + user: user._id, + settlementStatus: "not-departed", + }, + }, + time: { $lte: req.timestamp }, + }, { settlementTotal: 1, - isDeparted: true, - $set: { "part[0].settlementStatus": "paid" }, + $set: { "part.$.settlementStatus": "paid" }, }, - { raw: true } + { new: true } ) .lean() .populate(roomPopulateOption); From 88d5899c6505e71952edda20b32f43565a19518f Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Tue, 29 Nov 2022 21:17:45 +0900 Subject: [PATCH 05/17] Fix(rooms.js): searchByUserHandler remove lean --- src/service/rooms.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/service/rooms.js b/src/service/rooms.js index ceb480f7..97b4e0a1 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -348,8 +348,7 @@ const searchByUserHandler = async (req, res) => { path: "doneRoom", options: { limit: 1000 }, populate: roomPopulateOption, - }) - .lean(); + }); // ongoingRoom 중 이미 출발했고, 혼자 참여중인 방은 // 정산 상태를 완료로 바꾸고 doneRoom으로 옮긴다. @@ -357,7 +356,9 @@ const searchByUserHandler = async (req, res) => { (room) => room.part.length == 1 && room.time <= req.timestamp ); - for (const room of moving) { + console.log("moving array: " + moving); + for await (const room of moving) { + console.log("before changing settlement: " + room); let changingRoomObject = await roomModel .findOneAndUpdate( { @@ -385,17 +386,18 @@ const searchByUserHandler = async (req, res) => { }); } + console.log("after changing settlement: " + changingRoomObject); user.doneRoom.push(room._id); - const movingRoomIndex = user.ongoingRoom.indexOf(room._id); + console.log("movingRoomIndex: " + movingRoomIndex); if (movingRoomIndex === -1) { await user.save(); + console.log("There is no room that satisfies room id. "); return res.status(500).json({ error: "Rooms/searchByUser/:id : internal server error", }); } user.ongoingRoom.splice(movingRoomIndex, 1); - await user.save(); } From 97a4ad571a7748aed52f46d476ab6f9a42ee9d26 Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Tue, 29 Nov 2022 23:40:44 +0900 Subject: [PATCH 06/17] Fix: searchByUserHandler moving operation --- src/service/rooms.js | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/service/rooms.js b/src/service/rooms.js index 97b4e0a1..5ea61e9f 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -337,7 +337,7 @@ const searchHandler = async (req, res) => { const searchByUserHandler = async (req, res) => { try { - const user = await userModel + var user = await userModel .findOne({ id: req.userId }) .populate({ path: "ongoingRoom", @@ -356,7 +356,7 @@ const searchByUserHandler = async (req, res) => { (room) => room.part.length == 1 && room.time <= req.timestamp ); - console.log("moving array: " + moving); + // 정산 상태를 완료로 바꾼다. for await (const room of moving) { console.log("before changing settlement: " + room); let changingRoomObject = await roomModel @@ -386,21 +386,33 @@ const searchByUserHandler = async (req, res) => { }); } - console.log("after changing settlement: " + changingRoomObject); - user.doneRoom.push(room._id); - const movingRoomIndex = user.ongoingRoom.indexOf(room._id); - console.log("movingRoomIndex: " + movingRoomIndex); - if (movingRoomIndex === -1) { - await user.save(); - console.log("There is no room that satisfies room id. "); - return res.status(500).json({ - error: "Rooms/searchByUser/:id : internal server error", - }); - } - user.ongoingRoom.splice(movingRoomIndex, 1); - await user.save(); + // ongoingRoom에서 doneRoom으로 옮긴다. + await userModel.updateOne( + { id: req.userId }, + { $push: { doneRoom: room.id } } + ); + + await userModel.updateOne( + { id: req.userId }, + { $pull: { ongoingRoom: room.id } } + ); } + // lean()이 적용된 user를 response에 반환해줘야 하기 때문에 user를 한 번 더 지정한다. + user = await userModel + .findOne({ id: req.userId }) + .populate({ + path: "ongoingRoom", + options: { limit: 1000 }, + populate: roomPopulateOption, + }) + .populate({ + path: "doneRoom", + options: { limit: 1000 }, + populate: roomPopulateOption, + }) + .lean(); + // 정산완료여부 기준으로 진행중인 방과 완료된 방을 분리해서 응답을 전송합니다. const response = {}; response.ongoing = user.ongoingRoom.map((room) => From a231e2d44ff1159e139a0117104cd37cd8e825aa Mon Sep 17 00:00:00 2001 From: Hyogyeong8 Date: Wed, 30 Nov 2022 11:07:30 +0900 Subject: [PATCH 07/17] Docs: searchByUserHandler --- src/route/docs/rooms.md | 2 ++ src/service/rooms.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/route/docs/rooms.md b/src/route/docs/rooms.md index 54c20b92..1526034c 100755 --- a/src/route/docs/rooms.md +++ b/src/route/docs/rooms.md @@ -226,6 +226,8 @@ room의 ID를 받아 해당 room의 참가자 목록에서 요청을 보낸 사 ### `/searchByUser` **(GET)** 로그인된 사용자가 참여 중인 room들을 반환한다. +혼자 참여 중인 방 중 이미 출발한 방이 있으면 +정산 완료 처리한 후 과거 참여 방으로 옮긴다. #### URL parameters diff --git a/src/service/rooms.js b/src/service/rooms.js index 5ea61e9f..2c9d6c19 100644 --- a/src/service/rooms.js +++ b/src/service/rooms.js @@ -337,7 +337,7 @@ const searchHandler = async (req, res) => { const searchByUserHandler = async (req, res) => { try { - var user = await userModel + var user = await userModel // 일련의 작업 후 user를 재정의하기 때문에 var로 정의 .findOne({ id: req.userId }) .populate({ path: "ongoingRoom", @@ -382,7 +382,7 @@ const searchByUserHandler = async (req, res) => { if (!changingRoomObject) { return res.status(404).json({ - error: "Rooms/searchByUser/:id : cannot find settlement info", + error: "Rooms/searchByUser : cannot find settlement info", }); } From 11cfed9693d0ec16490f691803c2fb54773e6e0a Mon Sep 17 00:00:00 2001 From: 14Kgun Date: Fri, 8 Sep 2023 20:27:25 +0900 Subject: [PATCH 08/17] Remove: setTimestamp --- src/routes/rooms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/rooms.js b/src/routes/rooms.js index 76d37c35..be1c3f59 100644 --- a/src/routes/rooms.js +++ b/src/routes/rooms.js @@ -76,7 +76,7 @@ router.post( ); // 로그인된 사용자의 모든 방들을 반환한다. -router.get("/searchByUser", setTimestamp, roomHandlers.searchByUserHandler); +router.get("/searchByUser", roomHandlers.searchByUserHandler); router.post( "/commitPayment", From abda40050fe4aba7f33ca660f9ec81169ee92a33 Mon Sep 17 00:00:00 2001 From: cokia Date: Tue, 23 Apr 2024 19:56:33 +0900 Subject: [PATCH 09/17] fix: autoProcessingRoom cron logic --- src/schedules/autoProcessingRoom.js | 56 +++++++++++++++++++++++++++++ src/schedules/index.js | 1 + 2 files changed, 57 insertions(+) create mode 100644 src/schedules/autoProcessingRoom.js diff --git a/src/schedules/autoProcessingRoom.js b/src/schedules/autoProcessingRoom.js new file mode 100644 index 00000000..f297b506 --- /dev/null +++ b/src/schedules/autoProcessingRoom.js @@ -0,0 +1,56 @@ +const { userModel, roomModel, chatModel } = require("../modules/stores/mongo"); +const logger = require("../modules/logger"); +const { MS_PER_MINUTE } = require("../modules/constants"); +const { emitChatEvent } = require("../modules/socket"); + +// 탑승자가 1명인 상태로 탑승일이 지난 방에 대해서 정산 완료 처리 +module.exports = (app) => async () => { + try { + const io = app.get("io"); + const expiredDate = new Date(Date.now() - 90 * MS_PER_MINUTE).toISOString(); + const arrivalDate = new Date(Date.now() - 60 * MS_PER_MINUTE).toISOString(); + + const candidateRooms = await roomModel.find({ + $and: [ + { time: { $gte: expiredDate } }, + { time: { $lte: arrivalDate } }, + { "part.0": { $exists: true }, "part.1": { $exists: false } }, + { "part.0.settlementStatus": { $nin: ["paid", "sent"] } }, + ], + }); + + await Promise.all( + candidateRooms.map(async ({ _id: roomId, time, part }) => { + const countArrivalChat = await chatModel.countDocuments({ + roomId, + type: "arrival", + }); + if (countArrivalChat > 0) return; + const minuteDiff = Math.floor((Date.now() - time) / MS_PER_MINUTE); + if (minuteDiff <= 0) return; + await emitChatEvent(io, { + roomId: roomId, + type: "arrival", + content: minuteDiff.toString(), + }); + // user에게 doneroom 으로 이전 + const user = await userModel.findById(part[0].userId); + user.doneRooms.push(roomId); + + const userOngoingRoomIndex = user.ongoingRoom.indexOf(roomId); + if (userOngoingRoomIndex === -1) { + await user.save(); + return false; + } + user.ongoingRoom.splice(userOngoingRoomIndex, 1); + + await user.save(); + + // room에 대한 정산 완료 처리 isOver + await roomModel.findByIdAndUpdate(roomId, { isOver: true }); + }) + ); + } catch (err) { + logger.error(err); + } +}; diff --git a/src/schedules/index.js b/src/schedules/index.js index 97818b92..e153f3ed 100644 --- a/src/schedules/index.js +++ b/src/schedules/index.js @@ -3,6 +3,7 @@ const cron = require("node-cron"); const registerSchedules = (app) => { cron.schedule("*/5 * * * *", require("./notifyBeforeDepart")(app)); cron.schedule("*/10 * * * *", require("./notifyAfterArrival")(app)); + cron.schedule("*/15 * * * *", require("./autoProcessingRoom")(app)); }; module.exports = registerSchedules; From f275b149b4a93894b2d9358f4cddaeb3a07b056a Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Mon, 3 Feb 2025 21:05:19 +0900 Subject: [PATCH 10/17] Add: autoProcessingRooms --- src/routes/docs/rooms.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 3ac66e6b..1a572eb3 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -645,7 +645,8 @@ roomsDocs[`${apiPrefix}/searchByUser`] = { summary: "사용자가 참여 중인 방 검색", description: `로그인 된 사용자가 참여 중인 방을 검색합니다.
정산 완료 여부 기준으로 진행 중인 방과 완료된 방을 \`ongoing\`과 \`done\`으로 각각 분리하여 응답을 전송합니다.
- (\`ongoing\`은 \`isOver\`이 flase인 방, \`done\`은 \`isOver\`이 true인 방을 의미합니다.)`, + (\`ongoing\`은 \`isOver\`이 flase인 방, \`done\`은 \`isOver\`이 true인 방을 의미합니다.)
+ 혼자 참여 중인 방 중 이미 출발한 방이 있으면 정산 완료 처리한 후 과거 참여 방으로 옮긴다.`, parameters: {}, responses: { 200: { From 3bdf0a722c4f8ec9ccb4a54e025c37d5e3554647 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Wed, 5 Feb 2025 00:45:52 +0900 Subject: [PATCH 11/17] Fix: confliction --- src/schedules/autoProcessingRoom.js | 3 ++- src/schedules/index.js | 15 --------------- src/schedules/index.ts | 1 + 3 files changed, 3 insertions(+), 16 deletions(-) delete mode 100644 src/schedules/index.js diff --git a/src/schedules/autoProcessingRoom.js b/src/schedules/autoProcessingRoom.js index f297b506..c8816c08 100644 --- a/src/schedules/autoProcessingRoom.js +++ b/src/schedules/autoProcessingRoom.js @@ -1,8 +1,9 @@ const { userModel, roomModel, chatModel } = require("../modules/stores/mongo"); const logger = require("../modules/logger"); -const { MS_PER_MINUTE } = require("../modules/constants"); const { emitChatEvent } = require("../modules/socket"); +const MS_PER_MINUTE = 60000; + // 탑승자가 1명인 상태로 탑승일이 지난 방에 대해서 정산 완료 처리 module.exports = (app) => async () => { try { diff --git a/src/schedules/index.js b/src/schedules/index.js deleted file mode 100644 index 9c8a5217..00000000 --- a/src/schedules/index.js +++ /dev/null @@ -1,15 +0,0 @@ -const cron = require("node-cron"); -const { apiId: naverMapApiId, apiKey: naverMapApiKey } = - require("../../loadenv").naverMap; - -const registerSchedules = (app) => { - cron.schedule("*/5 * * * *", require("./notifyBeforeDepart")(app)); - cron.schedule("*/10 * * * *", require("./notifyAfterArrival")(app)); - cron.schedule("*/15 * * * *", require("./autoProcessingRoom")(app)); - if (naverMapApiId !== undefined && naverMapApiKey !== undefined) { - cron.schedule("0,30 * * * * ", require("./updateMajorTaxiFare")(app)); - cron.schedule("0 18 * * *", require("./updateMinorTaxiFare")(app)); - } -}; - -module.exports = registerSchedules; diff --git a/src/schedules/index.ts b/src/schedules/index.ts index f714dd61..67fa1d5d 100644 --- a/src/schedules/index.ts +++ b/src/schedules/index.ts @@ -9,6 +9,7 @@ import updateMinorTaxiFare from "./updateMinorTaxiFare"; const registerSchedules = (app: Express) => { cron.schedule("*/5 * * * *", notifyBeforeDepart(app)); cron.schedule("*/10 * * * *", notifyAfterArrival(app)); + cron.schedule("*/15 * * * *", require("./autoProcessingRoom")(app)); if (naverMap.apiId && naverMap.apiKey) { cron.schedule("0,30 * * * * ", updateMajorTaxiFare(app)); From 4a59be0d8669fea940922ad70a6f9547b78e5a0a Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Wed, 5 Feb 2025 03:59:20 +0900 Subject: [PATCH 12/17] Add: resolve comments --- src/routes/docs/rooms.md | 369 --------------------------------------- src/schedules/index.ts | 3 +- src/services/rooms.js | 74 +------- 3 files changed, 3 insertions(+), 443 deletions(-) delete mode 100755 src/routes/docs/rooms.md diff --git a/src/routes/docs/rooms.md b/src/routes/docs/rooms.md deleted file mode 100755 index 795864d0..00000000 --- a/src/routes/docs/rooms.md +++ /dev/null @@ -1,369 +0,0 @@ -# `/rooms` API - -## Table of contents - -- [`/rooms` API](#rooms-api) - - [Table of contents](#table-of-contents) - - [Description](#description) - - [Available endpoints](#available-endpoints) - - [`/publicInfo` **(GET)**](#publicinfo-get) - - [URL parameters](#url-parameters) - - [Response](#response) - - [Errors](#errors) - - [`/info` **(GET)**](#info-get) - - [URL parameters](#url-parameters-1) - - [Response](#response-1) - - [Errors](#errors-1) - - [`/create` **(POST)**](#create-post) - - [POST request form](#post-request-form) - - [Errors](#errors-2) - - [Response](#response-2) - - [`/join` (POST)](#join-post) - - [request JSON form](#request-json-form) - - [Errors](#errors-3) - - [`/abort` (POST)](#abort-post) - - [request JSON form](#request-json-form-1) - - [Errors](#errors-4) - - [`/search` **(GET)**](#search-get) - - [URL parameters](#url-parameters-2) - - [Response](#response-3) - - [Errors](#errors-5) - - [`/searchByUser` **(GET)**](#searchbyuser-get) - - [URL parameters](#url-parameters-3) - - [Response](#response-4) - - [Errors](#errors-6) - - [`/commitPayment` **(POST)**](#commitpayment-post) - - [Request Body](#request-body) - - [Response](#response-5) - - [Errors](#errors-7) - - [`/commitSettlement/` **(POST)**](#commitsettlement-post) - - [Request Body](#request-body-1) - - [Response](#response-6) - - [Errors](#errors-8) - - [`/edit/` **(POST)** **(for dev)**](#edit-post-for-dev) - - [POST request form](#post-request-form-1) - - [Response](#response-7) - - [Errors](#errors-9) - - [`/getAllRoom` **(GET)** (for dev)](#getallroom-get-for-dev) - - [`/removeAllRoom` **(GET)** (for dev)](#removeallroom-get-for-dev) - - [`/:id/delete/` **(GET)** **(for dev)**](#iddelete-get-for-dev) - - [URL Parameters](#url-parameters-4) - - [Response](#response-8) - - [Errors](#errors-10) - -## Description - -- 방 생성/수정/삭제/조회 기능을 지원하는 API. -- `/publicInfo`, `/search`를 제외한 endpoint는 로그인된 상태에서만 접근 가능 -- Request form에서 요구하는 property 이름에 ? 이 붙은 경우 필수가 아니라는 뜻 -- 방을 반환할 경우 그 type은 다음과 같다. - -```javascript -Room { - _id: ObjectId, //ObjectID - name: String, // 1~50글자로 구성되며 영어 대소문자, 숫자, 한글, "-", ",", ".", "?", "!", "_"로만 이루어져야 함. - from: { - _id: ObjectId, // 출발지 document의 ObjectId - koName: String, // 출발지의 한국어 명칭 - enName: String, // 출발지의 영어 명칭 - }, - to: { - _id: ObjectId, // 도착지 document의 ObjectId - koName: String, // 도착지의 한국어 명칭 - enName: String, // 도착지의 영어 명칭 - }, - time: String(ISO 8601), // ex) 방 출발 시각. '2022-01-12T13:58:20.180Z' - isDeparted: Boolean, // 이미 출발한 택시인지 여부 (출발했으면 true) - part: [ - { - _id: ObjectId, // part의 ObjectId - user: { - _id: ObjectId, // 참여 중인 사용자 Document의 ObjectId - name: String, // 참여 중인 사용자 이름 - nickname: String, // 참여 중인 사용자 닉네임 - profileImageUrl: String, // 프로필 사진 url - isSettlement: String || undefined, //해당 사용자의 정산 상태 (주의: "/publicInfo"와 "/search"에서는 isSettlement 속성이 undefined로 설정됨). - }, - } - ], - maxPartLength: Number(2~4), //방의 최대 인원 수 - madeat: String(ISO 8601), // ex) 방 생성 시각. '2022-01-12T13:58:20.180Z' - settlementTotal: Number(2~4), // 정산이 완료된 사용자 수 (주의: "/publicInfo"와 "/search"에서는 settlementTotal 속성이 undefined로 설정됨). - isOver: Boolean, // 요청을 보낸 사용자가 해당 방의 정산을 완료됐는지 여부(완료 시 true) (주의: rooms/search에서는 isOver 속성을 반환하지 않고 undefined를 반환함). - __v: Number, // 문서 버전. mongoDB 내부적으로 사용됨. -} -``` - -`settlementStatus` 속성은 아래 네 가지 값들 중 하나를 가진다. - -1. `"not-departed"` : 아무도 결제/정산하지 않은 상태 -2. `"paid"` : 택시비를 결제한 참가가 "결제하기" 버튼을 누르면 해당 참가자에게 설정되는 정산 상태. -3. `"send-required"` : 특정 참가자가 "결제하기" 버튼을 눌렀을 때 그 방의 나머지 참가자에게 설정되는 정산 상태. -4. `"sent"` : 정산 상태가`"send-required"`인 사용자가 "정산하기" 버튼을 눌렀을 때 그 사용자에게 설정되는 정산 상태. - -## Available endpoints - -### `/publicInfo` **(GET)** - -ID를 parameter로 받아 해당 ID의 room의 정보 출력 - -#### URL parameters - -- id : 조회할 room의 ID - -#### Response - -- 해당 방의 정보 -- 각 참여자의 isSettlement 속성과 방의 settlementTotal 속성은 undefined로 설정됨. - -#### Errors - -- 404 "id does not exist" -- 500 "internal server error" - -### `/info` **(GET)** - -ID를 parameter로 받아 해당 ID의 room의 정보 출력 - -#### URL parameters - -- id : 조회할 room의 ID - -#### Response - -- 해당 방의 정보 - -#### Errors - -- 403 "not logged in" -- 403 "did not joined the room" -- 404 "id does not exist" -- 500 "internal server error" - -### `/create` **(POST)** - -요청을 받아 room을 생성 -하나의 User는 최대 5개의 진행중인 방에 참여할 수 있다. - -#### POST request form - -`Request body` - -```javascript -{ - name : String, // 방 이름. 문서 상단에 명시된 규칙을 만족시켜야 함 - from : ObjectId, // 출발지 Document의 ObjectId - to : ObjectId, // 도착지 Document의 ObjectId - time : Date, // 방 출발 시각. 현재 이후여야 함. - part? : String[], // 방 사람들의 ObjectId. 따라서 빈 배열로 요청하시면 됩니다. - maxPartLength: Number(2~4), //방의 최대 인원 수 -} -``` - -#### Errors - -- 400 "bad request" -- 400 "participating in too many rooms" -- 400 "locations are same" -- 400 "no corresponding locations" -- 500 "internal server error" - -#### Response - -- 새로이 만들어진 방 - -### `/join` (POST) - -room의 ID를 받아 해당 room의 참가자 목록에 요청을 보낸 사용자를 추가한다. -하나의 User는 최대 5개의 진행중인 방에 참여할 수 있다. -아직 정원이 차지 않은 방과 아직 출발하지 않은 방에만 참여할 수 있다. - -#### request JSON form - -```javascript -{ - roomId : ObjectId, // 초대 혹은 참여하려는 방 Document의 ObjectId -} -``` - -#### Errors - -- 400 "Bad request" -- 400 "participating in too many rooms" -- 400 "The room is full" -- 400 "The room has already departed" -- 404 "no corresponding room" -- 409 "{userID} Already in room" -- 500 "internal server error" - -### `/abort` (POST) - -room의 ID를 받아 해당 room의 참가자 목록에서 요청을 보낸 사용자를 삭제한다. -출발했지만 정산이 완료되지 않은 방에서는 나갈 수 없다. - -#### request JSON form - -```javascript -{ - roomId : ObjectId, // 초대 혹은 참여하려는 방 Document의 ObjectId -} -``` - -#### Errors - -- 400 "Bad request" -- 400 "cannot exit room. Settlement is not done" -- 404 "no corresponding room" -- 500 "internal server error" - - -### `/search` **(GET)** - -출발지/도착지/날짜를 받아 해당하는 room들을 반환한다. - -#### URL parameters - -- name?: String, // 검색할 방의 이름. 주어진 경우 해당 텍스트가 방의 이름에 포함된 방들만 반환. 주어지지 않은 경우 임의의 이름을 가지는 방들을 검색. -- from? : ObjectId, // 출발지 Document의 ObjectId. 주어진 경우 출발지가 일치하는 방들만 반환. 주어지지 않은 경우 임의의 출발지를 가지는 방들을 검색. -- to? : ObjectId, // 도착지 Document의 ObjectId. 주어진 경우 도착지가 일치하는 방들만 반환. 주어지지 않은 경우 임의의 도착지를 가지는 방들을 검색. -- time? : Date, // 출발 시각. 주어진 경우 주어진 시간부터 주어진 시간부터 그 다음에 찾아오는 오전 5시 전에 출발하는 방들만 반환. 주어지지 않은 경우 현재 시각부터 그 다음으로 찾아오는 오전 5시 전까지의 방들을 반환. -- withTime? : Boolean, // 검색 옵션에 시간 옵션이 포함되어 있는지 여부. false이고 검색하는 날짜가 오늘 이후인 경우 검색하는 시간을 0시 0분 0초로 설정함. -- maxPartLength?: Number(2~4), // 방의 최대 인원 수. 주어진 경우 최대 인원 수가 일치하는 방들만 반환. 주어지지 않은 경우 임의의 최대 인원 수를 가지는 방들을 검색. - - -#### Response - -조건에 맞는 방**들**의 정보: `Room[]` -조건에 일치하는 방이 없더라도 빈 배열을 반환함. - -#### Errors - -- 400 "Bad request" -- 400 "no corresponding locations" -- 500 "Internal server error" - -### `/searchByUser` **(GET)** - -로그인된 사용자가 참여 중인 room들을 반환한다. -혼자 참여 중인 방 중 이미 출발한 방이 있으면 -정산 완료 처리한 후 과거 참여 방으로 옮긴다. - -#### URL parameters - -없음. - -#### Response - -```javascript -{ - ongoing: [Room], // 정산이 완료되지 않은 방 (방의 isOver 속성이 false인 방) - done: [Room], // 정산이 완료된 방 (방의 isOver 속성이 true인 방) -} -``` - -#### Errors - -- 403 "not logged in" -- 500 "internal server error" - - -### `/commitPayment` **(POST)** - -- ID를 받아 해당 방에 요청을 보낸 유저를 결제자로 처리 -- 이미 출발한 방(현재 시각이 출발 시각 이후인 경우)에 대해서만 요청을 처리함 -- 방의 part 배열에서 요청을 보낸 유저의 isSettlement 속성을 `paid`로 설정하고, 나머지 유저들의 isSettlement 속성을 `"send-required"`로 설정함. - -#### Request Body - -- roomId : 정산할 room의 ID - -#### Response - -- 멤버들의 정산정보가 반영된 방의 정보 - -#### Errors - -- 400 "Bad request": 로그인이 되어있지 않은 경우 -- 404 "cannot find settlement info": 사용자가 참여 중인 방이 아니거나, 이미 다른 사람이 결제자이거나, 아직 방이 출발하지 않은 경우 -- 500 "internal server error" - - - -### `/commitSettlement/` **(POST)** - -- ID를 받아 해당 방에 요청을 보낸 유저의 정산을 완료로 처리 -- 방의 part 배열에서 요청을 보낸 유저의 isSettlement 속성을 `send-required`에서 `"sent"`로 변경함. -- 방에 참여한 멤버들이 모두 정산완료를 하면 방의 `isOver` 속성이 `true`로 변경되며, 과거 방으로 취급됨 - -#### Request Body - -- roomId : 정산할 room의 ID - -#### Response - -- 멤버들의 정산정보가 반영된 방의 정보 - -#### Errors - -- 400 "Bad request" : 로그인이 되어있지 않은 경우 -- 404 "cannot find settlement info": 사용자가 참여중인 방이 아니거나, 사용자가 결제를 했거나 이미 정산한 경우 -- 500 "internal server error" - -### `/edit/` **(POST)** **(for dev)** - -- ID와 수정할 데이터를 JSON으로 받아 해당 ID의 room을 수정 -- 방에 참여중인 사용자만 정보를 수정할 수 있음. -- 프론트엔드에서 쓰일 일은 없어 보임. - -#### POST request form - -```javascript -{ - roomId : String, // 수정할 room의 ID - name? : String, // 방 이름. 문서 상단에 명시된 규칙을 만족시켜야 함 - from? : ObjectId, // 출발지 Document의 ObjectId - to? : ObjectId, // 도착지 Document의 ObjectId - time? : Date, // 방 출발 시각. 현재 이후여야 함. - maxPartLength?: Number(2~4), // 방의 최대 인원 수. 현재 참여 인원수보다 크거나 같은 값이어야 함. -} -``` - -#### Response - -- 변경된 방의 정보 - -#### Errors - -- 400 "Bad request" -- 404 "id does not exist" -- 500 "internal server error" - -### `/getAllRoom` **(GET)** (for dev) - -모든 방 가져옴 - -### `/removeAllRoom` **(GET)** (for dev) - -모든 방 삭제 - -### `/:id/delete/` **(GET)** **(for dev)** - -ID를 받아 해당 ID의 room을 제거 - -#### URL Parameters - -- id : 삭제할 room의 ID - -#### Response - -```javascript -{ - id: ObjectId, // 삭제할 방 Document의 ObjectId - isDeleted: true -} -``` - -#### Errors - -- 404 "ID does not exist" -- 500 "Internal server error" \ No newline at end of file diff --git a/src/schedules/index.ts b/src/schedules/index.ts index 67fa1d5d..53b14a52 100644 --- a/src/schedules/index.ts +++ b/src/schedules/index.ts @@ -5,11 +5,12 @@ import notifyBeforeDepart from "./notifyBeforeDepart"; import notifyAfterArrival from "./notifyAfterArrival"; import updateMajorTaxiFare from "./updateMajorTaxiFare"; import updateMinorTaxiFare from "./updateMinorTaxiFare"; +import autoProcessingRoom from "./autoProcessingRoom"; const registerSchedules = (app: Express) => { cron.schedule("*/5 * * * *", notifyBeforeDepart(app)); cron.schedule("*/10 * * * *", notifyAfterArrival(app)); - cron.schedule("*/15 * * * *", require("./autoProcessingRoom")(app)); + cron.schedule("1-59/10 * * * *", autoProcessingRoom(app)); if (naverMap.apiId && naverMap.apiKey) { cron.schedule("0,30 * * * * ", updateMajorTaxiFare(app)); diff --git a/src/services/rooms.js b/src/services/rooms.js index b3dbb8ca..736ea3fb 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -485,7 +485,7 @@ const searchHandler = async (req, res) => { const searchByUserHandler = async (req, res) => { try { - var user = await userModel // 일련의 작업 후 user를 재정의하기 때문에 var로 정의 + let user = await userModel .findOne({ id: req.userId }) .populate({ path: "ongoingRoom", @@ -498,78 +498,6 @@ const searchByUserHandler = async (req, res) => { populate: roomPopulateOption, }); - // ongoingRoom 중 이미 출발했고, 혼자 참여중인 방은 - // 정산 상태를 완료로 바꾸고 doneRoom으로 옮긴다. - const moving = user.ongoingRoom.filter( - (room) => room.part.length == 1 && room.time <= req.timestamp - ); - - // 정산 상태를 완료로 바꾼다. - for await (const room of moving) { - console.log("before changing settlement: " + room); - let changingRoomObject = await roomModel - .findOneAndUpdate( - { - _id: room._id, - part: { - $elemMatch: { - user: user._id, - settlementStatus: "not-departed", - }, - }, - time: { $lte: req.timestamp }, - }, - { - settlementTotal: 1, - $set: { "part.$.settlementStatus": "paid" }, - }, - { new: true } - ) - .lean() - .populate(roomPopulateOption); - - if (!changingRoomObject) { - return res.status(404).json({ - error: "Rooms/searchByUser : cannot find settlement info", - }); - } - - // ongoingRoom에서 doneRoom으로 옮긴다. - await userModel.updateOne( - { id: req.userId }, - { $push: { doneRoom: room.id } } - ); - - await userModel.updateOne( - { id: req.userId }, - { $pull: { ongoingRoom: room.id } } - ); - } - - // lean()이 적용된 user를 response에 반환해줘야 하기 때문에 user를 한 번 더 지정한다. - user = await userModel - .findOne({ id: req.userId }) - .populate({ - path: "ongoingRoom", - options: { - limit: 1000, - // ongoingRoom 은 시간 오름차순 정렬 - sort: { time: 1 }, - }, - populate: roomPopulateOption, - }) - .populate({ - path: "doneRoom", - options: { - limit: 1000, - // doneRoom 은 시간 내림차순 정렬 - sort: { time: -1 }, - }, - populate: roomPopulateOption, - }) - .lean(); - - // 정산완료여부 기준으로 진행중인 방과 완료된 방을 분리해서 응답을 전송합니다. const response = {}; response.ongoing = user.ongoingRoom.map((room) => formatSettlement(room, { isOver: false }) From 758b42826db3ac79db2aa1891f983ee8407edb2f Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Thu, 6 Feb 2025 01:20:46 +0900 Subject: [PATCH 13/17] Add: resolve race condition --- src/schedules/autoProcessingRoom.js | 54 +++++++++++++---------------- src/schedules/index.ts | 3 +- src/services/rooms.js | 17 +++++++-- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/schedules/autoProcessingRoom.js b/src/schedules/autoProcessingRoom.js index c8816c08..4fc0539a 100644 --- a/src/schedules/autoProcessingRoom.js +++ b/src/schedules/autoProcessingRoom.js @@ -1,54 +1,48 @@ -const { userModel, roomModel, chatModel } = require("../modules/stores/mongo"); -const logger = require("../modules/logger"); const { emitChatEvent } = require("../modules/socket"); +const { userModel, roomModel } = require("../modules/stores/mongo"); +const logger = require("../modules/logger"); const MS_PER_MINUTE = 60000; -// 탑승자가 1명인 상태로 탑승일이 지난 방에 대해서 정산 완료 처리 +// 탑승자가 1명인 상태로 탑승 시간이 지난 방에 대해서 정산 완료 처리 module.exports = (app) => async () => { try { const io = app.get("io"); - const expiredDate = new Date(Date.now() - 90 * MS_PER_MINUTE).toISOString(); - const arrivalDate = new Date(Date.now() - 60 * MS_PER_MINUTE).toISOString(); - + const expiredDate = new Date(Date.now() - 60 * MS_PER_MINUTE).toISOString(); + const arrivalDate = new Date(Date.now()).toISOString(); const candidateRooms = await roomModel.find({ $and: [ { time: { $gte: expiredDate } }, { time: { $lte: arrivalDate } }, { "part.0": { $exists: true }, "part.1": { $exists: false } }, - { "part.0.settlementStatus": { $nin: ["paid", "sent"] } }, + { "part.0.settlementStatus": { $nin: ["paid", "sent"] } }, // "sent"의 경우 로직상 불가능 하지만, 문서화 측면에서 의도적으로 남겨두었음음. ], }); await Promise.all( - candidateRooms.map(async ({ _id: roomId, time, part }) => { - const countArrivalChat = await chatModel.countDocuments({ - roomId, - type: "arrival", - }); - if (countArrivalChat > 0) return; - const minuteDiff = Math.floor((Date.now() - time) / MS_PER_MINUTE); - if (minuteDiff <= 0) return; + candidateRooms.map(async ({ _id: roomId, part }) => { + const user = await userModel.findById(part[0].user._id); + + // 정산 채팅을 보냅니다. await emitChatEvent(io, { roomId: roomId, - type: "arrival", - content: minuteDiff.toString(), + type: "settlement", + content: user.id, + authorId: user._id, }); - // user에게 doneroom 으로 이전 - const user = await userModel.findById(part[0].userId); - user.doneRooms.push(roomId); - - const userOngoingRoomIndex = user.ongoingRoom.indexOf(roomId); - if (userOngoingRoomIndex === -1) { - await user.save(); - return false; - } - user.ongoingRoom.splice(userOngoingRoomIndex, 1); - await user.save(); + // 1명의 참여자만 존재하는 room에 대하여 정산 완료 처리 + await roomModel.findByIdAndUpdate(roomId, { + ["part.0.settlementStatus"]: "paid", + settlementTotal: 1, + }); - // room에 대한 정산 완료 처리 isOver - await roomModel.findByIdAndUpdate(roomId, { isOver: true }); + // Atomic update로 각 Room을 한번에 제거 및 추가함. + // 아토믹하게 처리하지 않을 경우 각 Promise가 동일한 user의 여러 ongoingRoom 또는 doneRoom을 동시에 수정하여 경합조건이 발생할 수 있음에 유의. + await userModel.findByIdAndUpdate(user._id, { + $pull: { ongoingRoom: roomId }, + $push: { doneRoom: roomId }, + }); }) ); } catch (err) { diff --git a/src/schedules/index.ts b/src/schedules/index.ts index 53b14a52..80f55d99 100644 --- a/src/schedules/index.ts +++ b/src/schedules/index.ts @@ -10,8 +10,7 @@ import autoProcessingRoom from "./autoProcessingRoom"; const registerSchedules = (app: Express) => { cron.schedule("*/5 * * * *", notifyBeforeDepart(app)); cron.schedule("*/10 * * * *", notifyAfterArrival(app)); - cron.schedule("1-59/10 * * * *", autoProcessingRoom(app)); - + cron.schedule("1,11,21,31,41,51 * * * *", autoProcessingRoom(app)); if (naverMap.apiId && naverMap.apiKey) { cron.schedule("0,30 * * * * ", updateMajorTaxiFare(app)); cron.schedule("0 18 * * *", updateMinorTaxiFare(app)); diff --git a/src/services/rooms.js b/src/services/rooms.js index 736ea3fb..c27e92e5 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -485,19 +485,30 @@ const searchHandler = async (req, res) => { const searchByUserHandler = async (req, res) => { try { + // lean()이 적용된 user를 response에 반환해줘야 하기 때문에 user를 한 번 더 지정한다. let user = await userModel .findOne({ id: req.userId }) .populate({ path: "ongoingRoom", - options: { limit: 1000 }, + options: { + limit: 1000, + // ongoingRoom 은 시간 오름차순 정렬 + sort: { time: 1 }, + }, populate: roomPopulateOption, }) .populate({ path: "doneRoom", - options: { limit: 1000 }, + options: { + limit: 1000, + // doneRoom 은 시간 내림차순 정렬 + sort: { time: -1 }, + }, populate: roomPopulateOption, - }); + }) + .lean(); + // 정산완료여부 기준으로 진행중인 방과 완료된 방을 분리해서 응답을 전송합니다. const response = {}; response.ongoing = user.ongoingRoom.map((room) => formatSettlement(room, { isOver: false }) From b75ba0f2ba5cd30e2a8ef811a730b3734f946df9 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Thu, 6 Feb 2025 02:43:19 +0900 Subject: [PATCH 14/17] Add: resolve comments --- src/routes/docs/rooms.js | 1 - ...utoProcessingRoom.js => autoSettlement.ts} | 27 +++++++++++-------- src/schedules/index.ts | 4 +-- src/services/rooms.js | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) rename src/schedules/{autoProcessingRoom.js => autoSettlement.ts} (69%) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 9e190654..8292acd5 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -657,7 +657,6 @@ roomsDocs[`${apiPrefix}/searchByUser`] = { summary: "사용자가 참여 중인 방 검색", description: `로그인 된 사용자가 참여 중인 방을 검색합니다.
정산 완료 여부 기준으로 진행 중인 방과 완료된 방을 \`ongoing\`과 \`done\`으로 각각 분리하여 응답을 전송합니다.
- (\`ongoing\`은 \`isOver\`이 flase인 방, \`done\`은 \`isOver\`이 true인 방을 의미합니다.)
혼자 참여 중인 방 중 이미 출발한 방이 있으면 정산 완료 처리한 후 과거 참여 방으로 옮긴다.`, parameters: {}, responses: { diff --git a/src/schedules/autoProcessingRoom.js b/src/schedules/autoSettlement.ts similarity index 69% rename from src/schedules/autoProcessingRoom.js rename to src/schedules/autoSettlement.ts index 4fc0539a..e3f57c1b 100644 --- a/src/schedules/autoProcessingRoom.js +++ b/src/schedules/autoSettlement.ts @@ -1,11 +1,12 @@ -const { emitChatEvent } = require("../modules/socket"); -const { userModel, roomModel } = require("../modules/stores/mongo"); -const logger = require("../modules/logger"); +import type { Express } from "express"; +import { emitChatEvent } from "@/modules/socket"; +import { userModel, roomModel } from "@/modules/stores/mongo"; +import logger from "@/modules/logger"; const MS_PER_MINUTE = 60000; // 탑승자가 1명인 상태로 탑승 시간이 지난 방에 대해서 정산 완료 처리 -module.exports = (app) => async () => { +const autoSettlement = (app: Express) => async () => { try { const io = app.get("io"); const expiredDate = new Date(Date.now() - 60 * MS_PER_MINUTE).toISOString(); @@ -15,23 +16,25 @@ module.exports = (app) => async () => { { time: { $gte: expiredDate } }, { time: { $lte: arrivalDate } }, { "part.0": { $exists: true }, "part.1": { $exists: false } }, - { "part.0.settlementStatus": { $nin: ["paid", "sent"] } }, // "sent"의 경우 로직상 불가능 하지만, 문서화 측면에서 의도적으로 남겨두었음음. + { "part.0.settlementStatus": { $nin: ["paid", "sent"] } }, // "sent"의 경우 로직상 불가능 하지만, 문서화 측면에서 의도적으로 남겨두었음. ], }); await Promise.all( candidateRooms.map(async ({ _id: roomId, part }) => { - const user = await userModel.findById(part[0].user._id); + const user = await userModel.findById(part![0].user._id); + if (user && !user.withdraw) return false; // 정산 채팅을 보냅니다. await emitChatEvent(io, { - roomId: roomId, + roomId: roomId.toString(), type: "settlement", - content: user.id, - authorId: user._id, + content: user!.id, + authorId: user!._id.toString(), + time: null, }); - // 1명의 참여자만 존재하는 room에 대하여 정산 완료 처리 + // 1명의 참여자만 존재하는 room에 대하여 정산 완료 처리. await roomModel.findByIdAndUpdate(roomId, { ["part.0.settlementStatus"]: "paid", settlementTotal: 1, @@ -39,7 +42,7 @@ module.exports = (app) => async () => { // Atomic update로 각 Room을 한번에 제거 및 추가함. // 아토믹하게 처리하지 않을 경우 각 Promise가 동일한 user의 여러 ongoingRoom 또는 doneRoom을 동시에 수정하여 경합조건이 발생할 수 있음에 유의. - await userModel.findByIdAndUpdate(user._id, { + await userModel.findByIdAndUpdate(user!._id, { $pull: { ongoingRoom: roomId }, $push: { doneRoom: roomId }, }); @@ -49,3 +52,5 @@ module.exports = (app) => async () => { logger.error(err); } }; + +export default autoSettlement; diff --git a/src/schedules/index.ts b/src/schedules/index.ts index 80f55d99..ea1bb96f 100644 --- a/src/schedules/index.ts +++ b/src/schedules/index.ts @@ -5,12 +5,12 @@ import notifyBeforeDepart from "./notifyBeforeDepart"; import notifyAfterArrival from "./notifyAfterArrival"; import updateMajorTaxiFare from "./updateMajorTaxiFare"; import updateMinorTaxiFare from "./updateMinorTaxiFare"; -import autoProcessingRoom from "./autoProcessingRoom"; +import autoSettlement from "./autoSettlement"; const registerSchedules = (app: Express) => { cron.schedule("*/5 * * * *", notifyBeforeDepart(app)); cron.schedule("*/10 * * * *", notifyAfterArrival(app)); - cron.schedule("1,11,21,31,41,51 * * * *", autoProcessingRoom(app)); + cron.schedule("1,11,21,31,41,51 * * * *", autoSettlement(app)); if (naverMap.apiId && naverMap.apiKey) { cron.schedule("0,30 * * * * ", updateMajorTaxiFare(app)); cron.schedule("0 18 * * *", updateMinorTaxiFare(app)); diff --git a/src/services/rooms.js b/src/services/rooms.js index c27e92e5..76350db0 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -486,7 +486,7 @@ const searchHandler = async (req, res) => { const searchByUserHandler = async (req, res) => { try { // lean()이 적용된 user를 response에 반환해줘야 하기 때문에 user를 한 번 더 지정한다. - let user = await userModel + const user = await userModel .findOne({ id: req.userId }) .populate({ path: "ongoingRoom", From ac12dbec29421ecd66e3d23ba358067422194b85 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Thu, 6 Feb 2025 02:57:30 +0900 Subject: [PATCH 15/17] Add: resolve comments --- src/schedules/autoSettlement.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/schedules/autoSettlement.ts b/src/schedules/autoSettlement.ts index e3f57c1b..4e07a4a6 100644 --- a/src/schedules/autoSettlement.ts +++ b/src/schedules/autoSettlement.ts @@ -23,8 +23,6 @@ const autoSettlement = (app: Express) => async () => { await Promise.all( candidateRooms.map(async ({ _id: roomId, part }) => { const user = await userModel.findById(part![0].user._id); - if (user && !user.withdraw) return false; - // 정산 채팅을 보냅니다. await emitChatEvent(io, { roomId: roomId.toString(), From 5077617e9002e775b9e94e2104b2fa6a0e871cb3 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Thu, 6 Feb 2025 03:08:13 +0900 Subject: [PATCH 16/17] Add: resolve comments --- src/routes/docs/rooms.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 8292acd5..30c00077 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -656,8 +656,7 @@ roomsDocs[`${apiPrefix}/searchByUser`] = { tags: [tag], summary: "사용자가 참여 중인 방 검색", description: `로그인 된 사용자가 참여 중인 방을 검색합니다.
- 정산 완료 여부 기준으로 진행 중인 방과 완료된 방을 \`ongoing\`과 \`done\`으로 각각 분리하여 응답을 전송합니다.
- 혼자 참여 중인 방 중 이미 출발한 방이 있으면 정산 완료 처리한 후 과거 참여 방으로 옮긴다.`, + 정산 완료 여부 기준으로 진행 중인 방과 완료된 방을 \`ongoing\`과 \`done\`으로 각각 분리하여 응답을 전송합니다.`, parameters: {}, responses: { 200: { From ec34739d230c2497b7cee4fbfeb52f02282799f0 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Thu, 6 Feb 2025 03:10:13 +0900 Subject: [PATCH 17/17] Add: resolve comments --- src/routes/docs/rooms.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 30c00077..41d6a1cb 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -656,7 +656,8 @@ roomsDocs[`${apiPrefix}/searchByUser`] = { tags: [tag], summary: "사용자가 참여 중인 방 검색", description: `로그인 된 사용자가 참여 중인 방을 검색합니다.
- 정산 완료 여부 기준으로 진행 중인 방과 완료된 방을 \`ongoing\`과 \`done\`으로 각각 분리하여 응답을 전송합니다.`, + 정산 완료 여부 기준으로 진행 중인 방과 완료된 방을 \`ongoing\`과 \`done\`으로 각각 분리하여 응답을 전송합니다.
+ (\`ongoing\`은 \`isOver\`이 flase인 방, \`done\`은 \`isOver\`이 true인 방을 의미합니다.)`, parameters: {}, responses: { 200: {