Private
Public Access
1
0

refacto: Changing click cooldown to daily actions for users and teams

This commit is contained in:
gauvainboiche
2026-04-01 16:30:35 +02:00
parent 33c3518ee4
commit 5aa347eb13
9 changed files with 294 additions and 101 deletions

View File

@@ -106,6 +106,13 @@ export async function initGameSchema() {
END $$;
ALTER TABLE grid_cells ALTER COLUMN discovered_by SET NOT NULL;
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS team_action_quota (
team TEXT PRIMARY KEY CHECK (team IN ('blue', 'red')),
actions_remaining INTEGER NOT NULL DEFAULT 0,
quota_reset_at TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00'
);
`);
}
// ── World-seed epoch ──────────────────────────────────────────────────────────
@@ -355,3 +362,39 @@ export async function setTileOwner(worldSeed, x, y, team) {
[team, worldSeed, x, y]
);
}
// ── Team action quota (daily, independent of world seed) ─────────────────────
export async function getTeamActionsRow(team) {
const { rows } = await pool.query(
`SELECT actions_remaining, quota_reset_at FROM team_action_quota WHERE team = $1`,
[team]
);
return rows[0] ?? null;
}
export async function resetTeamActions(team, actionsRemaining, quotaResetAt) {
await pool.query(
`INSERT INTO team_action_quota (team, actions_remaining, quota_reset_at)
VALUES ($1, $2, $3)
ON CONFLICT (team) DO UPDATE
SET actions_remaining = $2,
quota_reset_at = $3`,
[team, actionsRemaining, quotaResetAt]
);
}
/**
* Atomically decrements team actions_remaining by 1 if > 0.
* Returns the updated row, or null if already 0.
*/
export async function decrementTeamActions(team) {
const { rows } = await pool.query(
`UPDATE team_action_quota
SET actions_remaining = actions_remaining - 1
WHERE team = $1 AND actions_remaining > 0
RETURNING actions_remaining`,
[team]
);
return rows[0] ?? null;
}

View File

@@ -13,6 +13,29 @@ export async function initUsersSchema() {
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
`);
await initUserActionQuotaSchema();
}
export async function initUserActionQuotaSchema() {
await usersPool.query(`
CREATE TABLE IF NOT EXISTS user_action_quota (
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
actions_remaining INTEGER NOT NULL DEFAULT 0,
quota_reset_at TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00'
);
`);
}
// ── Helpers ───────────────────────────────────────────────────────────────────
/** Returns the next noon (12:00:00) UTC after the current moment. */
export function nextNoonUtc() {
const now = new Date();
const noon = new Date(Date.UTC(
now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 12, 0, 0, 0
));
if (noon <= now) noon.setUTCDate(noon.getUTCDate() + 1);
return noon;
}
// ── Queries ───────────────────────────────────────────────────────────────────
@@ -50,4 +73,42 @@ export async function getTeamPlayerCounts() {
const result = { blue: 0, red: 0 };
for (const row of rows) result[row.team] = row.count;
return result;
}
// ── User action quota ─────────────────────────────────────────────────────────
/** Returns the current quota row for a user, or null if it doesn't exist. */
export async function getUserActionsRow(userId) {
const { rows } = await usersPool.query(
`SELECT actions_remaining, quota_reset_at FROM user_action_quota WHERE user_id = $1`,
[userId]
);
return rows[0] ?? null;
}
/** Insert or overwrite the quota row for a user. */
export async function resetUserActions(userId, actionsRemaining, quotaResetAt) {
await usersPool.query(
`INSERT INTO user_action_quota (user_id, actions_remaining, quota_reset_at)
VALUES ($1, $2, $3)
ON CONFLICT (user_id) DO UPDATE
SET actions_remaining = $2,
quota_reset_at = $3`,
[userId, actionsRemaining, quotaResetAt]
);
}
/**
* Atomically decrements actions_remaining by 1 if > 0.
* Returns the updated row (with new actions_remaining), or null if already 0.
*/
export async function decrementUserActions(userId) {
const { rows } = await usersPool.query(
`UPDATE user_action_quota
SET actions_remaining = actions_remaining - 1
WHERE user_id = $1 AND actions_remaining > 0
RETURNING actions_remaining`,
[userId]
);
return rows[0] ?? null;
}