From 1e1a83f381650be829cb5dac3b67c52a507a28a0 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Mon, 12 Feb 2024 17:12:08 +0000 Subject: [PATCH 01/25] Fix: change commitPayment and commitSettlement --- src/routes/docs/rooms.js | 20 ++++++++++---------- src/routes/rooms.js | 11 ++++++----- src/services/rooms.js | 18 +++++++++--------- test/services/rooms.js | 14 +++++++------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 3292b127..53ebbd5f 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -678,11 +678,11 @@ roomsDocs[`${apiPrefix}/searchByUser`] = { }, }; -roomsDocs[`${apiPrefix}/commitPayment`] = { +roomsDocs[`${apiPrefix}/commitSettlement`] = { post: { tags: [tag], - summary: "방 결제 처리", - description: `해당 방에 요청을 보낸 유저를 결제자로 처리합니다.
+ summary: "방 정산 요청 처리", + description: `해당 방에 요청을 보낸 유저를 결제자로 처리하여, 다른 유저들에게 정산을 요청합니다.
이미 출발한 방에 대해서만 요청을 처리합니다.
방의 \`part\` 배열에서 요청을 보낸 유저의 \`isSettlement\` 속성은 \`paid\`로 설정됩니다.
나머지 유저들의 \`isSettlement\` 속성을 \`send-required\`로 설정합니다.`, @@ -726,7 +726,7 @@ roomsDocs[`${apiPrefix}/commitPayment`] = { }, }, example: { - error: "Rooms/:id/commitPayment : cannot find settlement info", + error: "Rooms/:id/commitSettlement : cannot find settlement info", }, }, }, @@ -744,7 +744,7 @@ roomsDocs[`${apiPrefix}/commitPayment`] = { }, }, example: { - error: "Rooms/:id/commitPayment : internal server error", + error: "Rooms/:id/commitSettlement : internal server error", }, }, }, @@ -753,11 +753,11 @@ roomsDocs[`${apiPrefix}/commitPayment`] = { }, }; -roomsDocs[`${apiPrefix}/commitSettlement`] = { +roomsDocs[`${apiPrefix}/commitPayment`] = { post: { tags: [tag], - summary: "방 정산 완료 처리", - description: `해당 방에 요청을 보낸 유저를 정산 완료로 처리합니다.
+ summary: "방 송금 처리", + description: `해당 방에 요청을 보낸 유저를 송금을 완료한 정산 완료로 처리합니다.
방의 \`part\` 배열에서 요청을 보낸 유저의 \`isSettlement\` 속성은 \`send-required\`에서 \`sent\`로 변경합니다.
방의 참여한 유저들이 모두 정산완료를 하면 방의 \`isOver\` 속성이 \`true\`로 변경되며, 과거 방으로 취급됩니다.`, requestBody: { @@ -800,7 +800,7 @@ roomsDocs[`${apiPrefix}/commitSettlement`] = { }, }, example: { - error: "Rooms/:id/settlement : cannot find settlement info", + error: "Rooms/:id/commitPayment : cannot find settlement info", }, }, }, @@ -818,7 +818,7 @@ roomsDocs[`${apiPrefix}/commitSettlement`] = { }, }, example: { - error: "Rooms/:id/settlement : internal server error", + error: "Rooms/:id/commitPayment : internal server error", }, }, }, diff --git a/src/routes/rooms.js b/src/routes/rooms.js index be1c3f59..bfba96f7 100644 --- a/src/routes/rooms.js +++ b/src/routes/rooms.js @@ -78,19 +78,20 @@ router.post( // 로그인된 사용자의 모든 방들을 반환한다. router.get("/searchByUser", roomHandlers.searchByUserHandler); +// 해당 방에 요청을 보낸 유저의 정산을 처리한다. router.post( - "/commitPayment", + "/commitSettlement", body("roomId").isMongoId(), validator, - roomHandlers.commitPaymentHandler + roomHandlers.commitSettlementHandler ); -// 해당 룸의 요청을 보낸 유저의 정산을 완료로 처리한다. +// 해당 방에 요청을 보낸 유저의 송금을 처리한다. router.post( - "/commitSettlement", + "/commitPayment", body("roomId").isMongoId(), validator, - roomHandlers.settlementHandler + roomHandlers.commitPaymentHandler ); // json으로 수정할 값들을 받아 방의 정보를 수정합니다. diff --git a/src/services/rooms.js b/src/services/rooms.js index a2562c67..2228e29d 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -428,7 +428,7 @@ const searchByUserHandler = async (req, res) => { } }; -const commitPaymentHandler = async (req, res) => { +const commitSettlementHandler = async (req, res) => { try { const user = await userModel.findOne({ id: req.userId }); const { roomId } = req.body; @@ -462,7 +462,7 @@ const commitPaymentHandler = async (req, res) => { if (!roomObject) { return res.status(404).json({ - error: "Rooms/:id/commitPayment : cannot find settlement info", + error: "Rooms/:id/commitSettlement : cannot find settlement info", }); } @@ -475,7 +475,7 @@ const commitPaymentHandler = async (req, res) => { if (userOngoingRoomIndex === -1) { await user.save(); return res.status(500).json({ - error: "Rooms/:id/settlement : internal server error", + error: "Rooms/:id/commitSettlement : internal server error", }); } user.ongoingRoom.splice(userOngoingRoomIndex, 1); @@ -507,12 +507,12 @@ const commitPaymentHandler = async (req, res) => { } catch (err) { logger.error(err); res.status(500).json({ - error: "Rooms/:id/commitPayment : internal server error", + error: "Rooms/:id/commitSettlement : internal server error", }); } }; -const settlementHandler = async (req, res) => { +const commitPaymentHandler = async (req, res) => { try { const { roomId } = req.body; const user = await userModel.findOne({ id: req.userId }); @@ -540,7 +540,7 @@ const settlementHandler = async (req, res) => { if (!roomObject) { return res.status(404).json({ - error: "Rooms/:id/settlement : cannot find settlement info", + error: "Rooms/:id/commitPayment : cannot find settlement info", }); } @@ -553,7 +553,7 @@ const settlementHandler = async (req, res) => { if (userOngoingRoomIndex === -1) { await user.save(); return res.status(500).json({ - error: "Rooms/:id/settlement : internal server error", + error: "Rooms/:id/commitPayment : internal server error", }); } user.ongoingRoom.splice(userOngoingRoomIndex, 1); @@ -585,7 +585,7 @@ const settlementHandler = async (req, res) => { } catch (err) { logger.error(err); res.status(500).json({ - error: "Rooms/:id/settlement : internal server error", + error: "Rooms/:id/commitPayment : internal server error", }); } }; @@ -679,6 +679,6 @@ module.exports = { searchHandler, searchByUserHandler, commitPaymentHandler, - settlementHandler, + commitSettlementHandler, // editHandler, }; diff --git a/test/services/rooms.js b/test/services/rooms.js index e17ae6af..62d05609 100644 --- a/test/services/rooms.js +++ b/test/services/rooms.js @@ -141,8 +141,8 @@ describe("[rooms] 6.searchByUserHandler", () => { }); // 7. 1분이 지난 후, 정산 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 -describe("[rooms] 7.commitPaymentHandler", () => { - it("should return information of room and commit payment", async () => { +describe("[rooms] 7.commitsettlementHandler", () => { + it("should return information of room and commit settlement", async () => { const testUser1 = await userModel.findOne({ id: "test1" }); const testRoom = await roomModel.findOne({ name: "test-room" }); let req = httpMocks.createRequest({ @@ -152,7 +152,7 @@ describe("[rooms] 7.commitPaymentHandler", () => { app, }); let res = httpMocks.createResponse(); - await roomsHandlers.commitPaymentHandler(req, res); + await roomsHandlers.commitSettlementHandler(req, res); const resData = res._getData(); expect(resData).to.has.property("name", "test-room"); @@ -161,9 +161,9 @@ describe("[rooms] 7.commitPaymentHandler", () => { }); }); -// 8. 도착 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 -describe("[rooms] 8.settlementHandler", () => { - it("should return information of room and set settlement", async () => { +// 8. 송금 후 정산 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 +describe("[rooms] 8.commitPaymentHandler", () => { + it("should return information of room and commit payment", async () => { const testUser2 = await userModel.findOne({ id: "test2" }); const testRoom = await roomModel.findOne({ name: "test-room" }); let req = httpMocks.createRequest({ @@ -172,7 +172,7 @@ describe("[rooms] 8.settlementHandler", () => { app, }); let res = httpMocks.createResponse(); - await roomsHandlers.settlementHandler(req, res); + await roomsHandlers.commitPaymentHandler(req, res); const resData = res._getData(); expect(resData).to.has.property("name", "test-room"); From 1bd982f2f422b2254d2caad98d431876874200f8 Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Tue, 19 Mar 2024 21:04:48 +0900 Subject: [PATCH 02/25] Refactor: validate by zod --- src/routes/docs/schemas/roomsSchema.js | 8 ++++++++ src/routes/rooms.js | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/routes/docs/schemas/roomsSchema.js b/src/routes/docs/schemas/roomsSchema.js index 39dcd8bf..a0af753e 100644 --- a/src/routes/docs/schemas/roomsSchema.js +++ b/src/routes/docs/schemas/roomsSchema.js @@ -31,6 +31,14 @@ roomsZod["room"] = z }) .partial({ settlementTotal: true, isOver: true }); +roomsZod["commitSettlement"] = z.object({ + roomId: z.string().regex(objectId), +}); + +roomsZod["commitPayment"] = z.object({ + roomId: z.string().regex(objectId), +}); + const roomsSchema = zodToSchemaObject(roomsZod); module.exports = { roomsSchema, roomsZod }; diff --git a/src/routes/rooms.js b/src/routes/rooms.js index 566f862f..6345fa6f 100644 --- a/src/routes/rooms.js +++ b/src/routes/rooms.js @@ -1,5 +1,7 @@ const express = require("express"); const { query, body } = require("express-validator"); +const { validateBody } = require("../middlewares/zod"); +const { roomsZod } = require("./docs/schemas/roomsSchema"); const router = express.Router(); const roomHandlers = require("../services/rooms"); @@ -94,16 +96,14 @@ router.get("/searchByUser", roomHandlers.searchByUserHandler); // 해당 방에 요청을 보낸 유저의 정산을 처리한다. router.post( "/commitSettlement", - body("roomId").isMongoId(), - validator, + validateBody(roomsZod.commitSettlement), roomHandlers.commitSettlementHandler ); // 해당 방에 요청을 보낸 유저의 송금을 처리한다. router.post( "/commitPayment", - body("roomId").isMongoId(), - validator, + validateBody(roomsZod.commitPayment), roomHandlers.commitPaymentHandler ); From 295366c46ac8249149c4062061fe253d479d4f95 Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Tue, 26 Mar 2024 23:48:47 +0900 Subject: [PATCH 03/25] Refactor: change settlement and payment --- src/lottery/modules/contracts.js | 6 +++--- src/modules/socket.js | 4 ++-- src/routes/docs/chats.js | 2 +- src/services/rooms.js | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lottery/modules/contracts.js b/src/lottery/modules/contracts.js index 87a24a84..56188041 100644 --- a/src/lottery/modules/contracts.js +++ b/src/lottery/modules/contracts.js @@ -127,7 +127,7 @@ const completeFirstLoginQuest = async (userId, timestamp) => { * @param {Date} roomObject.time - 출발 시각입니다. * @returns {Promise} * @description 정산 요청 또는 송금이 이루어질 때마다 호출해 주세요. - * @usage rooms - commitPaymentHandler, rooms - settlementHandler + * @usage rooms - commitPaymentHandler, rooms - commitSettlementHandler */ const completePayingAndSendingQuest = async (userId, timestamp, roomObject) => { logger.info( @@ -167,7 +167,7 @@ const completeFirstRoomCreationQuest = async (userId, timestamp) => { * @param {Date} roomObject.time - 출발 시각입니다. * @returns {Promise} * @description 정산 요청이 이루어질 때마다 호출해 주세요. - * @usage rooms - commitPaymentHandler + * @usage rooms - commitSettlementHandler */ const completePayingQuest = async (userId, timestamp, roomObject) => { logger.info( @@ -195,7 +195,7 @@ const completePayingQuest = async (userId, timestamp, roomObject) => { * @param {Date} roomObject.time - 출발 시각입니다. * @returns {Promise} * @description 송금이 이루어질 때마다 호출해 주세요. - * @usage rooms - settlementHandler + * @usage rooms - paymentHandler */ const completeSendingQuest = async (userId, timestamp, roomObject) => { logger.info( diff --git a/src/modules/socket.js b/src/modules/socket.js index 07806ef4..bfdf95af 100644 --- a/src/modules/socket.js +++ b/src/modules/socket.js @@ -83,11 +83,11 @@ const getMessageBody = (type, nickname = "", content = "") => { const suffix = "님이 퇴장하였습니다"; return `${ellipsisedNickname} ${suffix}`; } - case "payment": { + case "settlement": { const suffix = "님이 정산을 시작하였습니다"; return `${ellipsisedNickname} ${suffix}`; } - case "settlement": { + case "payment": { const suffix = "님이 송금을 완료하였습니다"; return `${ellipsisedNickname} ${suffix}`; } diff --git a/src/routes/docs/chats.js b/src/routes/docs/chats.js index 0aaa1c6d..f9107201 100644 --- a/src/routes/docs/chats.js +++ b/src/routes/docs/chats.js @@ -211,7 +211,7 @@ chatsDocs[`${apiPrefix}/send`] = { Chat { roomId: ObjectId, //방의 objectId - type: String, // 메시지 종류 ("text": 일반 메시지, "s3img": S3에 업로드된 이미지, "in": 입장 메시지, "out": 퇴장 메시지, "payment": 결제 메시지, "settlement": 정산 완료 메시지, "account": 계좌 전송 메시지) + type: String, // 메시지 종류 ("text": 일반 메시지, "s3img": S3에 업로드된 이미지, "in": 입장 메시지, "out": 퇴장 메시지, "settlement": 정산 메시지, "payment": 송금 메시지, "account": 계좌 전송 메시지) authorId: ObejctId, //작성자의 objectId content: String, // 메시지 내용 (메시지 종류에 따라 포맷이 상이함) time: String(ISO 8601), // ex) 2024-01-08T01:52:00.000Z diff --git a/src/services/rooms.js b/src/services/rooms.js index 23f9cafb..7d9f5f8d 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -616,7 +616,7 @@ const commitSettlementHandler = async (req, res) => { // 결제 채팅을 보냅니다. await emitChatEvent(req.app.get("io"), { roomId, - type: "payment", + type: "settlement", content: user.id, authorId: user._id, }); @@ -694,7 +694,7 @@ const commitPaymentHandler = async (req, res) => { // 정산 채팅을 보냅니다. await emitChatEvent(req.app.get("io"), { roomId, - type: "settlement", + type: "payment", content: user.id, authorId: user._id, }); From 880aa3bf843f0d61215765025e9c49e367ca847c Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Wed, 27 Mar 2024 01:57:40 +0900 Subject: [PATCH 04/25] Add chatPaymentSettlementUpdater.js --- scripts/chatPaymentSettlementUpdater.js | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/chatPaymentSettlementUpdater.js diff --git a/scripts/chatPaymentSettlementUpdater.js b/scripts/chatPaymentSettlementUpdater.js new file mode 100644 index 00000000..22f2fba3 --- /dev/null +++ b/scripts/chatPaymentSettlementUpdater.js @@ -0,0 +1,37 @@ +// Issue #449-1을 해결하기 위한 DB 마이그레이션 스크립트입니다. +// chat type 중 settlement와 payment를 서로 교체합니다. +// https://github.com/sparcs-kaist/taxi-back/issues/449 + +const { MongoClient } = require("mongodb"); +const { mongo: mongoUrl } = require("../loadenv"); + +const time = Date.now(); + +const client = new MongoClient(mongoUrl); +const db = client.db("taxi"); +const chats = db.collection("chats"); + +async function run() { + try { + for await (const doc of chats.find()) { + // 이미 변환이 완료된 경우에는 Pass합니다. + if (doc.type === "settlement" || doc.type === "payment") { + await chats.findOneAndUpdate( + { _id: doc._id }, + { + $set: { + type: doc.type === "settlement" ? "payment" : "settlement", + }, + } + ); + } + } + } catch (err) { + console.log(err); + } finally { + await client.close(); + } +} +run().then(() => { + console.log("Done!"); +}); From 2c06b1f5ea3e9ea9a4bb162ea22781a6da99c8bc Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Wed, 27 Mar 2024 02:07:01 +0900 Subject: [PATCH 05/25] Fix: paymentHandler to commitPaymentHandler --- src/lottery/modules/contracts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lottery/modules/contracts.js b/src/lottery/modules/contracts.js index 56188041..93d43e23 100644 --- a/src/lottery/modules/contracts.js +++ b/src/lottery/modules/contracts.js @@ -195,7 +195,7 @@ const completePayingQuest = async (userId, timestamp, roomObject) => { * @param {Date} roomObject.time - 출발 시각입니다. * @returns {Promise} * @description 송금이 이루어질 때마다 호출해 주세요. - * @usage rooms - paymentHandler + * @usage rooms - commitPaymentHandler */ const completeSendingQuest = async (userId, timestamp, roomObject) => { logger.info( From b31b7b2d2924e30bafb68f64c1e10b7078155a1d Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Wed, 27 Mar 2024 02:10:06 +0900 Subject: [PATCH 06/25] Fix: rooms.js comment --- src/services/rooms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/rooms.js b/src/services/rooms.js index 7d9f5f8d..a1a61913 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -613,7 +613,7 @@ const commitSettlementHandler = async (req, res) => { await user.save(); - // 결제 채팅을 보냅니다. + // 정산 채팅을 보냅니다. await emitChatEvent(req.app.get("io"), { roomId, type: "settlement", @@ -691,7 +691,7 @@ const commitPaymentHandler = async (req, res) => { await user.save(); - // 정산 채팅을 보냅니다. + // 송금 채팅을 보냅니다. await emitChatEvent(req.app.get("io"), { roomId, type: "payment", From d1a04f5364a9e90e5f620cf3f939242857359157 Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Thu, 28 Mar 2024 17:55:36 +0900 Subject: [PATCH 07/25] Remove: comment in chatPaymentSettlementUpdater.js --- scripts/chatPaymentSettlementUpdater.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/chatPaymentSettlementUpdater.js b/scripts/chatPaymentSettlementUpdater.js index 22f2fba3..0fa45b89 100644 --- a/scripts/chatPaymentSettlementUpdater.js +++ b/scripts/chatPaymentSettlementUpdater.js @@ -14,7 +14,6 @@ const chats = db.collection("chats"); async function run() { try { for await (const doc of chats.find()) { - // 이미 변환이 완료된 경우에는 Pass합니다. if (doc.type === "settlement" || doc.type === "payment") { await chats.findOneAndUpdate( { _id: doc._id }, From d4336874b52acf2ce7ab655264e3fb93377563da Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Thu, 28 Mar 2024 17:56:14 +0900 Subject: [PATCH 08/25] Fix: test/rooms.js --- test/services/rooms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/services/rooms.js b/test/services/rooms.js index 62d05609..4e948ad1 100644 --- a/test/services/rooms.js +++ b/test/services/rooms.js @@ -141,7 +141,7 @@ describe("[rooms] 6.searchByUserHandler", () => { }); // 7. 1분이 지난 후, 정산 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 -describe("[rooms] 7.commitsettlementHandler", () => { +describe("[rooms] 7.commitSettlementHandler", () => { it("should return information of room and commit settlement", async () => { const testUser1 = await userModel.findOne({ id: "test1" }); const testRoom = await roomModel.findOne({ name: "test-room" }); From ce501cffebaf219f1ca6bc6fbf9b5eb94eb6e91e Mon Sep 17 00:00:00 2001 From: happycastle <41810556+happycastle114@users.noreply.github.com> Date: Wed, 8 May 2024 03:08:12 +0900 Subject: [PATCH 09/25] Add: Update Logic Change --- src/services/auth.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/auth.js b/src/services/auth.js index dab7cd64..979aa686 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -58,7 +58,7 @@ const joinus = async (req, userData) => { }; const update = async (userData) => { - const updateInfo = { name: userData.name }; + const updateInfo = { name: userData.name, email: userData.email }; await userModel.updateOne({ id: userData.id }, updateInfo); }; @@ -72,7 +72,7 @@ const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { await joinus(req, userData); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } - if (user.name != userData.name) { + if (user.name != userData.name || user.email != userData.email) { await update(userData); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } From c696d7cc94a411765d20422ec33d7af6efdcd6b1 Mon Sep 17 00:00:00 2001 From: happycastle <41810556+happycastle114@users.noreply.github.com> Date: Tue, 14 May 2024 23:23:44 +0900 Subject: [PATCH 10/25] Add: Logger --- src/services/auth.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/auth.js b/src/services/auth.js index 979aa686..ffc941ee 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -60,6 +60,7 @@ const joinus = async (req, userData) => { const update = async (userData) => { const updateInfo = { name: userData.name, email: userData.email }; await userModel.updateOne({ id: userData.id }, updateInfo); + logger.info(`Update user info: ${userData.id}`); }; const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { @@ -72,7 +73,7 @@ const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { await joinus(req, userData); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } - if (user.name != userData.name || user.email != userData.email) { + if (user.name !== userData.name || user.email !== userData.email) { await update(userData); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } From e1728520b7f4781379b3602edf64e1a2bbd5ca87 Mon Sep 17 00:00:00 2001 From: happycastle <41810556+happycastle114@users.noreply.github.com> Date: Tue, 14 May 2024 23:38:41 +0900 Subject: [PATCH 11/25] Add: kaist info update --- src/services/auth.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/services/auth.js b/src/services/auth.js index ffc941ee..1220a778 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -58,7 +58,11 @@ const joinus = async (req, userData) => { }; const update = async (userData) => { - const updateInfo = { name: userData.name, email: userData.email }; + const updateInfo = { + name: userData.name, + email: userData.email, + subinfo: { kaist: userData.kaist }, + }; await userModel.updateOne({ id: userData.id }, updateInfo); logger.info(`Update user info: ${userData.id}`); }; @@ -73,7 +77,11 @@ const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { await joinus(req, userData); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } - if (user.name !== userData.name || user.email !== userData.email) { + if ( + user.name !== userData.name || + user.email !== userData.email || + user.subinfo.kaist !== userData.kaist + ) { await update(userData); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } From 65c50ef005f7a149715106a9bdebbb25d3f9de94 Mon Sep 17 00:00:00 2001 From: happycastle <41810556+happycastle114@users.noreply.github.com> Date: Tue, 14 May 2024 23:56:23 +0900 Subject: [PATCH 12/25] Fix: Change all field --- src/services/auth.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/auth.js b/src/services/auth.js index 1220a778..b23efe6b 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -61,7 +61,7 @@ const update = async (userData) => { const updateInfo = { name: userData.name, email: userData.email, - subinfo: { kaist: userData.kaist }, + "subinfo.kaist": userData.kaist, }; await userModel.updateOne({ id: userData.id }, updateInfo); logger.info(`Update user info: ${userData.id}`); @@ -71,7 +71,7 @@ const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { try { const user = await userModel.findOne( { id: userData.id }, - "_id name id withdraw ban" + "_id name email subinfo id withdraw ban" ); if (!user) { await joinus(req, userData); From e3a4ad68879396881391e65464caed4eb8a40105 Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Mon, 20 May 2024 23:36:35 +0900 Subject: [PATCH 13/25] Add: check whether user participated in rooms with send-required --- src/routes/docs/rooms.js | 10 +++ src/services/rooms.js | 142 +++++++++++++++++++++++++-------------- 2 files changed, 100 insertions(+), 52 deletions(-) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 710bf649..68b724e7 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -98,6 +98,11 @@ roomsDocs[`${apiPrefix}/create`] = { error: "Rooms/create : participating in too many rooms", }, }, + "사용자가 아직 송금하지 않은 방이 존재": { + value: { + error: "Rooms/create : user has send-required rooms", + }, + }, }, }, }, @@ -309,6 +314,11 @@ roomsDocs[`${apiPrefix}/join`] = { error: "Rooms/join : participating in too many rooms", }, }, + "사용자가 아직 송금하지 않은 방이 존재": { + value: { + error: "Rooms/join : user has send-required rooms", + }, + }, "입력한 시간의 방이 이미 출발함": { value: { error: "Rooms/join : The room has already departed", diff --git a/src/services/rooms.js b/src/services/rooms.js index cf8b6e9e..afaf398e 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -72,6 +72,14 @@ const createHandler = async (req, res) => { }); } + // 사용자가 참여한 진행중인 방 중 송금을 아직 완료하지 않은 방이 있다면 오류를 반환합니다. + const isSendRequired = checkIsSendRequired(user); + if (isSendRequired) { + return res.status(400).json({ + error: "Rooms/create : user has send-required rooms", + }); + } + const part = [{ user: user._id }]; // settlementStatus는 기본적으로 "not-departed"로 설정됨 let room = new roomModel({ @@ -114,58 +122,6 @@ const createHandler = async (req, res) => { } }; -const checkIsAbusing = ( - { from, to, time, maxPartLength }, - countRecentlyMadeRooms, - candidateRooms -) => { - /** - * 방을 생성하였을 때, 다음 조건 중 하나라도 만족하게 되면 어뷰징 가능성이 있다고 판단합니다. - * 1. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 3개 이상인 경우 - * 2. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 2개이고, 다음 조건 중 하나 이상을 만족하는 경우 - * a. 두 방의 출발 시간 간격이 1시간 이하인 경우 - * b. 두 방의 출발 시간 간격이 1시간 초과이고, 다음 조건 중 하나 이상을 만족하는 경우 - * i. 두 방의 출발지가 같은 경우 - * ii. 두 방의 목적지가 같은 경우 - * iii. 먼저 출발하는 방의 목적지와 나중에 출발하는 방의 출발지가 다른 경우 - * iv. 두 방의 최대 탑승 가능 인원이 모두 2명인 경우 - * 3. 최근 24시간 내에 생성한 방이 4개 이상인 경우 - */ - - if (countRecentlyMadeRooms + 1 >= 4) return true; // 조건 3 - - if (candidateRooms.length + 1 >= 3) return true; // 조건 1 - if (candidateRooms.length + 1 < 2) return false; // 조건 2의 여집합 - - let firstRoom = { - from: candidateRooms[0].from.toString(), - to: candidateRooms[0].to.toString(), - time: candidateRooms[0].time, - maxPartLength: candidateRooms[0].maxPartLength, - }; - let secondRoom = { - from, - to, - time: new Date(time), - maxPartLength, - }; - if (secondRoom.time < firstRoom.time) { - [firstRoom, secondRoom] = [secondRoom, firstRoom]; - } - - if (secondRoom.time - firstRoom.time <= 3600000) return true; // 조건 2-a - if ( - firstRoom.from === secondRoom.from || - firstRoom.to === secondRoom.to || - firstRoom.to !== secondRoom.from - ) - return true; // 조건 2-b-i, 2-b-ii, 2-b-iii - if (firstRoom.maxPartLength === 2 && secondRoom.maxPartLength === 2) - return true; // 조건 2-b-iv - - return false; -}; - const createTestHandler = async (req, res) => { // 이 Handler에서는 Parameter에 대해 추가적인 Validation을 하지 않습니다. const { time } = req.body; @@ -288,6 +244,14 @@ const joinHandler = async (req, res) => { }); } + // 사용자가 참여한 진행중인 방 중 송금을 아직 완료하지 않은 방이 있다면 오류를 반환합니다. + const isSendRequired = checkIsSendRequired(user); + if (isSendRequired) { + return res.status(400).json({ + error: "Rooms/join : user has send-required rooms", + }); + } + const room = await roomModel.findById(req.body.roomId); if (!room) { res.status(404).json({ @@ -721,6 +685,80 @@ const settlementHandler = async (req, res) => { } }; +const checkIsAbusing = ( + { from, to, time, maxPartLength }, + countRecentlyMadeRooms, + candidateRooms +) => { + /** + * 방을 생성하였을 때, 다음 조건 중 하나라도 만족하게 되면 어뷰징 가능성이 있다고 판단합니다. + * 1. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 3개 이상인 경우 + * 2. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 2개이고, 다음 조건 중 하나 이상을 만족하는 경우 + * a. 두 방의 출발 시간 간격이 1시간 이하인 경우 + * b. 두 방의 출발 시간 간격이 1시간 초과이고, 다음 조건 중 하나 이상을 만족하는 경우 + * i. 두 방의 출발지가 같은 경우 + * ii. 두 방의 목적지가 같은 경우 + * iii. 먼저 출발하는 방의 목적지와 나중에 출발하는 방의 출발지가 다른 경우 + * iv. 두 방의 최대 탑승 가능 인원이 모두 2명인 경우 + * 3. 최근 24시간 내에 생성한 방이 4개 이상인 경우 + */ + + if (countRecentlyMadeRooms + 1 >= 4) return true; // 조건 3 + + if (candidateRooms.length + 1 >= 3) return true; // 조건 1 + if (candidateRooms.length + 1 < 2) return false; // 조건 2의 여집합 + + let firstRoom = { + from: candidateRooms[0].from.toString(), + to: candidateRooms[0].to.toString(), + time: candidateRooms[0].time, + maxPartLength: candidateRooms[0].maxPartLength, + }; + let secondRoom = { + from, + to, + time: new Date(time), + maxPartLength, + }; + if (secondRoom.time < firstRoom.time) { + [firstRoom, secondRoom] = [secondRoom, firstRoom]; + } + + if (secondRoom.time - firstRoom.time <= 3600000) return true; // 조건 2-a + if ( + firstRoom.from === secondRoom.from || + firstRoom.to === secondRoom.to || + firstRoom.to !== secondRoom.from + ) + return true; // 조건 2-b-i, 2-b-ii, 2-b-iii + if (firstRoom.maxPartLength === 2 && secondRoom.maxPartLength === 2) + return true; // 조건 2-b-iv + + return false; +}; + +/** + * User Object가 주어졌을 때, 해당 유저가 참여한 방 중 아직 유저가 송금하지 않은 방이 있는지 확인합니다. + * @param {Object} userObject - userObject입니다. ongoingRoom 정보를 포함한 형태의 object여야 합니다. + * @return {Boolean} 송금해야 하는 방이 있는지 여부를 반환합니다. + */ +const checkIsSendRequired = async (userObject) => { + // user의 참여중인 방의 part 정보만 가져오기 + const ongoingRoomParts = userObject.ongoingRoom.map((room) => room.part); + // part에서 자신의 id에 해당하는 part만 가져오기 + const userParts = ongoingRoomParts + .map((partList) => + partList.filter((part) => part.user.equals(userObject._id)) + ) + .filter((partList) => partList.length > 0); + // 해당 part object들 중 settlementStatus가 "send-required"인 part 찾기 + const sendRequired = userParts + .map((partList) => partList[0].settlementStatus) + .filter((status) => status === "send-required"); + + return sendRequired.length > 0; +}; + /** * @todo Unused -> Maybe used in the future? */ From 1ba4833b5495e87d964769af85403994185ef988 Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Mon, 20 May 2024 23:45:16 +0900 Subject: [PATCH 14/25] Fix: remove async in checkIsSendRequired --- src/services/rooms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/rooms.js b/src/services/rooms.js index afaf398e..2e478e1b 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -742,7 +742,7 @@ const checkIsAbusing = ( * @param {Object} userObject - userObject입니다. ongoingRoom 정보를 포함한 형태의 object여야 합니다. * @return {Boolean} 송금해야 하는 방이 있는지 여부를 반환합니다. */ -const checkIsSendRequired = async (userObject) => { +const checkIsSendRequired = (userObject) => { // user의 참여중인 방의 part 정보만 가져오기 const ongoingRoomParts = userObject.ongoingRoom.map((room) => room.part); // part에서 자신의 id에 해당하는 part만 가져오기 From dc99335df3e2ad558cbf15832230e35abe4ba72d Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 21 May 2024 01:52:54 +0900 Subject: [PATCH 15/25] Add: isBanned, getBanned api implementation --- src/modules/stores/mongo.js | 37 ++++++++++++++++++++++++++++++++++++ src/routes/admin.js | 2 ++ src/routes/users.js | 6 ++++++ src/services/users.js | 38 ++++++++++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/modules/stores/mongo.js b/src/modules/stores/mongo.js index bf2a8c53..45db1f9c 100755 --- a/src/modules/stores/mongo.js +++ b/src/modules/stores/mongo.js @@ -26,6 +26,42 @@ const userSchema = Schema({ account: { type: String, default: "" }, //계좌번호 정보 }); +const banSchema = Schema({ + // 정지 시킬 사용자를 기제함. + userId: { type: mongoose.Types.ObjectId, ref: "User", required: true }, + // 정지 사유 + reason: { + type: String, + default: null, + }, + bannedAt: { + type: Date, // 정지 당한 시각 + required: true, + default: null, + }, + expireAt: { + type: Date, // 정지 만료 시각 + required: true, + default: null, + }, + services: [ + { + // 정지를 당한 서비스를 기제함 + serviceName: { + type: String, + required: true, + // 필요시 이곳에 정지를 시킬 서비스를 추가함. + enum: [ + "all", // all -> 과거/미래 모든 서비스 및 이벤트 이용 제한 + "service", // service -> 방 생성/참여 제한 + "2023-fall-event", // event -> 특정 이벤트 참여 제한 + ], + default: null, + }, + }, + ], +}); + const participantSchema = Schema({ user: { type: Schema.Types.ObjectId, ref: "User", required: true }, settlementStatus: { @@ -207,6 +243,7 @@ const connectDatabase = (mongoUrl) => { module.exports = { connectDatabase, userModel: mongoose.model("User", userSchema), + banModel: mongoose.model("Ban", banSchema), deviceTokenModel: mongoose.model("DeviceToken", deviceTokenSchema), notificationOptionModel: mongoose.model( "NotificationOption", diff --git a/src/routes/admin.js b/src/routes/admin.js index da20d60d..7cd28735 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -4,6 +4,7 @@ const AdminJSExpress = require("@adminjs/express"); const AdminJSMongoose = require("@adminjs/mongoose"); const { userModel, + banModel, roomModel, locationModel, chatModel, @@ -26,6 +27,7 @@ AdminJS.registerAdapter(AdminJSMongoose); const resources = [ userModel, + banModel, roomModel, locationModel, chatModel, diff --git a/src/routes/users.js b/src/routes/users.js index 31bde597..2006df25 100755 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -56,4 +56,10 @@ router.get("/editProfileImg/done", userHandlers.editProfileImgDoneHandler); // 프로필 이미지를 기본값으로 재설정합니다. router.get("/resetProfileImg", userHandlers.resetProfileImgHandler); +// 유저의 서비스 정지 여부를 반환합니다. +router.get("/isBanned", userHandlers.isBanned); + +// 유저의 서비스 정지 여부를 반환합니다. +router.get("/getBanRecord", userHandlers.getBanRecord); + module.exports = router; diff --git a/src/services/users.js b/src/services/users.js index 514f2b4a..486eaf2e 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -1,4 +1,4 @@ -const { userModel } = require("../modules/stores/mongo"); +const { userModel, banModel } = require("../modules/stores/mongo"); const logger = require("../modules/logger"); const aws = require("../modules/stores/aws"); @@ -200,6 +200,40 @@ const resetProfileImgHandler = async (req, res) => { } }; +const isBanned = async (req, res) => { + try { + // 현재 시각이 expireAt 보다 작고 본인인 경우(ban의 userId가 userOid랑 같은 경우)의 record를 모두 가져옴 + const now = Date.now(); + const result = await banModel.find({ + userId: req.userOid, + expireAt: { + $gte: now, + }, + }); + if (!result) { + return res.status(400).json("Users/isBanned : there is no ban record"); + } + console.log(result); + res.status(200).json({ result }); + } catch (err) { + res.status(500).send("Users/isBanned : internal server error"); + } +}; + +const getBanRecord = async (req, res) => { + try { + // 본인인 경우(ban의 userId가 userOid랑 같은 경우)의 record를 모두 가져옴 + const result = await banModel.find({ userId: req.userOid }); + if (!result) { + return res.status(400).json("Users/isBanned : there is no ban record"); + } + console.log(result); + res.status(200).json({ result }); + } catch (err) { + res.status(500).send("Users/isBanned : internal server error"); + } +}; + module.exports = { agreeOnTermsOfServiceHandler, getAgreeOnTermsOfServiceHandler, @@ -209,4 +243,6 @@ module.exports = { editProfileImgDoneHandler, resetNicknameHandler, resetProfileImgHandler, + isBanned, + getBanRecord, }; From 0e63ae7172377e02bf19478e3baf3b7f2dad16b1 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 21 May 2024 02:34:06 +0900 Subject: [PATCH 16/25] Add: swagger docs --- src/routes/docs/users.js | 138 +++++++++++++++++++++++++++++++++++++++ src/services/users.js | 6 +- 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/routes/docs/users.js b/src/routes/docs/users.js index 3cd8aa96..b85b3d27 100644 --- a/src/routes/docs/users.js +++ b/src/routes/docs/users.js @@ -329,4 +329,142 @@ usersDocs[`${apiPrefix}/resetProfileImg`] = { }, }; +usersDocs[`${apiPrefix}/isBanned`] = { + post: { + tags: [tag], + summary: "본인의 현재 정지 기록을 가져움", + description: + "정지 기록들 중 본인이고, 서버 시간을 기준으로 expireAt 보다 작은 경우에 해당하는 정지 기록을 모두 가져옴", + responses: { + 200: { + content: { + "application/json": { + schema: { + type: "array", + items: { + properties: { + userId: { + type: "string", + description: "사용자의 UUID", + example: "664b5c1bfd906295bc0639a9", + }, + reason: { + type: "string", + description: "정지 사유", + example: "미정산", + }, + bannedAt: { + type: "date", + description: "정지 당한 시각", + example: "2024-05-20 12:00", + }, + expireAt: { + type: "date", + description: "정지 만료 시각", + example: "2024-05-21 12:00", + }, + services: { + type: "array", + items: { + properties: { + serviceName: { + type: "string", + description: "정지를 당한 서비스 또는 이벤트 이름", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + 400: { + content: { + "text/html": { + example: "Users/isBanned : there is no ban record", + }, + }, + }, + 500: { + content: { + "text/html": { + example: "Users/isBanned : internal server error", + }, + }, + }, + }, + }, +}; + +usersDocs[`${apiPrefix}/getBanRecord`] = { + post: { + tags: [tag], + summary: "본인의 모든 정지 기록을 가져움", + description: + "정지 기록들 중 본인인 경우에 해당하는 정지 기록을 모두 가져옴", + responses: { + 200: { + content: { + "application/json": { + schema: { + type: "array", + items: { + properties: { + userId: { + type: "string", + description: "사용자의 UUID", + example: "664b5c1bfd906295bc0639a9", + }, + reason: { + type: "string", + description: "정지 사유", + example: "미정산", + }, + bannedAt: { + type: "date", + description: "정지 당한 시각", + example: "2024-05-20 12:00", + }, + expireAt: { + type: "date", + description: "정지 만료 시각", + example: "2024-05-21 12:00", + }, + services: { + type: "array", + items: { + properties: { + serviceName: { + type: "string", + description: "정지를 당한 서비스 또는 이벤트 이름", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + 400: { + content: { + "text/html": { + example: "Users/getBanRecord : there is no ban record", + }, + }, + }, + 500: { + content: { + "text/html": { + example: "Users/getBanRecord : internal server error", + }, + }, + }, + }, + }, +}; + module.exports = usersDocs; diff --git a/src/services/users.js b/src/services/users.js index 486eaf2e..377ddea0 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -225,12 +225,14 @@ const getBanRecord = async (req, res) => { // 본인인 경우(ban의 userId가 userOid랑 같은 경우)의 record를 모두 가져옴 const result = await banModel.find({ userId: req.userOid }); if (!result) { - return res.status(400).json("Users/isBanned : there is no ban record"); + return res + .status(400) + .json("Users/getBanRecord : there is no ban record"); } console.log(result); res.status(200).json({ result }); } catch (err) { - res.status(500).send("Users/isBanned : internal server error"); + res.status(500).send("Users/getBanRecord : internal server error"); } }; From 90014131f5f314001a7a9a215d01474178a8739c Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 21 May 2024 02:36:23 +0900 Subject: [PATCH 17/25] Fix: swagger docs --- src/routes/docs/users.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/docs/users.js b/src/routes/docs/users.js index b85b3d27..aba7dd60 100644 --- a/src/routes/docs/users.js +++ b/src/routes/docs/users.js @@ -330,7 +330,7 @@ usersDocs[`${apiPrefix}/resetProfileImg`] = { }; usersDocs[`${apiPrefix}/isBanned`] = { - post: { + get: { tags: [tag], summary: "본인의 현재 정지 기록을 가져움", description: @@ -399,7 +399,7 @@ usersDocs[`${apiPrefix}/isBanned`] = { }; usersDocs[`${apiPrefix}/getBanRecord`] = { - post: { + get: { tags: [tag], summary: "본인의 모든 정지 기록을 가져움", description: From 28be0f0e7723be28111be7b7cff816201e85ec95 Mon Sep 17 00:00:00 2001 From: happycastle <41810556+happycastle114@users.noreply.github.com> Date: Tue, 21 May 2024 23:14:46 +0900 Subject: [PATCH 18/25] Add: More logs --- src/services/auth.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services/auth.js b/src/services/auth.js index b23efe6b..15e4c0e7 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -64,7 +64,9 @@ const update = async (userData) => { "subinfo.kaist": userData.kaist, }; await userModel.updateOne({ id: userData.id }, updateInfo); - logger.info(`Update user info: ${userData.id}`); + logger.info( + `Update user info: ${userData.id} ${userData.name} ${userData.email} ${userData.kaist}` + ); }; const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { @@ -83,6 +85,9 @@ const tryLogin = async (req, res, userData, redirectOrigin, redirectPath) => { user.subinfo.kaist !== userData.kaist ) { await update(userData); + logger.info( + `Past user info: ${user.id} ${user.name} ${user.email} ${user.subinfo.kaist}` + ); return tryLogin(req, res, userData, redirectOrigin, redirectPath); } From 75b5314d2ce6b1d4e87bd4c134f3389913ab5d5a Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 28 May 2024 01:11:36 +0900 Subject: [PATCH 19/25] Refactor: code convention and resolve comments --- src/modules/stores/mongo.js | 1 + src/routes/docs/users.js | 5 +++-- src/routes/users.js | 4 ++-- src/services/users.js | 13 +++++-------- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/modules/stores/mongo.js b/src/modules/stores/mongo.js index 45db1f9c..2c9d3748 100755 --- a/src/modules/stores/mongo.js +++ b/src/modules/stores/mongo.js @@ -33,6 +33,7 @@ const banSchema = Schema({ reason: { type: String, default: null, + required: true, }, bannedAt: { type: Date, // 정지 당한 시각 diff --git a/src/routes/docs/users.js b/src/routes/docs/users.js index aba7dd60..ac8fa865 100644 --- a/src/routes/docs/users.js +++ b/src/routes/docs/users.js @@ -1,5 +1,6 @@ const tag = "users"; const apiPrefix = "/users"; +const { objectId } = require("../../modules/patterns"); const usersDocs = {}; usersDocs[`${apiPrefix}/agreeOnTermsOfService`] = { @@ -346,7 +347,7 @@ usersDocs[`${apiPrefix}/isBanned`] = { userId: { type: "string", description: "사용자의 UUID", - example: "664b5c1bfd906295bc0639a9", + pattern: objectId.source, }, reason: { type: "string", @@ -415,7 +416,7 @@ usersDocs[`${apiPrefix}/getBanRecord`] = { userId: { type: "string", description: "사용자의 UUID", - example: "664b5c1bfd906295bc0639a9", + pattern: objectId.source, }, reason: { type: "string", diff --git a/src/routes/users.js b/src/routes/users.js index 2006df25..c81534a7 100755 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -57,9 +57,9 @@ router.get("/editProfileImg/done", userHandlers.editProfileImgDoneHandler); router.get("/resetProfileImg", userHandlers.resetProfileImgHandler); // 유저의 서비스 정지 여부를 반환합니다. -router.get("/isBanned", userHandlers.isBanned); +router.get("/isBanned", userHandlers.isBannedHandler); // 유저의 서비스 정지 여부를 반환합니다. -router.get("/getBanRecord", userHandlers.getBanRecord); +router.get("/getBanRecord", userHandlers.getBanRecordHandler); module.exports = router; diff --git a/src/services/users.js b/src/services/users.js index 377ddea0..b65dfa31 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -200,27 +200,25 @@ const resetProfileImgHandler = async (req, res) => { } }; -const isBanned = async (req, res) => { +const isBannedHandler = async (req, res) => { try { // 현재 시각이 expireAt 보다 작고 본인인 경우(ban의 userId가 userOid랑 같은 경우)의 record를 모두 가져옴 - const now = Date.now(); const result = await banModel.find({ userId: req.userOid, expireAt: { - $gte: now, + $gte: req.timestamp, }, }); if (!result) { return res.status(400).json("Users/isBanned : there is no ban record"); } - console.log(result); res.status(200).json({ result }); } catch (err) { res.status(500).send("Users/isBanned : internal server error"); } }; -const getBanRecord = async (req, res) => { +const getBanRecordHandler = async (req, res) => { try { // 본인인 경우(ban의 userId가 userOid랑 같은 경우)의 record를 모두 가져옴 const result = await banModel.find({ userId: req.userOid }); @@ -229,7 +227,6 @@ const getBanRecord = async (req, res) => { .status(400) .json("Users/getBanRecord : there is no ban record"); } - console.log(result); res.status(200).json({ result }); } catch (err) { res.status(500).send("Users/getBanRecord : internal server error"); @@ -245,6 +242,6 @@ module.exports = { editProfileImgDoneHandler, resetNicknameHandler, resetProfileImgHandler, - isBanned, - getBanRecord, + isBannedHandler, + getBanRecordHandler, }; From fc365c46db3182891c46fb960970e442b9746b31 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 28 May 2024 03:03:52 +0900 Subject: [PATCH 20/25] Refactor: resolve comments --- src/modules/stores/mongo.js | 4 ---- src/routes/users.js | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/modules/stores/mongo.js b/src/modules/stores/mongo.js index 2c9d3748..6bc93246 100755 --- a/src/modules/stores/mongo.js +++ b/src/modules/stores/mongo.js @@ -32,18 +32,15 @@ const banSchema = Schema({ // 정지 사유 reason: { type: String, - default: null, required: true, }, bannedAt: { type: Date, // 정지 당한 시각 required: true, - default: null, }, expireAt: { type: Date, // 정지 만료 시각 required: true, - default: null, }, services: [ { @@ -57,7 +54,6 @@ const banSchema = Schema({ "service", // service -> 방 생성/참여 제한 "2023-fall-event", // event -> 특정 이벤트 참여 제한 ], - default: null, }, }, ], diff --git a/src/routes/users.js b/src/routes/users.js index c81534a7..d5366155 100755 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -56,10 +56,10 @@ router.get("/editProfileImg/done", userHandlers.editProfileImgDoneHandler); // 프로필 이미지를 기본값으로 재설정합니다. router.get("/resetProfileImg", userHandlers.resetProfileImgHandler); -// 유저의 서비스 정지 여부를 반환합니다. +// 유저의 현재 유효한 서비스 정지 기록들만 반환합니다. router.get("/isBanned", userHandlers.isBannedHandler); -// 유저의 서비스 정지 여부를 반환합니다. +// 유저의 서비스 정지 기록들을 모두 반환합니다. router.get("/getBanRecord", userHandlers.getBanRecordHandler); module.exports = router; From 2bd12af6106f4289942175852af44d2799bc0834 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 28 May 2024 03:45:07 +0900 Subject: [PATCH 21/25] Refactor: resolve comments --- src/routes/docs/users.js | 4 ++-- src/services/users.js | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/routes/docs/users.js b/src/routes/docs/users.js index ac8fa865..deaeb113 100644 --- a/src/routes/docs/users.js +++ b/src/routes/docs/users.js @@ -346,7 +346,7 @@ usersDocs[`${apiPrefix}/isBanned`] = { properties: { userId: { type: "string", - description: "사용자의 UUID", + description: "사용자의 ObjectId", pattern: objectId.source, }, reason: { @@ -415,7 +415,7 @@ usersDocs[`${apiPrefix}/getBanRecord`] = { properties: { userId: { type: "string", - description: "사용자의 UUID", + description: "사용자의 ObjectId", pattern: objectId.source, }, reason: { diff --git a/src/services/users.js b/src/services/users.js index b65dfa31..2fd8eec5 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -209,10 +209,9 @@ const isBannedHandler = async (req, res) => { $gte: req.timestamp, }, }); - if (!result) { - return res.status(400).json("Users/isBanned : there is no ban record"); - } - res.status(200).json({ result }); + if (!result) + return res.status(500).send("Users/getBanRecord : internal server error"); + res.status(200).json(result); } catch (err) { res.status(500).send("Users/isBanned : internal server error"); } @@ -222,12 +221,9 @@ const getBanRecordHandler = async (req, res) => { try { // 본인인 경우(ban의 userId가 userOid랑 같은 경우)의 record를 모두 가져옴 const result = await banModel.find({ userId: req.userOid }); - if (!result) { - return res - .status(400) - .json("Users/getBanRecord : there is no ban record"); - } - res.status(200).json({ result }); + if (!result) + return res.status(500).send("Users/getBanRecord : internal server error"); + res.status(200).json(result); } catch (err) { res.status(500).send("Users/getBanRecord : internal server error"); } From 323c09a8f26ed3ed867acc4f62d770c2e1140f40 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Tue, 28 May 2024 03:46:35 +0900 Subject: [PATCH 22/25] Fix: wrong comment --- src/services/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/users.js b/src/services/users.js index 2fd8eec5..5d8ee632 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -210,7 +210,7 @@ const isBannedHandler = async (req, res) => { }, }); if (!result) - return res.status(500).send("Users/getBanRecord : internal server error"); + return res.status(500).send("Users/isBanned : internal server error"); res.status(200).json(result); } catch (err) { res.status(500).send("Users/isBanned : internal server error"); From f9eb6013a0a071751156b653281093cd9510bcc1 Mon Sep 17 00:00:00 2001 From: static Date: Tue, 28 May 2024 22:46:29 +0900 Subject: [PATCH 23/25] =?UTF-8?q?Revert=20"#517=20=EB=AF=B8=EC=A0=95?= =?UTF-8?q?=EC=82=B0=20=EC=8B=9C=20=EB=B0=A9=20=EC=83=9D=EC=84=B1/?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=20=EC=B0=A8=EB=8B=A8"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/docs/rooms.js | 10 --- src/services/rooms.js | 142 ++++++++++++++------------------------- 2 files changed, 52 insertions(+), 100 deletions(-) diff --git a/src/routes/docs/rooms.js b/src/routes/docs/rooms.js index 68b724e7..710bf649 100644 --- a/src/routes/docs/rooms.js +++ b/src/routes/docs/rooms.js @@ -98,11 +98,6 @@ roomsDocs[`${apiPrefix}/create`] = { error: "Rooms/create : participating in too many rooms", }, }, - "사용자가 아직 송금하지 않은 방이 존재": { - value: { - error: "Rooms/create : user has send-required rooms", - }, - }, }, }, }, @@ -314,11 +309,6 @@ roomsDocs[`${apiPrefix}/join`] = { error: "Rooms/join : participating in too many rooms", }, }, - "사용자가 아직 송금하지 않은 방이 존재": { - value: { - error: "Rooms/join : user has send-required rooms", - }, - }, "입력한 시간의 방이 이미 출발함": { value: { error: "Rooms/join : The room has already departed", diff --git a/src/services/rooms.js b/src/services/rooms.js index 2e478e1b..cf8b6e9e 100644 --- a/src/services/rooms.js +++ b/src/services/rooms.js @@ -72,14 +72,6 @@ const createHandler = async (req, res) => { }); } - // 사용자가 참여한 진행중인 방 중 송금을 아직 완료하지 않은 방이 있다면 오류를 반환합니다. - const isSendRequired = checkIsSendRequired(user); - if (isSendRequired) { - return res.status(400).json({ - error: "Rooms/create : user has send-required rooms", - }); - } - const part = [{ user: user._id }]; // settlementStatus는 기본적으로 "not-departed"로 설정됨 let room = new roomModel({ @@ -122,6 +114,58 @@ const createHandler = async (req, res) => { } }; +const checkIsAbusing = ( + { from, to, time, maxPartLength }, + countRecentlyMadeRooms, + candidateRooms +) => { + /** + * 방을 생성하였을 때, 다음 조건 중 하나라도 만족하게 되면 어뷰징 가능성이 있다고 판단합니다. + * 1. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 3개 이상인 경우 + * 2. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 2개이고, 다음 조건 중 하나 이상을 만족하는 경우 + * a. 두 방의 출발 시간 간격이 1시간 이하인 경우 + * b. 두 방의 출발 시간 간격이 1시간 초과이고, 다음 조건 중 하나 이상을 만족하는 경우 + * i. 두 방의 출발지가 같은 경우 + * ii. 두 방의 목적지가 같은 경우 + * iii. 먼저 출발하는 방의 목적지와 나중에 출발하는 방의 출발지가 다른 경우 + * iv. 두 방의 최대 탑승 가능 인원이 모두 2명인 경우 + * 3. 최근 24시간 내에 생성한 방이 4개 이상인 경우 + */ + + if (countRecentlyMadeRooms + 1 >= 4) return true; // 조건 3 + + if (candidateRooms.length + 1 >= 3) return true; // 조건 1 + if (candidateRooms.length + 1 < 2) return false; // 조건 2의 여집합 + + let firstRoom = { + from: candidateRooms[0].from.toString(), + to: candidateRooms[0].to.toString(), + time: candidateRooms[0].time, + maxPartLength: candidateRooms[0].maxPartLength, + }; + let secondRoom = { + from, + to, + time: new Date(time), + maxPartLength, + }; + if (secondRoom.time < firstRoom.time) { + [firstRoom, secondRoom] = [secondRoom, firstRoom]; + } + + if (secondRoom.time - firstRoom.time <= 3600000) return true; // 조건 2-a + if ( + firstRoom.from === secondRoom.from || + firstRoom.to === secondRoom.to || + firstRoom.to !== secondRoom.from + ) + return true; // 조건 2-b-i, 2-b-ii, 2-b-iii + if (firstRoom.maxPartLength === 2 && secondRoom.maxPartLength === 2) + return true; // 조건 2-b-iv + + return false; +}; + const createTestHandler = async (req, res) => { // 이 Handler에서는 Parameter에 대해 추가적인 Validation을 하지 않습니다. const { time } = req.body; @@ -244,14 +288,6 @@ const joinHandler = async (req, res) => { }); } - // 사용자가 참여한 진행중인 방 중 송금을 아직 완료하지 않은 방이 있다면 오류를 반환합니다. - const isSendRequired = checkIsSendRequired(user); - if (isSendRequired) { - return res.status(400).json({ - error: "Rooms/join : user has send-required rooms", - }); - } - const room = await roomModel.findById(req.body.roomId); if (!room) { res.status(404).json({ @@ -685,80 +721,6 @@ const settlementHandler = async (req, res) => { } }; -const checkIsAbusing = ( - { from, to, time, maxPartLength }, - countRecentlyMadeRooms, - candidateRooms -) => { - /** - * 방을 생성하였을 때, 다음 조건 중 하나라도 만족하게 되면 어뷰징 가능성이 있다고 판단합니다. - * 1. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 3개 이상인 경우 - * 2. 참여한 방 중, 생성하려는 방의 출발 시간 앞 뒤 12시간 내에 출발하는 방이 2개이고, 다음 조건 중 하나 이상을 만족하는 경우 - * a. 두 방의 출발 시간 간격이 1시간 이하인 경우 - * b. 두 방의 출발 시간 간격이 1시간 초과이고, 다음 조건 중 하나 이상을 만족하는 경우 - * i. 두 방의 출발지가 같은 경우 - * ii. 두 방의 목적지가 같은 경우 - * iii. 먼저 출발하는 방의 목적지와 나중에 출발하는 방의 출발지가 다른 경우 - * iv. 두 방의 최대 탑승 가능 인원이 모두 2명인 경우 - * 3. 최근 24시간 내에 생성한 방이 4개 이상인 경우 - */ - - if (countRecentlyMadeRooms + 1 >= 4) return true; // 조건 3 - - if (candidateRooms.length + 1 >= 3) return true; // 조건 1 - if (candidateRooms.length + 1 < 2) return false; // 조건 2의 여집합 - - let firstRoom = { - from: candidateRooms[0].from.toString(), - to: candidateRooms[0].to.toString(), - time: candidateRooms[0].time, - maxPartLength: candidateRooms[0].maxPartLength, - }; - let secondRoom = { - from, - to, - time: new Date(time), - maxPartLength, - }; - if (secondRoom.time < firstRoom.time) { - [firstRoom, secondRoom] = [secondRoom, firstRoom]; - } - - if (secondRoom.time - firstRoom.time <= 3600000) return true; // 조건 2-a - if ( - firstRoom.from === secondRoom.from || - firstRoom.to === secondRoom.to || - firstRoom.to !== secondRoom.from - ) - return true; // 조건 2-b-i, 2-b-ii, 2-b-iii - if (firstRoom.maxPartLength === 2 && secondRoom.maxPartLength === 2) - return true; // 조건 2-b-iv - - return false; -}; - -/** - * User Object가 주어졌을 때, 해당 유저가 참여한 방 중 아직 유저가 송금하지 않은 방이 있는지 확인합니다. - * @param {Object} userObject - userObject입니다. ongoingRoom 정보를 포함한 형태의 object여야 합니다. - * @return {Boolean} 송금해야 하는 방이 있는지 여부를 반환합니다. - */ -const checkIsSendRequired = (userObject) => { - // user의 참여중인 방의 part 정보만 가져오기 - const ongoingRoomParts = userObject.ongoingRoom.map((room) => room.part); - // part에서 자신의 id에 해당하는 part만 가져오기 - const userParts = ongoingRoomParts - .map((partList) => - partList.filter((part) => part.user.equals(userObject._id)) - ) - .filter((partList) => partList.length > 0); - // 해당 part object들 중 settlementStatus가 "send-required"인 part 찾기 - const sendRequired = userParts - .map((partList) => partList[0].settlementStatus) - .filter((status) => status === "send-required"); - - return sendRequired.length > 0; -}; - /** * @todo Unused -> Maybe used in the future? */ From 0a91f62df548d0c077be12d9b7dbed5f34b7166e Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Tue, 28 May 2024 23:04:46 +0900 Subject: [PATCH 24/25] Fix: minor changes --- scripts/chatPaymentSettlementUpdater.js | 2 -- src/lottery/modules/contracts.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/chatPaymentSettlementUpdater.js b/scripts/chatPaymentSettlementUpdater.js index 0fa45b89..76e43682 100644 --- a/scripts/chatPaymentSettlementUpdater.js +++ b/scripts/chatPaymentSettlementUpdater.js @@ -5,8 +5,6 @@ const { MongoClient } = require("mongodb"); const { mongo: mongoUrl } = require("../loadenv"); -const time = Date.now(); - const client = new MongoClient(mongoUrl); const db = client.db("taxi"); const chats = db.collection("chats"); diff --git a/src/lottery/modules/contracts.js b/src/lottery/modules/contracts.js index 93d43e23..72a62deb 100644 --- a/src/lottery/modules/contracts.js +++ b/src/lottery/modules/contracts.js @@ -127,7 +127,7 @@ const completeFirstLoginQuest = async (userId, timestamp) => { * @param {Date} roomObject.time - 출발 시각입니다. * @returns {Promise} * @description 정산 요청 또는 송금이 이루어질 때마다 호출해 주세요. - * @usage rooms - commitPaymentHandler, rooms - commitSettlementHandler + * @usage rooms - commitSettlementHandler, rooms - commitPaymentHandler */ const completePayingAndSendingQuest = async (userId, timestamp, roomObject) => { logger.info( From 6cedcf91bc7c66487fcc297974265ff70cbba7dd Mon Sep 17 00:00:00 2001 From: happycastle <41810556+happycastle114@users.noreply.github.com> Date: Tue, 28 May 2024 23:31:21 +0900 Subject: [PATCH 25/25] Fix: Change KAIST Info Mail --- src/services/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/auth.js b/src/services/auth.js index 15e4c0e7..fdca15dd 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -33,7 +33,7 @@ const transUserData = (userData) => { twitter: userData.twitter_id || "", kaist: kaistInfo?.ku_std_no || "", sparcs: userData.sparcs_id || "", - email: userData.email, + email: kaistInfo?.mail || userData.email, isEligible: userPattern.allowedEmployeeTypes.test(kaistInfo?.employeeType), }; return info;