From 083f4a2896a5be6c231dc9fe44950b4d43cab27e Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Fri, 7 Jan 2022 13:18:38 +0200 Subject: [PATCH] Log in, seed via magic search input --- app/components/Layout/SearchInput.tsx | 66 ++++++++++++++++++++++ app/entry.server.tsx | 2 +- app/validators/seedVariations.ts | 4 ++ app/validators/user.ts | 2 +- prisma/seed/index.ts | 7 +-- prisma/seed/script.ts | 5 +- server/index.ts | 79 +++++++++++++++++++++++---- 7 files changed, 144 insertions(+), 21 deletions(-) create mode 100644 app/validators/seedVariations.ts diff --git a/app/components/Layout/SearchInput.tsx b/app/components/Layout/SearchInput.tsx index 783b818f7..160d7119f 100644 --- a/app/components/Layout/SearchInput.tsx +++ b/app/components/Layout/SearchInput.tsx @@ -1,13 +1,79 @@ +import * as React from "react"; import clsx from "clsx"; import { SearchIcon } from "../../components/icons/Search"; export function SearchInput() { + // TODO: search input that searches + if (process.env.NODE_ENV !== "development") return
; + return ; +} + +export function SearchInputDev() { + const [inputValue, setInputValue] = React.useState(""); + + const handleEnter = () => { + const [action, value] = inputValue.split(":"); + if (!action || !value) return; + + let fetchUrl = ""; + switch (action) { + case "liu": { + fetchUrl = `/mock-auth?username=${encodeURIComponent(value)}`; + break; + } + case "lit": { + fetchUrl = `/mock-auth?team=${encodeURIComponent(value)}`; + break; + } + case "seed": { + fetchUrl = `/seed?variation=${encodeURIComponent(value)}`; + break; + } + default: { + console.error("invalid action"); + return; + } + } + + return fetch(fetchUrl, { method: "post" }).then((res) => { + if (res.status === 200) location.reload(); + else { + console.error(`http error when trying an admin action: ${res.status}`); + } + }); + }; + + return ( + + ); +} + +export function DumbSearchInput({ + value, + setValue, + handleEnter, +}: { + value: string; + setValue: (newValue: string) => void; + handleEnter: () => void; +}) { return (
setValue(e.target.value)} + onKeyDown={(event) => { + if (event.key === "Enter") { + handleEnter(); + } + }} />
diff --git a/app/entry.server.tsx b/app/entry.server.tsx index cae206749..3576abdee 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -1,6 +1,6 @@ import { renderToString } from "react-dom/server"; -import { RemixServer } from "remix"; import type { EntryContext } from "remix"; +import { RemixServer } from "remix"; export default function handleRequest( request: Request, diff --git a/app/validators/seedVariations.ts b/app/validators/seedVariations.ts new file mode 100644 index 000000000..0e01bbbbb --- /dev/null +++ b/app/validators/seedVariations.ts @@ -0,0 +1,4 @@ +import { z } from "zod"; + +export type SeedVariations = z.infer; +export const SeedVariationsSchema = z.enum(["check-in", "match"]); diff --git a/app/validators/user.ts b/app/validators/user.ts index 7f34b19d4..4fef82888 100644 --- a/app/validators/user.ts +++ b/app/validators/user.ts @@ -6,7 +6,7 @@ export const LoggedInUserSchema = z.object({ .object({ id: z.string(), discordId: z.string(), - discordAvatar: z.string(), + discordAvatar: z.string().nullable(), }) .nullish(), }); diff --git a/prisma/seed/index.ts b/prisma/seed/index.ts index ba3cd22d0..08d76af97 100644 --- a/prisma/seed/index.ts +++ b/prisma/seed/index.ts @@ -1,15 +1,12 @@ import { PrismaClient } from "@prisma/client"; -import { z } from "zod"; +import { SeedVariationsSchema } from "~/validators/seedVariations"; const prisma = new PrismaClient(); import { seed } from "./script"; const maybeVariation = process.argv[2]?.startsWith("-v=") ? process.argv[2].split("-v=")[1] : undefined; -const variation = z - .enum(["check-in", "match"]) - .optional() - .parse(maybeVariation); +const variation = SeedVariationsSchema.optional().parse(maybeVariation); seed(variation) .then(() => { diff --git a/prisma/seed/script.ts b/prisma/seed/script.ts index f59256901..c90ba3007 100644 --- a/prisma/seed/script.ts +++ b/prisma/seed/script.ts @@ -15,11 +15,12 @@ import path from "path"; import crypto from "crypto"; import { createTournamentRounds } from "../../app/services/tournament"; import invariant from "tiny-invariant"; +import { SeedVariations } from "~/validators/seedVariations"; const prisma = new PrismaClient(); const mapListDE = `{"losers":[[{"id":4647,"name":"Kelp Dome","mode":"SZ"},{"id":4658,"name":"Blackbelly Skatepark","mode":"TC"},{"id":4645,"name":"Manta Maria","mode":"CB"}],[{"id":4624,"name":"Inkblot Art Academy","mode":"RM"},{"id":4707,"name":"Ancho-V Games","mode":"SZ"},{"id":4618,"name":"Humpback Pump Track","mode":"TC"}],[{"id":4692,"name":"Camp Triggerfish","mode":"SZ"},{"id":4665,"name":"MakoMart","mode":"CB"},{"id":4634,"name":"Moray Towers","mode":"RM"}],[{"id":4609,"name":"Musselforge Fitness","mode":"RM"},{"id":4647,"name":"Kelp Dome","mode":"SZ"},{"id":4678,"name":"Arowana Mall","mode":"TC"}],[{"id":4705,"name":"New Albacore Hotel","mode":"CB"},{"id":4644,"name":"Manta Maria","mode":"RM"},{"id":4707,"name":"Ancho-V Games","mode":"SZ"}],[{"id":4657,"name":"Blackbelly Skatepark","mode":"SZ"},{"id":4690,"name":"Piranha Pit","mode":"CB"},{"id":4682,"name":"Goby Arena","mode":"SZ"},{"id":4678,"name":"Arowana Mall","mode":"TC"},{"id":4624,"name":"Inkblot Art Academy","mode":"RM"}]],"winners":[[{"id":4677,"name":"Arowana Mall","mode":"SZ"},{"id":4665,"name":"MakoMart","mode":"CB"},{"id":4618,"name":"Humpback Pump Track","mode":"TC"}],[{"id":4624,"name":"Inkblot Art Academy","mode":"RM"},{"id":4683,"name":"Goby Arena","mode":"TC"},{"id":4692,"name":"Camp Triggerfish","mode":"SZ"}],[{"id":4647,"name":"Kelp Dome","mode":"SZ"},{"id":4634,"name":"Moray Towers","mode":"RM"},{"id":4707,"name":"Ancho-V Games","mode":"SZ"},{"id":4610,"name":"Musselforge Fitness","mode":"CB"},{"id":4658,"name":"Blackbelly Skatepark","mode":"TC"}],[{"id":4644,"name":"Manta Maria","mode":"RM"},{"id":4677,"name":"Arowana Mall","mode":"SZ"},{"id":4690,"name":"Piranha Pit","mode":"CB"},{"id":4682,"name":"Goby Arena","mode":"SZ"},{"id":4618,"name":"Humpback Pump Track","mode":"TC"}],[{"id":4624,"name":"Inkblot Art Academy","mode":"RM"},{"id":4707,"name":"Ancho-V Games","mode":"SZ"},{"id":4610,"name":"Musselforge Fitness","mode":"CB"},{"id":4657,"name":"Blackbelly Skatepark","mode":"SZ"},{"id":4693,"name":"Camp Triggerfish","mode":"TC"},{"id":4664,"name":"MakoMart","mode":"RM"},{"id":4647,"name":"Kelp Dome","mode":"SZ"}],[{"id":4617,"name":"Humpback Pump Track","mode":"SZ"},{"id":4635,"name":"Moray Towers","mode":"CB"},{"id":4682,"name":"Goby Arena","mode":"SZ"},{"id":4644,"name":"Manta Maria","mode":"RM"},{"id":4678,"name":"Arowana Mall","mode":"TC"},{"id":4692,"name":"Camp Triggerfish","mode":"SZ"},{"id":4705,"name":"New Albacore Hotel","mode":"CB"}]]}`; -export async function seed(variation?: "check-in" | "match") { +export async function seed(variation?: SeedVariations) { try { // // make sure we won't override production database @@ -129,7 +130,7 @@ export async function seed(variation?: "check-in" | "match") { "🛏️", "Name Subject to Change", "FTWin!", - "Starbust", + "Starburst", "Jackpot", "Crème Fresh", "Squids Next Door", diff --git a/server/index.ts b/server/index.ts index e95ffd349..03c9151ec 100644 --- a/server/index.ts +++ b/server/index.ts @@ -6,6 +6,10 @@ import { z } from "zod"; import { createRequestHandler } from "@remix-run/express"; import { setUpAuth } from "./auth"; import { seed } from "../prisma/seed/script"; +import { LoggedInUser } from "~/validators/user"; +import { db } from "~/utils/db.server"; +import { User } from "@prisma/client"; +import { SeedVariationsSchema } from "~/validators/seedVariations"; const MODE = process.env.NODE_ENV; const BUILD_DIR = path.join(process.cwd(), "server/build"); @@ -27,6 +31,65 @@ try { console.error(err); } +let mockUserFromHTTPCall: LoggedInUser | null = null; + +if (process.env.NODE_ENV === "development") { + app.post("/seed", async (req, res) => { + const variation = SeedVariationsSchema.optional().parse( + req.query.variation + ); + await seed(variation); + + res.status(200).end(); + }); + + // TODO: this could be in a different file -> later this will also be for prod + app.post("/mock-auth", async (req, res) => { + try { + const data = z + .object({ username: z.string().nullish(), team: z.string().nullish() }) + .parse(req.query); + + const allUsers = await db.user.findMany({}); + + let newMockUser: User | undefined; + if (data.username) { + const username = data.username.toLowerCase().trim(); + newMockUser = allUsers.find( + (user) => user.discordName.toLowerCase() === username + ); + } else if (data.team) { + const team = data.team.toLowerCase().trim(); + const teams = await db.tournamentTeam.findMany({ + include: { members: { include: { member: true } } }, + }); + + const wantedTeam = teams.find( + (teamFromDb) => teamFromDb.name.toLowerCase() === team.toLowerCase() + ); + if (!wantedTeam) return res.status(400).end(); + + const captain = wantedTeam.members.find((member) => member.captain); + if (!captain) return res.status(400).end(); + + newMockUser = captain.member; + } + + if (!newMockUser) return res.status(400).end(); + + mockUserFromHTTPCall = { + discordAvatar: newMockUser.discordAvatar, + discordId: newMockUser.discordId, + id: newMockUser.id, + }; + } catch { + return res.status(400).end(); + } + + res.status(200).end(); + }); +} + function userToContext(req: Express.Request) { if (process.env.NODE_ENV === "development") { // @ts-expect-error @@ -34,22 +97,14 @@ function userToContext(req: Express.Request) { if (mockedUser) { return { user: JSON.parse(mockedUser) }; } + + if (mockUserFromHTTPCall) { + return { user: mockUserFromHTTPCall }; + } } return { user: req.user }; } -if (process.env.NODE_ENV === "development") { - app.post("/seed", async (req, res) => { - const variation = z - .enum(["check-in"]) - .optional() - .parse(req.query.variation); - await seed(variation); - - res.status(200).end(); - }); -} - app.all( "*", MODE === "production"