diff --git a/package.json b/package.json index acc5e45c..3233a337 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "@fastify/cookie": "9.3.1", "@fastify/formbody": "7.4.0", + "@fastify/sensible": "^5.6.0", "@fastify/static": "^7.0.4", "@fastify/websocket": "10.0.1", "@kitajs/fastify-html-plugin": "4.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0eb59ab..1632925b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: '@fastify/formbody': specifier: 7.4.0 version: 7.4.0 + '@fastify/sensible': + specifier: ^5.6.0 + version: 5.6.0 '@fastify/static': specifier: ^7.0.4 version: 7.0.4 @@ -699,6 +702,18 @@ packages: mime: 3.0.0 dev: false + /@fastify/sensible@5.6.0: + resolution: {integrity: sha512-Vq6Z2ZQy10GDqON+hvLF52K99s9et5gVVxTul5n3SIAf0Kq5QjPRUKkAMT3zPAiiGvoHtS3APa/3uaxfDgCODQ==} + dependencies: + '@lukeed/ms': 2.0.2 + fast-deep-equal: 3.1.3 + fastify-plugin: 4.5.1 + forwarded: 0.2.0 + http-errors: 2.0.0 + type-is: 1.6.18 + vary: 1.1.2 + dev: false + /@fastify/static@7.0.4: resolution: {integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==} dependencies: @@ -2785,6 +2800,11 @@ packages: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} dev: true + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + /memory-pager@1.5.0: resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} dev: false @@ -4183,6 +4203,14 @@ packages: engines: {node: '>=4'} dev: true + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: false + /typed-emitter@0.1.0: resolution: {integrity: sha512-Tfay0l6gJMP5rkil8CzGbLthukn+9BN/VXWcABVFPjOoelJ+koW8BuPZYk+h/L+lEeIp1fSzVRiWRPIjKVjPdg==} dev: false @@ -4249,6 +4277,11 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + /vite-node@1.6.0(@types/node@20.12.7): resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} engines: {node: ^18.0.0 || >=20.0.0} diff --git a/src/games/routes.ts b/src/games/routes.ts index e4392fc2..0eaf9fd4 100644 --- a/src/games/routes.ts +++ b/src/games/routes.ts @@ -8,6 +8,7 @@ import { gameNumber } from './schemas/game-number' import { requestSubstitute } from './request-substitute' import { replacePlayer } from './replace-player' import { forceEnd } from './force-end' +import { collections } from '../database/collections' export default fp( // eslint-disable-next-line @typescript-eslint/require-await @@ -37,7 +38,13 @@ export default fp( }, }, async (request, reply) => { - reply.status(200).html(await GamePage(request.params.number, request.user)) + const { number } = request.params + const game = await collections.games.findOne({ number }) + if (!game) { + return reply.notFound() + } + + reply.status(200).html(await GamePage({ game, user: request.user })) }, ) .put( @@ -54,8 +61,7 @@ export default fp( }, async (request, reply) => { if (!request.isAdmin) { - await reply.status(403).send() - return + return reply.forbidden() } const number = request.params.number @@ -79,8 +85,7 @@ export default fp( }, async (request, reply) => { if (!request.user) { - await reply.status(401).send() - return + return reply.unauthorized() } const number = request.params.number @@ -101,8 +106,7 @@ export default fp( }, async (request, reply) => { if (!request.isAdmin) { - await reply.status(403).send() - return + return reply.forbidden() } await forceEnd(request.params.number, request.user!.player.steamId) diff --git a/src/games/views/html/game.page.tsx b/src/games/views/html/game.page.tsx index 76745f12..bff5f191 100644 --- a/src/games/views/html/game.page.tsx +++ b/src/games/views/html/game.page.tsx @@ -1,7 +1,6 @@ import { resolve } from 'node:path' import type { User } from '../../../auth/types/user' -import { collections } from '../../../database/collections' -import { GameState, type GameNumber } from '../../../database/models/game.model' +import { GameState, type GameModel } from '../../../database/models/game.model' import { NavigationBar } from '../../../html/components/navigation-bar' import { Page } from '../../../html/components/page' import { Style } from '../../../html/components/style' @@ -13,28 +12,23 @@ import { GameEventList } from './game-event-list' import { PlayerRole } from '../../../database/models/player.model' import { AdminActions } from './admin-actions' -export async function GamePage(number: GameNumber, user?: User) { - const game = await collections.games.findOne({ number }) - if (!game) { - throw new Error(`game not found: ${number}`) - } - +export async function GamePage(props: { game: GameModel; user?: User | undefined }) { return ( } > - +
- + Game events - +
- +
{[ @@ -42,14 +36,14 @@ export async function GamePage(number: GameNumber, user?: User) { GameState.configuring, GameState.launching, GameState.started, - ].includes(game.state) && user?.player.roles.includes(PlayerRole.admin) ? ( - + ].includes(props.game.state) && props.user?.player.roles.includes(PlayerRole.admin) ? ( + ) : ( <> )}
-