diff --git a/app/features/admin/actions/admin.server.ts b/app/features/admin/actions/admin.server.ts index aaf1babcc..9e83c09cb 100644 --- a/app/features/admin/actions/admin.server.ts +++ b/app/features/admin/actions/admin.server.ts @@ -4,6 +4,8 @@ import * as AdminRepository from "~/features/admin/AdminRepository.server"; import { makeArtist } from "~/features/art/queries/makeArtist.server"; import { requireUserId } from "~/features/auth/core/user.server"; import { refreshBannedCache } from "~/features/ban/core/banned.server"; +import { FRIEND_CODE_REGEXP } from "~/features/sendouq/q-constants"; +import * as UserRepository from "~/features/user-page/UserRepository.server"; import { isAdmin, isMod } from "~/permissions"; import { logger } from "~/utils/logger"; import { parseRequestPayload, validate } from "~/utils/remix"; @@ -112,6 +114,17 @@ export const action = async ({ request }: ActionFunctionArgs) => { break; } + case "UPDATE_FRIEND_CODE": { + validate(isMod(user), "Mod needed", 401); + + await UserRepository.insertFriendCode({ + friendCode: data.friendCode, + submitterUserId: user.id, + userId: data.user, + }); + + break; + } default: { assertUnreachable(data); } @@ -161,4 +174,9 @@ export const adminActionSchema = z.union([ _action: _action("UNBAN_USER"), user: z.preprocess(actualNumber, z.number().positive()), }), + z.object({ + _action: _action("UPDATE_FRIEND_CODE"), + friendCode: z.string().regex(FRIEND_CODE_REGEXP), + user: z.preprocess(actualNumber, z.number().positive()), + }), ]); diff --git a/app/features/admin/routes/admin.tsx b/app/features/admin/routes/admin.tsx index 0b8d8c652..4b9a94c7a 100644 --- a/app/features/admin/routes/admin.tsx +++ b/app/features/admin/routes/admin.tsx @@ -8,10 +8,12 @@ import { import * as React from "react"; import { Button } from "~/components/Button"; import { Catcher } from "~/components/Catcher"; +import { Input } from "~/components/Input"; import { Main } from "~/components/Main"; import { SubmitButton } from "~/components/SubmitButton"; import { UserSearch } from "~/components/UserSearch"; import { useUser } from "~/features/auth/core/user"; +import { FRIEND_CODE_REGEXP_PATTERN } from "~/features/sendouq/q-constants"; import { isAdmin, isMod } from "~/permissions"; import type { SendouRouteHandle } from "~/utils/remix"; import { makeTitle } from "~/utils/strings"; @@ -39,6 +41,7 @@ export default function AdminPage() { {isMod(user) ? : null} {isMod(user) ? : null} {isMod(user) ? : null} + {isMod(user) ? : null} {process.env.NODE_ENV !== "production" || isAdmin(user) ? ( @@ -199,6 +202,41 @@ function GiveVideoAdder() { ); } +function UpdateFriendCode() { + const fetcher = useFetcher(); + + return ( + +

Update friend code

+
+
+ + +
+
+ + +
+
+
+ + Submit + +
+
+ ); +} + function ForcePatron() { const fetcher = useFetcher(); diff --git a/scripts/update-fc.ts b/scripts/update-fc.ts deleted file mode 100644 index 7e55b4c12..000000000 --- a/scripts/update-fc.ts +++ /dev/null @@ -1,27 +0,0 @@ -import "dotenv/config"; -import { ADMIN_ID } from "~/constants"; -import { FRIEND_CODE_REGEXP } from "~/features/sendouq/q-constants"; -import * as UserRepository from "~/features/user-page/UserRepository.server"; -import invariant from "~/utils/invariant"; -import { logger } from "~/utils/logger"; - -async function main() { - const discordId = process.argv[2]?.trim(); - - invariant(discordId, "discord id is required (argument 1)"); - - const newFriendCode = process.argv[3]?.trim(); - - invariant(discordId, "friend code is required (argument 2)"); - - invariant(FRIEND_CODE_REGEXP.test(newFriendCode), "Invalid friend code"); - - await UserRepository.insertFriendCode({ - friendCode: newFriendCode, - submitterUserId: ADMIN_ID, - userId: await UserRepository.findByIdentifier(discordId).then((u) => u!.id), - }); - logger.info(`Friend code updated: ${discordId} - ${newFriendCode}`); -} - -void main();