mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-27 16:08:58 -07:00
[studio] rollout support
This commit is contained in:
@@ -144,6 +144,14 @@ export type Env = SharedHonoEnv & {
|
||||
* all closes the claim, exactly as an unset one does.
|
||||
*/
|
||||
DISCORD_BENEFITS_ROLE_IDS?: string
|
||||
/**
|
||||
* Discord role ids whose holders have Rec Room Studio upload access without the
|
||||
* account's `hasStudio` flag (`RECFLARE_STUDIO_ROLLOUT` in the root `.env`; the var
|
||||
* `auth` stamps `betastudio` from). `/api/studio-access` answers `granted` through the
|
||||
* same `hasStudioAccess`, so the Studio settings page agrees with the token. The staff
|
||||
* list and its add/remove still manage the flag alone.
|
||||
*/
|
||||
STUDIO_ROLLOUT?: string
|
||||
/**
|
||||
* The bot user's token for the scheduled role refresh (discord-roles.ts). Optional in
|
||||
* effect: the binding must exist for the deploy, but a placeholder value just leaves the
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
import { logger } from '@repo/hono-helpers'
|
||||
import { validateAndGetAccountId } from '@repo/jwt'
|
||||
|
||||
import { hasStudioAccess } from '../../auth/src/platform-db'
|
||||
|
||||
import type { Context } from 'hono'
|
||||
import type { Account } from '@repo/domain'
|
||||
import type { App } from './context'
|
||||
@@ -20,15 +22,18 @@ import type { App } from './context'
|
||||
* the signed-in player. Staff add and remove people through the routes under
|
||||
* `/api/staff/studio-access`, behind the same `requireStaff` gate as moderation.
|
||||
* The grant is the account's `hasStudio` flag; `auth` stamps `betastudio` from it
|
||||
* on the next Studio sign-in or refresh. Who granted what is on `audit_log`.
|
||||
* on the next Studio sign-in or refresh. Who granted what is on `audit_log`. A Discord
|
||||
* role in the `STUDIO_ROLLOUT` var grants the same access without the flag
|
||||
* (`hasStudioAccess`); the status below reports it, the staff list does not — that list
|
||||
* is the accounts staff added by hand.
|
||||
*/
|
||||
|
||||
/** The signed-in player's own flag, and nothing else. 401 with no session. */
|
||||
/** Whether the signed-in player can upload — flag or rollout role. 401 with no session. */
|
||||
export async function studioAccessStatusHandler(c: Context<App>) {
|
||||
const accountId = await validateAndGetAccountId(c.req.raw, await c.env.JWT_SECRET.get())
|
||||
if (accountId === null) return c.json({ error: 'Unauthorized' }, 401)
|
||||
const account = await getAccount(c.env.DB, accountId)
|
||||
return c.json({ granted: account?.hasStudio === true })
|
||||
return c.json({ granted: await hasStudioAccess(c.env.DB, account, c.env.STUDIO_ROLLOUT) })
|
||||
}
|
||||
|
||||
/** Every account with the flag set. */
|
||||
|
||||
@@ -3094,6 +3094,27 @@ it('tells a signed-in player whether they can upload, and nobody else', async ()
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
expect(await res.json()).toEqual({ granted: false })
|
||||
|
||||
// A Discord role named in STUDIO_ROLLOUT grants the same access without the flag, and the
|
||||
// page reads it from the same helper `auth` stamps `betastudio` from, so the two agree.
|
||||
// The account has to exist: a link alone, with no account behind it, grants nothing.
|
||||
await updateAccount(env.DB, 8601, { username: 'StudioFan' })
|
||||
await linkPlatformIdentity(env.DB, 8601, PlatformType.Discord, '500000000000008601', [
|
||||
'1077000000000000031',
|
||||
])
|
||||
const original = env.STUDIO_ROLLOUT
|
||||
try {
|
||||
env.STUDIO_ROLLOUT = '1077000000000000031'
|
||||
const rolled = await SELF.fetch('https://example.com/api/studio-access', {
|
||||
headers: { authorization: `Bearer ${await tokenFor(8601, ['gameClient'])}` },
|
||||
})
|
||||
expect(await rolled.json()).toEqual({ granted: true })
|
||||
// The flag itself never moved; the staff list is still empty of this account.
|
||||
expect((await getAccount(env.DB, 8601))?.hasStudio).not.toBe(true)
|
||||
} finally {
|
||||
if (original === undefined) delete env.STUDIO_ROLLOUT
|
||||
else env.STUDIO_ROLLOUT = original
|
||||
}
|
||||
})
|
||||
|
||||
it('lets staff add, list, and remove studio upload access', async () => {
|
||||
|
||||
Reference in New Issue
Block a user