summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-09-15 20:50:51 +0200
committerTor Andersson <tor@ccxvii.net>2023-09-18 21:16:47 +0200
commitd7ae1e694112d6a4bfc9d528aa738fb04946a0b3 (patch)
treefc4f1c147d5a7887f98240df2851a3ee8f039b29
parent9e77cf5b29a533faf1909327772359d189e527b1 (diff)
downloadserver-d7ae1e694112d6a4bfc9d528aa738fb04946a0b3.tar.gz
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.
-rw-r--r--public/join.js4
-rw-r--r--public/style.css2
-rw-r--r--server.js51
-rw-r--r--views/create.pug7
-rw-r--r--views/join.pug4
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 = `<i>Empty</i>`
+ else if (game.owner_id === user_id)
element.innerHTML = `\xbb <a class="join" href="javascript:join('${role}')">Join</a><a class="green" href="javascript:show_invite('${role}')">\u{2795}</a>`
else
element.innerHTML = `\xbb <a class="join" href="javascript:join('${role}')">Join</a>`
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