From d7ae1e694112d6a4bfc9d528aa738fb04946a0b3 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 15 Sep 2023 20:50:51 +0200 Subject: Enforce limits on how many games you can create and join. Also limit joining more games if you have too many games waiting. Generous default limits: 7 open, 29 active, and 3 waiting. --- public/join.js | 4 +++- public/style.css | 2 +- server.js | 51 ++++++++++++++++++++++++++++++++++++++++++++------- views/create.pug | 7 +++++-- views/join.pug | 4 ++++ 5 files changed, 57 insertions(+), 11 deletions(-) diff --git a/public/join.js b/public/join.js index 362800d..a22e0fa 100644 --- a/public/join.js +++ b/public/join.js @@ -213,7 +213,9 @@ function update() { break case 1: case 0: - if (game.owner_id === user_id) + if (limit) + element.innerHTML = `Empty` + else if (game.owner_id === user_id) element.innerHTML = `\xbb Join\u{2795}` else element.innerHTML = `\xbb Join` diff --git a/public/style.css b/public/style.css index 0a950e6..c334e86 100644 --- a/public/style.css +++ b/public/style.css @@ -85,7 +85,7 @@ button:disabled { .error { color: brown; font-style: italic; white-space: pre-wrap; } .warning { color: brown; } -p.warning::before { content: "\26a0"; } +p.warning::before { content: "\26a0 "; } /* TABLES */ diff --git a/server.js b/server.js index c07b0d8..2e831eb 100644 --- a/server.js +++ b/server.js @@ -21,6 +21,10 @@ const HTTP_PORT = process.env.HTTP_PORT || 8080 const SITE_NAME = process.env.SITE_NAME || "Localhost" const SITE_URL = process.env.SITE_URL || "http://" + HTTP_HOST + ":" + HTTP_PORT +const LIMIT_WAITING_GAMES = (process.env.LIMIT_WAITING_GAMES | 0) || 3 +const LIMIT_OPEN_GAMES = (process.env.LIMIT_OPEN_GAMES | 0) || 7 +const LIMIT_ACTIVE_GAMES = (process.env.LIMIT_ACTIVE_GAMES | 0) || 29 + const REGEX_MAIL = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/ const REGEX_NAME = /^[\p{Alpha}\p{Number}'_-]+( [\p{Alpha}\p{Number}'_-]+)*$/u @@ -1157,6 +1161,12 @@ const SQL_DELETE_PLAYER_ROLE = SQL("DELETE FROM players WHERE game_id=? AND role const SQL_SELECT_OPEN_GAMES = SQL(`SELECT * FROM games WHERE status=${STATUS_OPEN}`) const SQL_COUNT_OPEN_GAMES = SQL(`SELECT COUNT(*) FROM games WHERE owner_id=? AND status=${STATUS_OPEN}`).pluck() +const SQL_COUNT_ACTIVE_GAMES = SQL(` + select count(*) from games + where status < 2 and exists ( + select 1 from players where players.user_id=? and players.game_id=games.game_id + ) +`).pluck() const SQL_SELECT_REMATCH = SQL(`SELECT game_id FROM games WHERE status < ${STATUS_FINISHED} AND notice=?`).pluck() const SQL_INSERT_REMATCH = SQL(` @@ -1256,7 +1266,7 @@ const QUERY_LIST_ACTIVE_GAMES_OF_USER = SQL(` ( owner_id=$user_id or game_id in ( select game_id from players where players.user_id=$user_id ) ) and ( status <= ${STATUS_FINISHED} ) - order by status asc, mtime desc + order by status asc, is_opposed desc, mtime desc `) const QUERY_LIST_FINISHED_GAMES_OF_USER = SQL(` @@ -1268,6 +1278,24 @@ const QUERY_LIST_FINISHED_GAMES_OF_USER = SQL(` order by status asc, mtime desc `) +function check_create_game_limit(user) { + if (user.waiting > LIMIT_WAITING_GAMES) + return "You have too many games waiting!" + if (SQL_COUNT_OPEN_GAMES.get(user.user_id) >= LIMIT_OPEN_GAMES) + return "You have too many open games!" + if (SQL_COUNT_ACTIVE_GAMES.get(user.user_id) >= LIMIT_ACTIVE_GAMES) + return "You cannot join any more games!" + return null +} + +function check_join_game_limit(user) { + if (user.waiting > LIMIT_WAITING_GAMES + 1) + return "You have too many games waiting!" + if (SQL_COUNT_ACTIVE_GAMES.get(user.user_id) >= LIMIT_ACTIVE_GAMES) + return "You cannot join any more games!" + return null +} + function format_options(options) { function to_english(k) { if (k === true || k === 1) return 'yes' @@ -1373,8 +1401,10 @@ app.get('/games', function (req, res) { }) function sort_your_turn(a, b) { - if (a.your_turn && !b.your_turn) return -1 - if (!a.your_turn && b.your_turn) return 1 + if (a.is_opposed && b.is_opposed) { + if (a.your_turn && !b.your_turn) return -1 + if (!a.your_turn && b.your_turn) return 1 + } return 0 } @@ -1486,6 +1516,7 @@ app.get('/create/:title_id', must_be_logged_in, function (req, res) { res.render('create.pug', { user: req.user, title: title, + limit: check_create_game_limit(req.user), scenarios: RULES[title_id].scenarios, create_html: HTML_CREATE[title_id], }) @@ -1514,9 +1545,10 @@ app.post("/create/:title_id", must_be_logged_in, function (req, res) { let options = JSON.stringify(req.body, options_json_replacer) let notice = req.body.notice - let count = SQL_COUNT_OPEN_GAMES.get(user_id) - if (count >= 7) - return res.send("You have too many open games!") + let limit = check_create_game_limit(req.user) + if (limit) + return res.send(limit) + if (!(title_id in RULES)) return res.send("Invalid title.") if (!RULES[title_id].scenarios.includes(scenario)) @@ -1615,7 +1647,8 @@ app.get('/join/:game_id', must_be_logged_in, function (req, res) { game.ctime = human_date(game.ctime) game.mtime = human_date(game.mtime) res.render('join.pug', { - user: req.user, game, roles, players, ready, whitelist, blacklist, friends + user: req.user, game, roles, players, ready, whitelist, blacklist, friends, + limit: check_join_game_limit(req.user) }) }) @@ -1679,6 +1712,9 @@ function do_join(res, game_id, role, user_id, is_invite) { app.post('/join/:game_id/:role', must_be_logged_in, function (req, res) { let game_id = req.params.game_id | 0 let role = req.params.role + let limit = check_join_game_limit(req.user) + if (limit) + return res.send(limit) do_join(res, game_id, role, req.user.user_id, 0) }) @@ -1693,6 +1729,7 @@ app.post('/invite/:game_id/:role/:user', must_be_logged_in, function (req, res) }) app.post('/accept/:game_id/:role', must_be_logged_in, function (req, res) { + // TODO: check join game limit if inviting self... let game_id = req.params.game_id | 0 let role = req.params.role let info = SQL_UPDATE_PLAYER_ACCEPT.run(game_id, role, req.user.user_id) diff --git a/views/create.pug b/views/create.pug index d742cfc..c8c70b2 100644 --- a/views/create.pug +++ b/views/create.pug @@ -38,5 +38,8 @@ html label input(type="checkbox" name="is_private" value="true") | Private - p - button(type="submit") Create + if limit + p.error= limit + else + p + button(type="submit") Create diff --git a/views/join.pug b/views/join.pug index ced1fe3..3110bd3 100644 --- a/views/join.pug +++ b/views/join.pug @@ -27,6 +27,7 @@ html let whitelist = !{ JSON.stringify(whitelist) } let blacklist = !{ JSON.stringify(blacklist) } let friends = !{ JSON.stringify(friends) } + let limit = !{ !!limit } let ready = !{ ready } script(src="/join.js") body @@ -36,6 +37,9 @@ html h1 #{game.title_name} else h1 #{game.title_name} - #{game.scenario} + + if limit + p.error= limit p.error#error div.logo -- cgit v1.2.3