Skip to content

Commit

Permalink
Merge pull request #543 from sparcs-kaist/dev
Browse files Browse the repository at this point in the history
Main branch update from Dev branch
  • Loading branch information
kmc7468 authored Sep 5, 2024
2 parents e29f1f3 + 30ff291 commit d876254
Show file tree
Hide file tree
Showing 39 changed files with 1,221 additions and 929 deletions.
13 changes: 12 additions & 1 deletion loadenv.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,18 @@ module.exports = {
slackWebhookUrl: {
report: process.env.SLACK_REPORT_WEBHOOK_URL || "", // optional
},
eventConfig: process.env.EVENT_CONFIG && JSON.parse(process.env.EVENT_CONFIG), // optional
eventConfig: (process.env.EVENT_CONFIG &&
JSON.parse(process.env.EVENT_CONFIG)) || {
mode: "2024fall",
credit: {
name: "송편코인",
initialAmount: 0,
},
period: {
startAt: new Date("2024-09-07T00:00:00+09:00"),
endAt: new Date("2024-09-24T00:00:00+09:00"),
},
}, // optional
naverMap: {
apiId: process.env.NAVER_MAP_API_ID, // optional
apiKey: process.env.NAVER_MAP_API_KEY, //optional
Expand Down
4 changes: 2 additions & 2 deletions src/lottery/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ lotteryRouter.use(require("../middlewares/originValidator"));

// [Router] APIs
lotteryRouter.use("/globalState", require("./routes/globalState"));
lotteryRouter.use("/invite", require("./routes/invite"));
lotteryRouter.use("/invites", require("./routes/invites"));
lotteryRouter.use("/transactions", require("./routes/transactions"));
lotteryRouter.use("/items", require("./routes/items"));
lotteryRouter.use("/publicNotice", require("./routes/publicNotice"));
// lotteryRouter.use("/publicNotice", require("./routes/publicNotice"));
lotteryRouter.use("/quests", require("./routes/quests"));

// [AdminJS] AdminJS에 표시할 Resource 생성
Expand Down
150 changes: 58 additions & 92 deletions src/lottery/modules/contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,53 +13,44 @@ const quests = buildQuests({
firstLogin: {
name: "첫 발걸음",
description:
"로그인만 해도 넙죽코인을 얻을 수 있다고?? 이벤트 기간에 처음으로 SPARCS Taxi 서비스에 로그인하여 넙죽코인을 받아보세요.",
"이벤트 참여만 해도 송편코인을 얻을 수 있다고?? 이벤트 참여에 동의하고 송편코인을 받아 보세요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_firstLogin.png",
reward: 50,
},
payingAndSending: {
name: "함께하는 택시의 여정",
description:
"2명 이상과 함께 택시를 타고 정산/송금까지 완료해보세요. 최대 3번까지 넙죽코인을 받을 수 있어요. 정산/송금 버튼은 채팅 페이지 좌측 하단의 <b>+버튼</b>을 눌러 확인할 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_payingAndSending.png",
reward: 150,
maxCount: 0,
reward: 200,
},
firstRoomCreation: {
name: "첫 방 개설",
description:
"원하는 택시팟을 찾을 수 없다면? 원하는 조건으로 <b>방 개설 페이지</b>에서 방을 직접 개설해보세요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_firstRoomCreation.png",
reward: 50,
reward: 500,
},
roomSharing: {
name: "너 T야? Taxi",
name: "이 택시팟은 진짜 유명한 택시팟임",
description:
"방을 공유해 친구들을 택시에 초대해보세요. 채팅창 상단의 햄버거(☰) 버튼을 누르면 <b>공유하기</b> 버튼을 찾을 수 있어요.",
"방을 공유해 친구들을 택시팟에 초대해 보세요. 채팅창 상단의 햄버거(☰) 버튼을 누르면 <b>공유하기 버튼</b> 찾을 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_roomSharing.png",
reward: 50,
reward: 500,
isApiRequired: true,
},
paying: {
name: "정산해요 택시의 숲",
fareSettlement: {
name: "정산의 신, 신팍스",
description:
"2명 이상과 함께 택시를 타고 택시비를 결제한 후 정산하기를 요청해보세요. 정산하기 버튼은 채팅 페이지 좌측 하단의 <b>+버튼</b>을 눌러 확인할 수 있어요.",
"2명 이상과 함께 택시를 타고 택시비를 결제한 후 정산을 요청해 보세요. 정산하기 버튼은 채팅 페이지 좌측 하단의 <b>+ 버튼</b>을 눌러 찾을 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_paying.png",
reward: 100,
reward: 2000,
maxCount: 0,
},
sending: {
farePayment: {
name: "송금 완료면 I am 신뢰에요",
description:
"2명 이상과 함께 택시를 타고 택시비를 결제한 분께 송금해주세요. 송금하기 버튼은 채팅 페이지 좌측 하단의 <b>+버튼</b>을 눌러 확인할 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_sending.png",
reward: 50,
reward: 2000,
maxCount: 0,
},
nicknameChanging: {
Expand All @@ -68,41 +59,46 @@ const quests = buildQuests({
"닉네임을 변경하여 자신을 표현하세요. <b>마이페이지</b>의 <b>수정하기</b> 버튼을 눌러 닉네임을 수정할 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_nicknameChanging.png",
reward: 50,
reward: 500,
},
accountChanging: {
name: "계좌 등록을 해야 능률이 올라갑니다",
description:
"정산하기 기능을 더욱 빠르고 이용할 수 있다고? 계좌번호를 등록하면 정산하기를 할 때 계좌가 자동으로 입력돼요. <b>마이페이지</b>의 <b>수정하기</b> 버튼을 눌러 계좌번호를 등록 또는 수정할 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_accountChanging.png",
reward: 50,
reward: 500,
},
adPushAgreement: {
name: "Taxi의 소울메이트",
description:
"Taxi 서비스를 잊지 않도록 가끔 찾아갈게요! 광고성 푸시 알림 수신 동의를 해주시면 방이 많이 모이는 시즌, 주변에 택시앱 사용자가 있을 때 알려드릴 수 있어요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_adPushAgreement.png",
reward: 50,
reward: 500,
},
eventSharing: {
name: "너 나랑 ㅌ태태택 (1명)",
description:
"내가 초대한 사람이 Taxi에 가입하여 이벤트에 참여하면 넙죽코인을 드려요. 내가 초대한 사람도 넙죽코인을 받아요. 이벤트 안내 페이지의 <b>이벤트 공유하기</b> 버튼을 통해 카카오톡으로 초대 문자를 보낼 수 있어요!",
name: "Taxi를 아십니까",
description: "내가 초대한 사람이 이벤트에 참여하면 송편코인을 드려요.",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_eventSharing.png",
reward: 50,
reward: 700,
maxCount: 0,
},
eventSharing5: {
name: "너 나랑 ㅌ태태택 (5명)",
dailyAttendance: {
name: "하루 한 번 Taxi!",
description:
"내가 초대한 사람이 5명이 Taxi에 가입하여 이벤트에 참여하면 넙죽코인을 드려요. 내가 초대한 사람도 넙죽코인을 받아요. 이벤트 안내 페이지의 <b>이벤트 공유하기</b> 버튼을 통해 카카오톡으로 초대 문자를 보낼 수 있어요!",
imageUrl:
"https://sparcs-taxi-prod.s3.ap-northeast-2.amazonaws.com/assets/event-2024spring/quest_eventSharing.png",
reward: 250,
maxCount: 0,
"매일 Taxi에 접속하여 출석 체크를 하면 송편코인을 드려요! 하루에 한 번, 택시팟도 둘러보고 송편코인도 받아 가세요. 송편코인을 얻으려면 출석 체크 페이지에서 <b>출석 버튼</b>을 눌러야 해요.",
imageUrl: "",
reward: 700,
maxCount: 17,
isApiRequired: true,
},
itemPurchase: {
name: "itemPurchase",
description: "itemPurchase",
imageUrl: "",
reward: 500,
},
});

Expand All @@ -111,40 +107,12 @@ const quests = buildQuests({
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @returns {Promise}
* @usage lottery/globalState/createUserGlobalStateHandler
* @usage lottery/globalState - createUserGlobalStateHandler
*/
const completeFirstLoginQuest = async (userId, timestamp) => {
return await completeQuest(userId, timestamp, quests.firstLogin);
};

/**
* payingAndSending 퀘스트의 완료를 요청합니다. 방의 참가자 수가 2명 미만이면 요청하지 않습니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @param {Object} roomObject - 방의 정보입니다.
* @param {mongoose.Types.ObjectId} roomObject._id - 방의 ObjectId입니다.
* @param {Array<{ user: mongoose.Types.ObjectId }>} roomObject.part - 참여자 목록입니다.
* @param {Date} roomObject.time - 출발 시각입니다.
* @returns {Promise}
* @description 정산 요청 또는 송금이 이루어질 때마다 호출해 주세요.
* @usage rooms - commitSettlementHandler, rooms - commitPaymentHandler
*/
const completePayingAndSendingQuest = async (userId, timestamp, roomObject) => {
logger.info(
`User ${userId} requested to complete payingAndSendingQuest in Room ${roomObject._id}`
);

if (roomObject.part.length < 2) return null;
if (
!eventPeriod ||
roomObject.time >= eventPeriod.endAt ||
roomObject.time < eventPeriod.startAt
)
return null; // 택시 출발 시각이 이벤트 기간 내에 포함되지 않는 경우 퀘스트 완료 요청을 하지 않습니다.

return await completeQuest(userId, timestamp, quests.payingAndSending);
};

/**
* firstRoomCreation 퀘스트의 완료를 요청합니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
Expand All @@ -158,7 +126,7 @@ const completeFirstRoomCreationQuest = async (userId, timestamp) => {
};

/**
* paying 퀘스트의 완료를 요청합니다. 방의 참가자 수가 2명 미만이면 요청하지 않습니다.
* fareSettlement 퀘스트의 완료를 요청합니다. 방의 참가자 수가 2명 미만이면 요청하지 않습니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @param {Object} roomObject - 방의 정보입니다.
Expand All @@ -169,9 +137,9 @@ const completeFirstRoomCreationQuest = async (userId, timestamp) => {
* @description 정산 요청이 이루어질 때마다 호출해 주세요.
* @usage rooms - commitSettlementHandler
*/
const completePayingQuest = async (userId, timestamp, roomObject) => {
const completeFareSettlementQuest = async (userId, timestamp, roomObject) => {
logger.info(
`User ${userId} requested to complete payingQuest in Room ${roomObject._id}`
`User ${userId} requested to complete fareSettlementQuest in Room ${roomObject._id}`
);

if (roomObject.part.length < 2) return null;
Expand All @@ -182,11 +150,11 @@ const completePayingQuest = async (userId, timestamp, roomObject) => {
)
return null; // 택시 출발 시각이 이벤트 기간 내에 포함되지 않는 경우 퀘스트 완료 요청을 하지 않습니다.

return await completeQuest(userId, timestamp, quests.paying);
return await completeQuest(userId, timestamp, quests.fareSettlement);
};

/**
* sending 퀘스트의 완료를 요청합니다. 방의 참가자 수가 2명 미만이면 요청하지 않습니다.
* farePayment 퀘스트의 완료를 요청합니다. 방의 참가자 수가 2명 미만이면 요청하지 않습니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @param {Object} roomObject - 방의 정보입니다.
Expand All @@ -197,9 +165,9 @@ const completePayingQuest = async (userId, timestamp, roomObject) => {
* @description 송금이 이루어질 때마다 호출해 주세요.
* @usage rooms - commitPaymentHandler
*/
const completeSendingQuest = async (userId, timestamp, roomObject) => {
const completeFarePaymentQuest = async (userId, timestamp, roomObject) => {
logger.info(
`User ${userId} requested to complete sendingQuest in Room ${roomObject._id}`
`User ${userId} requested to complete farePaymentQuest in Room ${roomObject._id}`
);

if (roomObject.part.length < 2) return null;
Expand All @@ -210,7 +178,7 @@ const completeSendingQuest = async (userId, timestamp, roomObject) => {
)
return null; // 택시 출발 시각이 이벤트 기간 내에 포함되지 않는 경우 퀘스트 완료 요청을 하지 않습니다.

return await completeQuest(userId, timestamp, quests.sending);
return await completeQuest(userId, timestamp, quests.farePayment);
};

/**
Expand Down Expand Up @@ -241,13 +209,13 @@ const completeAccountChangingQuest = async (userId, timestamp, newAccount) => {
};

/**
* adPushAgreementQuest 퀘스트의 완료를 요청합니다.
* adPushAgreement 퀘스트의 완료를 요청합니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @param {boolean} advertisement - 변경된 광고성 알림 수신 동의 여부입니다.
* @returns {Promise}
* @description 알림 옵션을 변경할 때마다 호출해 주세요.
* @usage notifications/editOptionsHandler
* @usage notifications - editOptionsHandler
*/
const completeAdPushAgreementQuest = async (
userId,
Expand All @@ -260,38 +228,36 @@ const completeAdPushAgreementQuest = async (
};

/**
* eventSharing, eventSharing5 퀘스트의 완료를 요청합니다.
* eventSharing 퀘스트의 완료를 요청합니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @returns {Promise}
* @description 초대 링크를 통해 사용자가 이벤트에 참여할 때마다, 초대한 사용자 및 초대받은 사용자에 대해 각각 호출해 주세요.
* @usage lottery/globalState - createUserGlobalStateHandler
*/
const completeEventSharingQuest = async (userId, timestamp) => {
const eventSharingResult = await completeQuest(
userId,
timestamp,
quests.eventSharing
);
if (!eventSharingResult || eventSharingResult.questCount % 5 !== 0)
return [eventSharingResult, null];
return await completeQuest(userId, timestamp, quests.eventSharing);
};

const eventSharing5Result = await completeQuest(
userId,
timestamp,
quests.eventSharing5
);
return [eventSharingResult, eventSharing5Result];
/**
* itemPurchase 퀘스트의 완료를 요청합니다.
* @param {string|mongoose.Types.ObjectId} userId - 퀘스트를 완료한 사용자의 ObjectId입니다.
* @param {number|Date} timestamp - 퀘스트 완료를 요청한 시각입니다.
* @returns {Promise}
* @description 상품을 구입할 때마다 호출해 주세요.
*/
const completeItemPurchaseQuest = async (userId, timestamp) => {
return await completeQuest(userId, timestamp, quests.itemPurchase);
};

module.exports = {
quests,
completeFirstLoginQuest,
completePayingAndSendingQuest,
completeFirstRoomCreationQuest,
completePayingQuest,
completeSendingQuest,
completeFareSettlementQuest,
completeFarePaymentQuest,
completeNicknameChangingQuest,
completeAccountChangingQuest,
completeAdPushAgreementQuest,
completeEventSharingQuest,
completeItemPurchaseQuest,
};
5 changes: 2 additions & 3 deletions src/lottery/modules/populates/transactions.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const transactionPopulateOption = [
{
path: "item",
select:
"name imageUrl instagramStoryStickerImageUrl price description isDisabled stock itemType",
path: "itemId",
select: "name imageUrl",
},
];

Expand Down
10 changes: 7 additions & 3 deletions src/lottery/modules/quests.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const eventPeriod = eventConfig && {
};

const requiredQuestFields = ["name", "description", "imageUrl", "reward"];

const buildQuests = (quests) => {
for (const [id, quest] of Object.entries(quests)) {
// quest에 필수 필드가 모두 포함되어 있는지 확인합니다.
Expand Down Expand Up @@ -61,7 +62,7 @@ const buildQuests = (quests) => {
* @param {number} quest.reward.credit - 퀘스트의 완료 보상 중 재화의 양입니다.
* @param {number} quest.reward.ticket1 - 퀘스트의 완료 보상 중 일반 티켓의 개수입니다.
* @param {number} quest.maxCount - 퀘스트의 최대 완료 가능 횟수입니다.
* @returns {Object|null} 성공한 경우 Object를, 실패한 경우 null을 반환합니다. 이미 최대 완료 횟수에 도달했거나, 퀘스트가 원격으로 비활성화 된 경우에도 실패로 처리됩니다.
* @returns {Object|null} 성공한 경우 Object를, 실패한 경우 null을 반환합니다. 이미 최대 완료 횟수에 도달했거나, 퀘스트가 원격으로 비활성화된 경우에도 실패로 처리됩니다.
*/
const completeQuest = async (userId, timestamp, quest) => {
try {
Expand Down Expand Up @@ -118,7 +119,10 @@ const completeQuest = async (userId, timestamp, quest) => {
ticket1Amount: quest.reward.ticket1,
},
$push: {
completedQuests: quest.id,
completedQuests: {
questId: quest.id,
completedAt: timestamp,
},
},
}
);
Expand All @@ -143,7 +147,7 @@ const completeQuest = async (userId, timestamp, quest) => {
amount: 0,
userId,
questId: quest.id,
item: ticket1._id,
itemId: ticket1._id,
comment: `"${quest.name}" 퀘스트를 완료해 "${ticket1.name}" ${quest.reward.ticket1}개를 획득했습니다.`,
});
await transaction.save();
Expand Down
Loading

0 comments on commit d876254

Please sign in to comment.