Skip to content

Commit

Permalink
feat: add @fastify/sensible
Browse files Browse the repository at this point in the history
  • Loading branch information
garrappachc committed Aug 1, 2024
1 parent 647ab83 commit fb622f7
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 45 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
33 changes: 33 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 11 additions & 7 deletions src/games/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
26 changes: 10 additions & 16 deletions src/games/views/html/game.page.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -13,43 +12,38 @@ 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 (
<Layout
title={`game #${game.number}`}
title={`game #${props.game.number}`}
head={<Style fileName={resolve(import.meta.dirname, 'style.css')} />}
>
<NavigationBar user={user} />
<NavigationBar user={props.user} />
<Page>
<div class="container mx-auto grid grid-cols-4 gap-x-4 relative">
<div class="order-first flex flex-col">
<GameSummary game={game} actor={user?.player.steamId} />
<GameSummary game={props.game} actor={props.user?.player.steamId} />
<span class="col-span-2 mb-0 mt-8 text-2xl font-bold text-white">Game events</span>
<GameEventList game={game} />
<GameEventList game={props.game} />
</div>

<div class="col-span-3">
<GameSlotList game={game} actor={user?.player.steamId} />
<GameSlotList game={props.game} actor={props.user?.player.steamId} />
</div>

{[
GameState.created,
GameState.configuring,
GameState.launching,
GameState.started,
].includes(game.state) && user?.player.roles.includes(PlayerRole.admin) ? (
<AdminActions gameNumber={game.number} />
].includes(props.game.state) && props.user?.player.roles.includes(PlayerRole.admin) ? (
<AdminActions gameNumber={props.game.number} />
) : (
<></>
)}
</div>
</Page>
<Footer user={user} />
<Footer user={props.user} />
</Layout>
)
}
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const app = fastify({ logger })
app.setSerializerCompiler(serializerCompiler)
app.setValidatorCompiler(validatorCompiler)

await app.register(await import('@fastify/sensible'))
await app.register(await import('@fastify/formbody'))
await app.register(await import('@fastify/cookie'), {
secret: environment.AUTH_SECRET,
Expand Down
9 changes: 8 additions & 1 deletion src/players/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PlayerPage } from './views/html/player.page'
import type { ZodTypeProvider } from 'fastify-type-provider-zod'
import { z } from 'zod'
import { steamId64 } from '../shared/schemas/steam-id-64'
import { collections } from '../database/collections'

export default fp(
// eslint-disable-next-line @typescript-eslint/require-await
Expand All @@ -26,9 +27,15 @@ export default fp(
},
async (req, reply) => {
const { steamId } = req.params
const player = await collections.players.findOne({ steamId })
if (!player) {
return reply.notFound(`player not found: ${steamId}`)
}
reply
.status(200)
.html(await PlayerPage(steamId, req.user, Number(req.query.gamespage) || 1))
.html(
await PlayerPage({ player, user: req.user, page: Number(req.query.gamespage) || 1 }),
)
},
)
},
Expand Down
41 changes: 20 additions & 21 deletions src/players/views/html/player.page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { User } from '../../../auth/types/user'
import { collections } from '../../../database/collections'
import type { SteamId64 } from '../../../shared/types/steam-id-64'
import { Layout } from '../../../html/layout'
import { NavigationBar } from '../../../html/components/navigation-bar'
import { PlayerRole, type PlayerModel } from '../../../database/models/player.model'
import { format } from 'date-fns'
import { GameState, type GameModel } from '../../../database/models/game.model'
import { GameState } from '../../../database/models/game.model'
import { getPlayerGameCountOnClasses } from '../../get-player-game-count-on-classes'
import { Tf2ClassName } from '../../../shared/types/tf2-class-name'
import { GameClassIcon } from '../../../html/components/game-class-icon'
Expand All @@ -16,39 +15,39 @@ import { Page } from '../../../html/components/page'
import { Footer } from '../../../html/components/footer'
import { GameListItem } from '../../../games/views/html/game-list-item'
import { Pagination, paginate } from '../../../html/components/pagination'
import type { WithId } from 'mongodb'

const gamesPerPage = 5

export async function PlayerPage(steamId: SteamId64, user?: User, page = 1) {
const player = await collections.players.findOne({ steamId })
if (!player) {
throw new Error(`player not found: ${steamId}`)
}

const skip = (page - 1) * gamesPerPage
export async function PlayerPage(props: {
player: WithId<PlayerModel>
user?: User | undefined
page: number
}) {
const skip = (props.page - 1) * gamesPerPage

const games = await collections.games
.find(
{ 'slots.player': player._id },
{ 'slots.player': props.player._id },
{ limit: gamesPerPage, skip, sort: { 'events.0.at': -1 } },
)
.toArray()

const { last, around } = paginate(
page,
props.page,
gamesPerPage,
await collections.games.countDocuments({ 'slots.player': player._id }),
await collections.games.countDocuments({ 'slots.player': props.player._id }),
)

const gameCount = await collections.games.countDocuments({
$and: [{ state: GameState.ended }, { ['slots.player' as keyof GameModel]: player._id }],
$and: [{ state: GameState.ended }, { ['slots.player']: props.player._id }],
})

const gameCountOnClasses = await getPlayerGameCountOnClasses(player._id)
const gameCountOnClasses = await getPlayerGameCountOnClasses(props.player._id)

return (
<Layout
title={player.name}
title={props.player.name}
head={
<>
<Style fileName={resolve(import.meta.dirname, 'style.css')} />
Expand All @@ -58,11 +57,11 @@ export async function PlayerPage(steamId: SteamId64, user?: User, page = 1) {
</>
}
>
<NavigationBar user={user} />
<NavigationBar user={props.user} />
<Page>
<div class="container mx-auto mt-12 flex flex-col gap-[30px] p-2 lg:p-0">
<PlayerPresentation
player={player}
player={props.player}
gameCount={gameCount}
gameCountOnClasses={gameCountOnClasses}
/>
Expand All @@ -72,20 +71,20 @@ export async function PlayerPage(steamId: SteamId64, user?: User, page = 1) {
{games.map(game => (
<GameListItem
game={game}
classPlayed={game.slots.find(s => s.player.equals(player._id))!.gameClass}
classPlayed={game.slots.find(s => s.player.equals(props.player._id))!.gameClass}
/>
))}
</div>

<Pagination
hrefFn={page => `/players/${player.steamId}?gamespage=${page}`}
hrefFn={page => `/players/${props.player.steamId}?gamespage=${page}`}
lastPage={last}
currentPage={page}
currentPage={props.page}
around={around}
/>
</div>
</Page>
<Footer user={user} />
<Footer user={props.user} />
</Layout>
)
}
Expand Down

0 comments on commit fb622f7

Please sign in to comment.