diff --git a/app/config/default.json b/app/config/default.json index e126a09a..7e46a430 100644 --- a/app/config/default.json +++ b/app/config/default.json @@ -225,5 +225,10 @@ "full_image": "https://chieru.hanshino.dev/assets/units/full/%s.png", "head_image": "https://chieru.hanshino.dev/assets/units/head/%s.png" } + }, + "gamble": { + "number": { + "daily_limit": 100 + } } } \ No newline at end of file diff --git a/app/package.json b/app/package.json index 7854423b..a496e629 100644 --- a/app/package.json +++ b/app/package.json @@ -12,7 +12,7 @@ "migrate": "knex migrate:latest" }, "dependencies": { - "@sentry/node": "^7.99.0", + "@sentry/node": "^7.101.1", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "axios": "1.6.7", @@ -44,7 +44,7 @@ "devDependencies": { "@types/express": "^4.17.21", "cors": "^2.8.5", - "dotenv": "^16.4.1", + "dotenv": "^16.4.4", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", diff --git a/app/src/controller/application/NumberController.js b/app/src/controller/application/NumberController.js index 9499ea7d..8fe7b9fb 100644 --- a/app/src/controller/application/NumberController.js +++ b/app/src/controller/application/NumberController.js @@ -6,6 +6,7 @@ const redis = require("../../util/redis"); const { inventory } = require("../../model/application/Inventory"); const numberGambleHistory = require("../../model/application/NumberGambleHistory"); const moment = require("moment"); +const config = require("config"); exports.router = [ text(/^[.#/](猜大小) (?\d{1,5})$/, privateSicBoHolding), @@ -15,7 +16,7 @@ exports.router = [ const optionMapping = { big: ["大"], small: ["小"], - // double: ["兩顆"], + double: ["兩顆"], triple: ["三顆"], }; @@ -37,8 +38,10 @@ function searchOption(option) { * Handles the user's decision in a game. * @param {Object} context - The context object. * @param {Object} props - The props object containing the user's decision. - * @param {string} props.option - The user's selected option. - * @param {string} props.chips - The amount of chips the user has bet. + * @param {Object} props.match - The match object containing the user's decision. + * @param {Object} props.match.groups - The groups object containing the user's decision. + * @param {string} props.match.groups.option - The user's selected option. + * @param {string} props.match.groups.chips - The amount of chips the user has bet. * @returns {Promise} - A promise that resolves when the function is done. */ async function userDecide(context, props) { @@ -51,12 +54,26 @@ async function userDecide(context, props) { return; } - const key = searchOption(option); + // 去除掉數字的部分進行驗證 + const key = searchOption(option.replace(/\d+/g, "")); if (!key) { await context.replyText("請選擇正確的選項,例如:大、小、兩顆、三顆", { quoteToken }); return; } + // 如果選項為兩顆,必須要有數字且介於 1~6,ex: 兩顆1, 兩顆2 + if (key === "double") { + if (option.replace(/\D/g, "").length !== 1) { + await context.replyText("請選擇正確的選項,例如:兩顆1、兩顆2", { quoteToken }); + return; + } + + if (/^[1-6]$/.test(option.replace(/\D/g, "")) === false) { + await context.replyText("請選擇正確的範圍,僅限於 1~6", { quoteToken }); + return; + } + } + if (!chips) { await context.replyText("請先下注", { quoteToken }); return; @@ -71,7 +88,7 @@ async function userDecide(context, props) { const { count: todayHistoryCount } = await query; - if (todayHistoryCount >= 10) { + if (todayHistoryCount >= config.get("gamble.number.daily_limit")) { await context.replyText(i18n.__("message.gamble.reach_daily_limit")); return; } @@ -89,12 +106,18 @@ async function userDecide(context, props) { return; } - const dice = rollDice(3); - const sum = dice.reduce((acc, cur) => acc + cur, 0); + const dices = rollDice(3); + const sum = dices.reduce((acc, cur) => acc + cur, 0); const isSmall = sum >= 3 && sum <= 10; const isBig = sum >= 11 && sum <= 18; - const isDouble = dice[0] === dice[1] || dice[0] === dice[2] || dice[1] === dice[2]; - const isTriple = dice[0] === dice[1] && dice[0] === dice[2]; + const isDouble = (() => { + if (key !== "double") { + return false; + } + const double = parseInt(option.replace(/\D/g, "")); + return dices.includes(double) && dices.filter(d => d === double).length === 2; + })(); + const isTriple = dices[0] === dices[1] && dices[0] === dices[2]; let result = false; switch (key) { @@ -130,9 +153,9 @@ async function userDecide(context, props) { const messages = [ i18n.__("message.gamble.sic_bo_rolled", { - dice1: dice[0], - dice2: dice[1], - dice3: dice[2], + dice1: dices[0], + dice2: dices[1], + dice3: dices[2], sum, }), ]; @@ -149,7 +172,7 @@ async function userDecide(context, props) { await numberGambleHistory.create({ user_id: userId, option, - dices: dice.join(","), + dices: dices.join(","), chips, payout, result: result ? 1 : 0, diff --git a/app/yarn.lock b/app/yarn.lock index 7638f1ed..e5ca90d1 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -960,44 +960,44 @@ resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.5.tgz#a6d70ef7a0e71e083ea09b967df0a0ed742bc6ad" integrity sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg== -"@sentry-internal/tracing@7.99.0": - version "7.99.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.99.0.tgz#ad13f8343444ecf7323a4220d4e57a55166565d7" - integrity sha512-z3JQhHjoM1KdM20qrHwRClKJrNLr2CcKtCluq7xevLtXHJWNAQQbafnWD+Aoj85EWXBzKt9yJMv2ltcXJ+at+w== +"@sentry-internal/tracing@7.101.1": + version "7.101.1" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.101.1.tgz#9504e29c3c2c3ef5f652777e487b596cf8f78e1a" + integrity sha512-ihjWG8x4x0ozx6t+EHoXLKbsPrgzYLCpeBLWyS+M6n3hn6cmHM76c8nZw3ldhUQi5UYL3LFC/JZ50b4oSxtlrg== dependencies: - "@sentry/core" "7.99.0" - "@sentry/types" "7.99.0" - "@sentry/utils" "7.99.0" + "@sentry/core" "7.101.1" + "@sentry/types" "7.101.1" + "@sentry/utils" "7.101.1" -"@sentry/core@7.99.0": - version "7.99.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.99.0.tgz#6881aae5ac1436637b3d88e0b12df4ab56016c5f" - integrity sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA== +"@sentry/core@7.101.1": + version "7.101.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.101.1.tgz#929841b7734129803b6dcd4d16bf0d3f53af4657" + integrity sha512-XSmXXeYT1d4O14eDF3OXPJFUgaN2qYEeIGUztqPX9nBs9/ij8y/kZOayFqlIMnfGvjOUM+63sy/2xDBOpFn6ug== dependencies: - "@sentry/types" "7.99.0" - "@sentry/utils" "7.99.0" + "@sentry/types" "7.101.1" + "@sentry/utils" "7.101.1" -"@sentry/node@^7.99.0": - version "7.99.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.99.0.tgz#c70e174527bbd86294dd446dbc1ae9036fb729f2" - integrity sha512-34wYtLddnPcQ8qvKq62AfxowaMFw+GMUZGv7fIs9FxeBqqqn6Ckl0gFCTADudIIBQ3rSbmN7sHJIXdyiQv+pcw== +"@sentry/node@^7.101.1": + version "7.101.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.101.1.tgz#d652503002be921be5ca042a3ef7457d309cdfa9" + integrity sha512-iXSxUT6Zbt/KUY0+fRcW5II6Tgp2zdTfhBW+fQuDt/UUZt7Ypvb+6n4U2oom3LJfttmD7mdjQuT4+vsNImDjTQ== dependencies: - "@sentry-internal/tracing" "7.99.0" - "@sentry/core" "7.99.0" - "@sentry/types" "7.99.0" - "@sentry/utils" "7.99.0" + "@sentry-internal/tracing" "7.101.1" + "@sentry/core" "7.101.1" + "@sentry/types" "7.101.1" + "@sentry/utils" "7.101.1" -"@sentry/types@7.99.0": - version "7.99.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.99.0.tgz#bba7a514abab445026ee42f40f92f81275a6deba" - integrity sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA== +"@sentry/types@7.101.1": + version "7.101.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.101.1.tgz#7f936022d9b373f85ebf357634bf03a9e433a3d0" + integrity sha512-bwtkQvrCZ6JGc7vqX7TEAKBgkbQFORt84FFS3JQQb8G3efTt9fZd2ReY4buteKQdlALl8h1QWVngTLmI+kyUuw== -"@sentry/utils@7.99.0": - version "7.99.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.99.0.tgz#ef96c3b59e23c79f3ef500db508234a48fa1cfbe" - integrity sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ== +"@sentry/utils@7.101.1": + version "7.101.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.101.1.tgz#97399b1e6a63a15e8f9fec5112ac4834239f1db6" + integrity sha512-Nrg0nrEI3nrOCd9SLJ/WGzxS5KMQE4cryLOvrDcHJRWpsSyGBF1hLLerk84Nsw/0myMsn7zTYU+xoq7idNsX5A== dependencies: - "@sentry/types" "7.99.0" + "@sentry/types" "7.101.1" "@sinclair/typebox@^0.27.8": version "0.27.8" @@ -2697,10 +2697,10 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -dotenv@^16.4.1: - version "16.4.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.1.tgz#1d9931f1d3e5d2959350d1250efab299561f7f11" - integrity sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ== +dotenv@^16.4.4: + version "16.4.4" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.4.tgz#a26e7bb95ebd36272ebb56edb80b826aecf224c1" + integrity sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg== duplexer3@^0.1.4: version "0.1.4"