diff --git a/app/features/auth/core/user.server.ts b/app/features/auth/core/user.server.ts index 03667dba5..6b8efe8c9 100644 --- a/app/features/auth/core/user.server.ts +++ b/app/features/auth/core/user.server.ts @@ -1,6 +1,10 @@ import { IMPERSONATED_SESSION_KEY, SESSION_KEY } from "./authenticator.server"; import { authSessionStorage } from "./session.server"; -import { type AuthenticatedUser, getUserContext } from "./user-context.server"; +import { + type AuthenticatedUser, + getUserContext, + userAsyncLocalStorage, +} from "./user-context.server"; export type { AuthenticatedUser }; @@ -32,6 +36,13 @@ export function actorIdOrNull(): number | null { return getUser()?.id ?? null; } +/** Id of the acting user, or null when there is no actor *or* no request + * context at all (e.g. cron routines). Never throws, unlike actorIdOrNull — + * use for ambient side effects that may also run outside of a request. */ +export function actorIdOrNullSafe(): number | null { + return userAsyncLocalStorage.getStore()?.user?.id ?? null; +} + export async function isImpersonating(request: Request) { const session = await authSessionStorage.getSession( request.headers.get("Cookie"), diff --git a/app/features/chat/ChatSystemMessage.server.ts b/app/features/chat/ChatSystemMessage.server.ts index b27933a7b..c8edae989 100644 --- a/app/features/chat/ChatSystemMessage.server.ts +++ b/app/features/chat/ChatSystemMessage.server.ts @@ -1,6 +1,7 @@ import { add } from "date-fns"; import { nanoid } from "nanoid"; import { ServerConfig } from "~/config.server"; +import { actorIdOrNullSafe } from "~/features/auth/core/user.server"; import * as UserRepository from "~/features/user-page/UserRepository.server"; import { IS_E2E_TEST_RUN } from "~/utils/e2e"; import invariant from "~/utils/invariant"; @@ -60,7 +61,7 @@ export const send: ChatSystemMessageService["send"] = (partialMsg) => { context: partialMsg.context, type: partialMsg.type, revalidateOnly: partialMsg.revalidateOnly, - authorUserId: partialMsg.authorUserId, + authorUserId: partialMsg.authorUserId ?? actorIdOrNullSafe() ?? undefined, }; }); diff --git a/app/features/scrims/actions/scrims.$id.server.ts b/app/features/scrims/actions/scrims.$id.server.ts index b17fbd3eb..17fa58291 100644 --- a/app/features/scrims/actions/scrims.$id.server.ts +++ b/app/features/scrims/actions/scrims.$id.server.ts @@ -103,7 +103,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { serializedPool, }); - broadcastRevalidate({ post, user }); + broadcastRevalidate(post); break; } case "REMOVE_MAP_LIST": { @@ -111,7 +111,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { await ScrimMapListRepository.deleteMapList(post.id, viewerSide); - broadcastRevalidate({ post, user }); + broadcastRevalidate(post); break; } case "REPORT_MAP": { @@ -127,7 +127,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { winnerSide: data.winnerSide, }); - broadcastRevalidate({ post, user }); + broadcastRevalidate(post); break; } case "UNDO_MAP": { @@ -138,7 +138,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { await ScrimMapRepository.undoMostRecentMap(post.id); - broadcastRevalidate({ post, user }); + broadcastRevalidate(post); break; } case "REPLAY_MAP": { @@ -203,18 +203,13 @@ async function loadMapByMapContext({ return { viewerSide: viewerSide!, maps, mapLists }; } -function broadcastRevalidate({ - post, - user, -}: { - post: NonNullable>>; - user: ReturnType; -}) { +function broadcastRevalidate( + post: NonNullable>>, +) { if (!post.chatCode) return; ChatSystemMessage.send({ room: post.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } diff --git a/app/features/sendouq-match/actions/q.match.$id.server.ts b/app/features/sendouq-match/actions/q.match.$id.server.ts index 7eaf01472..9cb254123 100644 --- a/app/features/sendouq-match/actions/q.match.$id.server.ts +++ b/app/features/sendouq-match/actions/q.match.$id.server.ts @@ -103,7 +103,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: match.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } } @@ -156,7 +155,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: match.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } @@ -164,7 +162,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: SENDOUQ_LOOKING_ROOM, revalidateOnly: true, - authorUserId: user.id, }); break; @@ -237,7 +234,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: SENDOUQ_LOOKING_ROOM, revalidateOnly: true, - authorUserId: user.id, }); } @@ -245,7 +241,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: match.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } @@ -297,7 +292,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: match.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } @@ -322,7 +316,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: match.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } @@ -402,7 +395,6 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: match.chatCode, revalidateOnly: true, - authorUserId: user.id, }); } diff --git a/app/features/sendouq/actions/q.looking.server.ts b/app/features/sendouq/actions/q.looking.server.ts index 996b9d693..228f99525 100644 --- a/app/features/sendouq/actions/q.looking.server.ts +++ b/app/features/sendouq/actions/q.looking.server.ts @@ -37,14 +37,12 @@ export const action: ActionFunction = async ({ request }) => { ChatSystemMessage.send({ room: SENDOUQ_LOOKING_ROOM, revalidateOnly: true, - authorUserId: user.id, }); const revalidateGroupTopic = (groupId: number) => ChatSystemMessage.send({ room: sqGroupWebsocketRoom(groupId), revalidateOnly: true, - authorUserId: user.id, }); const notifyLikeReceived = (groupId: number) => @@ -52,7 +50,6 @@ export const action: ActionFunction = async ({ request }) => { room: sqGroupWebsocketRoom(groupId), type: "LIKE_RECEIVED", revalidateOnly: true, - authorUserId: user.id, }); try { @@ -215,13 +212,11 @@ export const action: ActionFunction = async ({ request }) => { room: sqGroupWebsocketRoom(ownGroup.id), type: "MATCH_STARTED", revalidateOnly: true, - authorUserId: user.id, }, { room: sqGroupWebsocketRoom(theirGroup.id), type: "MATCH_STARTED", revalidateOnly: true, - authorUserId: user.id, }, ]); diff --git a/app/features/sendouq/actions/q.preparing.server.ts b/app/features/sendouq/actions/q.preparing.server.ts index f2818d9ba..188450d50 100644 --- a/app/features/sendouq/actions/q.preparing.server.ts +++ b/app/features/sendouq/actions/q.preparing.server.ts @@ -44,7 +44,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: SENDOUQ_LOOKING_ROOM, revalidateOnly: true, - authorUserId: user.id, }); return redirect(SENDOUQ_LOOKING_PAGE); @@ -78,7 +77,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: chatCodeToRevalidate, revalidateOnly: true, - authorUserId: user.id, }); } @@ -95,7 +93,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { ChatSystemMessage.send({ room: sqGroupWebsocketRoom(ownGroup.id), revalidateOnly: true, - authorUserId: user.id, }); notify({ diff --git a/app/features/sendouq/actions/q.server.ts b/app/features/sendouq/actions/q.server.ts index aa39de5a2..3c884d1b6 100644 --- a/app/features/sendouq/actions/q.server.ts +++ b/app/features/sendouq/actions/q.server.ts @@ -54,7 +54,6 @@ export const action: ActionFunction = async ({ request, url }) => { ChatSystemMessage.send({ room: chatCodeToRevalidate, revalidateOnly: true, - authorUserId: user.id, }); } @@ -66,7 +65,6 @@ export const action: ActionFunction = async ({ request, url }) => { ChatSystemMessage.send({ room: SENDOUQ_LOOKING_ROOM, revalidateOnly: true, - authorUserId: user.id, }); } @@ -100,7 +98,6 @@ export const action: ActionFunction = async ({ request, url }) => { ChatSystemMessage.send({ room: chatCodeToRevalidate, revalidateOnly: true, - authorUserId: user.id, }); } @@ -120,7 +117,6 @@ export const action: ActionFunction = async ({ request, url }) => { ChatSystemMessage.send({ room: sqGroupWebsocketRoom(groupInvitedTo.id), revalidateOnly: true, - authorUserId: user.id, }); } else { // Joining an active group changes its size/suitability for the whole @@ -129,7 +125,6 @@ export const action: ActionFunction = async ({ request, url }) => { ChatSystemMessage.send({ room: SENDOUQ_LOOKING_ROOM, revalidateOnly: true, - authorUserId: user.id, }); } diff --git a/app/features/tournament-admin/actions/to.$id.admin.index.server.ts b/app/features/tournament-admin/actions/to.$id.admin.index.server.ts index 4136fac76..793ad0066 100644 --- a/app/features/tournament-admin/actions/to.$id.admin.index.server.ts +++ b/app/features/tournament-admin/actions/to.$id.admin.index.server.ts @@ -123,7 +123,6 @@ export const action: ActionFunction = async ({ request, params }) => { sendDroppedMatchChatMessages({ tournamentId: tournament.ctx.id, endedMatchIds, - authorUserId: user.id, }); break; @@ -196,11 +195,9 @@ async function dropTeamOut({ function sendDroppedMatchChatMessages({ tournamentId, endedMatchIds, - authorUserId, }: { tournamentId: number; endedMatchIds: number[]; - authorUserId: number; }) { if (endedMatchIds.length === 0) return; @@ -209,13 +206,11 @@ function sendDroppedMatchChatMessages({ room: tournamentMatchWebsocketRoom(matchId), type: "TOURNAMENT_MATCH_UPDATED" as const, revalidateOnly: true as const, - authorUserId, })), { room: tournamentWebsocketRoom(tournamentId), type: "TOURNAMENT_UPDATED" as const, revalidateOnly: true as const, - authorUserId, }, ]); } diff --git a/app/features/tournament-bracket/actions/to.$id.brackets.server.ts b/app/features/tournament-bracket/actions/to.$id.brackets.server.ts index 63303928f..fe995a270 100644 --- a/app/features/tournament-bracket/actions/to.$id.brackets.server.ts +++ b/app/features/tournament-bracket/actions/to.$id.brackets.server.ts @@ -348,7 +348,6 @@ export const action: ActionFunction = async ({ params, request }) => { room: tournamentWebsocketRoom(tournament.ctx.id), type: "TOURNAMENT_UPDATED", revalidateOnly: true, - authorUserId: user.id, }, ]); } diff --git a/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts b/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts index bfaacaf55..a0654faa2 100644 --- a/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts +++ b/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts @@ -882,13 +882,11 @@ export const action: ActionFunction = async ({ params, request }) => { room: tournamentMatchWebsocketRoom(matchId), type: "TOURNAMENT_MATCH_UPDATED", revalidateOnly: true, - authorUserId: user.id, }, ...otherMatchIdsToRevalidate.map((id) => ({ room: tournamentMatchWebsocketRoom(id), type: "TOURNAMENT_MATCH_UPDATED" as const, revalidateOnly: true as const, - authorUserId: user.id, })), ]); } @@ -898,7 +896,6 @@ export const action: ActionFunction = async ({ params, request }) => { room: tournamentWebsocketRoom(tournament.ctx.id), type: "TOURNAMENT_UPDATED", revalidateOnly: true, - authorUserId: user.id, }, ]); }