diff --git a/.env.example b/.env.example index 1ae987ffc..f40055661 100644 --- a/.env.example +++ b/.env.example @@ -48,6 +48,9 @@ SQL_LOG=none VITE_SHOW_LUTI_NAV_ITEM=false +// If false the scanner page and its ingest endpoint are admin only +VITE_SCANNER_ENABLED=false + // Push notification. Generate values here https://vapidkeys.com/ VITE_VAPID_PUBLIC_KEY= VAPID_PRIVATE_KEY= diff --git a/app/config.ts b/app/config.ts index bae212fac..33fa59938 100644 --- a/app/config.ts +++ b/app/config.ts @@ -42,6 +42,7 @@ const values = { VITE_PROD_MODE: stringBool("VITE_PROD_MODE"), VITE_SHOW_LUTI_NAV_ITEM: stringBool("VITE_SHOW_LUTI_NAV_ITEM"), VITE_FUSE_ENABLED: stringBool("VITE_FUSE_ENABLED"), + VITE_SCANNER_ENABLED: stringBool("VITE_SCANNER_ENABLED"), VITE_LEAGUE_GOOGLE_FORM_URL: env.VITE_LEAGUE_GOOGLE_FORM_URL, VITE_SHOW_BANNER_FOR_SEASON: env.VITE_SHOW_BANNER_FOR_SEASON, VITE_SENTRY_DSN: env.VITE_SENTRY_DSN, @@ -66,6 +67,8 @@ export const Config = { /** Whether to show the LUTI navigation item. */ showLutiNavItem: values.VITE_SHOW_LUTI_NAV_ITEM, fuseEnabled: values.VITE_FUSE_ENABLED, + /** Whether the scanner is available to everyone. While false only the admin can use the scanner page and its ingest endpoint. */ + scannerEnabled: values.VITE_SCANNER_ENABLED, /** Google Form URL for league registration, if configured. */ leagueGoogleFormUrl: values.VITE_LEAGUE_GOOGLE_FORM_URL, /** Season identifier to show the registration banner for, if any. */ diff --git a/app/features/scanner-ingest/actions/scanner-ingest.server.ts b/app/features/scanner-ingest/actions/scanner-ingest.server.ts index 44c2e9197..552670127 100644 --- a/app/features/scanner-ingest/actions/scanner-ingest.server.ts +++ b/app/features/scanner-ingest/actions/scanner-ingest.server.ts @@ -1,9 +1,11 @@ import type { ActionFunction } from "react-router"; +import { Config } from "~/config"; import { requireUser } from "~/features/auth/core/user.server"; import type { ScannerMatch } from "~/features/scanner/core/scanner-match"; import * as UserRepository from "~/features/user-page/UserRepository.server"; +import { isAdmin } from "~/modules/permissions/utils"; import { logger } from "~/utils/logger"; -import { badRequestIfFalsy, parseBody } from "~/utils/remix.server"; +import { badRequestIfFalsy, forbidden, parseBody } from "~/utils/remix.server"; import * as Scoreboards from "../core/Scoreboards"; import * as ScannerIngestRepository from "../ScannerIngestRepository.server"; import { ingestBodySchema } from "../scanner-ingest-schemas"; @@ -15,6 +17,10 @@ import { ingestBodySchema } from "../scanner-ingest-schemas"; export const action: ActionFunction = async ({ request }) => { const user = requireUser(); + if (!Config.scannerEnabled && !isAdmin(user)) { + forbidden(); + } + const data = await parseBody({ request, schema: ingestBodySchema }); const povUserId = data.povUserId ?? user?.id ?? null; diff --git a/app/features/scanner/components/LivePage.tsx b/app/features/scanner/components/LivePage.tsx index 21472af86..add8a92b4 100644 --- a/app/features/scanner/components/LivePage.tsx +++ b/app/features/scanner/components/LivePage.tsx @@ -42,7 +42,6 @@ import { EventCard } from "./EventCard"; import { EventsSummary } from "./EventsSummary"; import { downloadEventsCsv } from "./events-csv"; import { type FixtureData, saveFixture } from "./fixture-export"; -import { SENDOU_UPLOAD_ENABLED } from "./flags"; import { MatchCard } from "./MatchCard"; import { MatchLobbyTabs } from "./MatchLobbyTabs"; import { @@ -293,25 +292,21 @@ export function LivePage({
{!running ? ( <> - {SENDOU_UPLOAD_ENABLED ? ( - - ) : null} + ) : ( @@ -319,21 +314,19 @@ export function LivePage({ - {SENDOU_UPLOAD_ENABLED ? ( - - ) : null} + )}