Skip to content

Commit

Permalink
Merge branch 'dev' into #539-방-생성시-어뷰징-사전검증-처리-방식-개선
Browse files Browse the repository at this point in the history
  • Loading branch information
cokia authored Sep 5, 2024
2 parents 2419698 + 30ff291 commit 677231b
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 130 deletions.
92 changes: 92 additions & 0 deletions src/lottery/routes/docs/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,92 @@ itemsDocs[`${apiPrefix}/`] = {
},
},
};
itemsDocs[`${apiPrefix}/{itemId}`] = {
get: {
tags: [`${apiPrefix}`],
summary: "상점에서 판매하는 특정 상품의 정보 반환",
description: "상점에서 판매하는 특정 상품의 정보를 가져옵니다.",
parameters: [
{
in: "path",
name: "itemId",
required: true,
description: "상품 정보를 조회할 ObjectId",
example: "ITEM ID",
},
],
responses: {
200: {
content: {
"application/json": {
schema: {
type: "object",
required: ["item"],
properties: {
item: {
type: "object",
required: [
"_id",
"name",
"description",
"imageUrl",
"price",
"isDisabled",
"itemType",
],
description: "상품의 정보",
properties: {
_id: {
type: "string",
description: "상품의 ObjectId",
example: "ITEM ID",
},
name: {
type: "string",
description: "상품의 이름",
example: "진짜 송편",
},
description: {
type: "string",
description: "상품의 설명",
example: "먹을 수 있는 송편입니다.",
},
imageUrl: {
type: "string",
description: "상품의 썸네일 이미지 URL",
example: "THUMBNAIL URL",
},
instagramStoryStickerImageUrl: {
type: "string",
description: "인스타그램 스토리 스티커 이미지 URL",
example: "STICKER URL",
},
price: {
type: "number",
description: "상품의 가격. 0 이상의 정수입니다.",
example: 400,
},
isDisabled: {
type: "boolean",
description: "상품의 판매 중지 여부",
example: false,
},
itemType: {
type: "number",
description:
"상품의 유형. 0: 일반 상품, 1: 일반 티켓, 2: 고급 티켓, 3: 랜덤박스입니다.",
example: 0,
},
},
},
},
},
},
},
},
},
},
};
itemsDocs[`${apiPrefix}/leaderboard/{itemId}`] = {
get: {
tags: [`${apiPrefix}`],
Expand Down Expand Up @@ -114,6 +200,7 @@ itemsDocs[`${apiPrefix}/leaderboard/{itemId}`] = {
"profileImageUrl",
"amount",
"probability",
"rank",
],
properties: {
nickname: {
Expand All @@ -136,6 +223,11 @@ itemsDocs[`${apiPrefix}/leaderboard/{itemId}`] = {
description: "유저가 상품에 당첨될 확률",
example: 0.1,
},
rank: {
type: "number",
description: "순위",
example: 1,
},
},
},
},
Expand Down
3 changes: 3 additions & 0 deletions src/lottery/routes/docs/schemas/itemsSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ const { zodToSchemaObject } = require("../../../../routes/docs/utils");
const { objectId } = require("../../../../modules/patterns");

const itemsZod = {
getItemHandler: z.object({
itemId: z.string().regex(objectId),
}),
getItemLeaderboardHandler: z.object({
itemId: z.string().regex(objectId),
}),
Expand Down
5 changes: 5 additions & 0 deletions src/lottery/routes/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const { itemsZod } = require("./docs/schemas/itemsSchema");
const itemsHandlers = require("../services/items");

router.get("/", itemsHandlers.getItemsHandler);
router.get(
"/:itemId",
validateParams(itemsZod.getItemHandler),
itemsHandlers.getItemHandler
);
router.get(
"/leaderboard/:itemId",
validateParams(itemsZod.getItemLeaderboardHandler),
Expand Down
20 changes: 20 additions & 0 deletions src/lottery/services/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ const getItemsHandler = async (req, res) => {
}
};

const getItemHandler = async (req, res) => {
try {
const { itemId } = req.params;
const item = await itemModel
.findById(
itemId,
"_id name description imageUrl instagramStoryStickerImageUrl price isDisabled itemType"
)
.lean();
if (!item) return res.status(400).json({ error: "Items/ : invalid item" });

res.json({ item });
} catch (err) {
logger.error(err);
res.status(500).json({ error: "Items/ : internal server error" });
}
};

// 유도 과정은 services/publicNotice.js 파일에 정의된 calculateProbabilityV2 함수의 주석 참조
const calculateWinProbability = (realStock, users, amount, totalAmount) => {
if (users.length <= realStock) return 1;
Expand Down Expand Up @@ -113,6 +131,7 @@ const getItemLeaderboardHandler = async (req, res) => {
profileImageUrl: userInfo.profileImageUrl,
amount: user.amount,
probability: user.probability,
rank: user.rank,
};
})
);
Expand Down Expand Up @@ -363,6 +382,7 @@ const purchaseItemHandler = async (req, res) => {

module.exports = {
getItemsHandler,
getItemHandler,
getItemLeaderboardHandler,
purchaseItemHandler,
};
19 changes: 19 additions & 0 deletions src/middlewares/ban.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { validateServiceBanRecord } = require("../modules/ban");

const serviceMapper = new Map([
["/rooms/create", "service"],
["/rooms/join", "service"],
]);

const banMiddleware = async (req, res, next) => {
const banErrorMessage = await validateServiceBanRecord(
req,
serviceMapper.get(req.originalUrl)
);
if (banErrorMessage !== undefined) {
return res.status(400).json({ error: banErrorMessage });
}
next();
};

module.exports = banMiddleware;
45 changes: 45 additions & 0 deletions src/modules/ban.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const logger = require("./logger");
const { banModel } = require("./stores/mongo");

/**
* @param {*} req
* @param {String} service
*/
const validateServiceBanRecord = async (req, service) => {
let banRecord = undefined;

try {
// 현재 시각이 expireAt 보다 작고, 본인인 경우(ban의 userId가 userId랑 같은 경우) 중 serviceName이 "service"인 record를 모두 가져옴
const bans = await banModel
.find({
userSid: req.session.loginInfo.sid,
expireAt: {
$gte: req.timestamp,
},
serviceName: service,
})
.sort({ expireAt: -1 });
if (bans.length > 0) {
// 가장 expireAt이 큰 정지 기록만 반환함.
banRecord = bans[0];
}
} catch (err) {
logger.error(
"Error occured while validateServiceBanRecord: " + err.message
);
return;
}
if (banRecord !== undefined) {
const formattedExpireAt = banRecord.expireAt
.toISOString()
.replace("T", " ")
.split(".")[0];
const banErrorMessage = `${req.originalUrl} : user ${req.userId} (${req.session.loginInfo.sid}) is temporarily restricted from service until ${formattedExpireAt}.`;
return banErrorMessage;
}
return;
};

module.exports = {
validateServiceBanRecord,
};
36 changes: 11 additions & 25 deletions src/modules/stores/mongo.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,21 @@ const userSchema = Schema({

const banSchema = Schema({
// 정지 시킬 사용자를 기제함.
userId: { type: mongoose.Types.ObjectId, ref: "User", required: true },
userSid: { type: String, required: true },
// 정지 사유
reason: {
reason: { type: String, required: true },
bannedAt: { type: Date, required: true }, // 정지 당한 시각
expireAt: { type: Date, required: true }, // 정지 만료 시각
// 정지를 당한 서비스를 기제함
serviceName: {
type: String,
required: true,
// 필요시 이곳에 정지를 시킬 서비스를 추가함.
enum: [
"service", // service: 방 생성/참여 제한
"2023-fall-event", // xxxx-xxxx-event: 특정 이벤트 참여 제한
],
},
bannedAt: {
type: Date, // 정지 당한 시각
required: true,
},
expireAt: {
type: Date, // 정지 만료 시각
required: true,
},
services: [
{
// 정지를 당한 서비스를 기제함
serviceName: {
type: String,
required: true,
// 필요시 이곳에 정지를 시킬 서비스를 추가함.
enum: [
"all", // all -> 과거/미래 모든 서비스 및 이벤트 이용 제한
"service", // service -> 방 생성/참여 제한
"2023-fall-event", // event -> 특정 이벤트 참여 제한
],
},
},
],
});

const participantSchema = Schema({
Expand Down
12 changes: 12 additions & 0 deletions src/routes/docs/rooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ roomsDocs[`${apiPrefix}/create`] = {
},
},
examples: {
"방 생성 기능이 정지당한 경우": {
value: {
error:
"Rooms/join : user monday is temporarily restricted from creating rooms until 2024-08-23 15:00:00.",
},
},
"출발지와 도착지가 같음": {
value: {
error: "Rooms/create : locations are same",
Expand Down Expand Up @@ -309,6 +315,12 @@ roomsDocs[`${apiPrefix}/join`] = {
},
},
examples: {
"방 참여 기능이 정지당한 경우": {
value: {
error:
"Rooms/join : user monday is temporarily restricted from joining rooms until 2024-08-23 15:00:00.",
},
},
"사용자가 참여하는 진행 중 방이 5개 이상": {
value: {
error: "Rooms/join : participating in too many rooms",
Expand Down
Loading

0 comments on commit 677231b

Please sign in to comment.