-
Notifications
You must be signed in to change notification settings - Fork 454
Upgrade react router and add auth middleware #1040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
9f9766a
05e00cf
1e86901
d0db7c6
ff7fc72
426b315
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { createContext } from 'react-router' | ||
|
||
// Holds the authenticated user's ID for routes protected by middleware | ||
export const userIdContext = createContext<string | null>(null) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { redirect, type MiddlewareFunction } from 'react-router' | ||
import { prisma } from '#app/utils/db.server.ts' | ||
import { authSessionStorage } from '#app/utils/session.server.ts' | ||
import { userIdContext } from '#app/context.ts' | ||
|
||
export const requireUserMiddleware: MiddlewareFunction = async ({ | ||
request, | ||
context, | ||
}) => { | ||
const cookie = request.headers.get('cookie') | ||
const session = await authSessionStorage.getSession(cookie) | ||
const sessionId = session.get('sessionId') as string | undefined | ||
if (!sessionId) throw redirect(`/login?redirectTo=${encodeURIComponent(new URL(request.url).pathname)}`) | ||
|
||
const sessionRecord = await prisma.session.findUnique({ | ||
select: { userId: true, expirationDate: true }, | ||
where: { id: sessionId }, | ||
}) | ||
|
||
if (!sessionRecord || sessionRecord.expirationDate < new Date()) { | ||
throw redirect(`/login?redirectTo=${encodeURIComponent(new URL(request.url).pathname)}`) | ||
} | ||
|
||
context.set(userIdContext, sessionRecord.userId) | ||
} | ||
|
||
export const requireAnonymousMiddleware: MiddlewareFunction = async ({ | ||
request, | ||
}) => { | ||
const cookie = request.headers.get('cookie') | ||
const session = await authSessionStorage.getSession(cookie) | ||
const sessionId = session.get('sessionId') as string | undefined | ||
if (sessionId) throw redirect('/') | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
import { generateSitemap } from '@nasa-gcn/remix-seo' | ||
import { type ServerBuild } from 'react-router' | ||
import { type ServerBuild, RouterContextProvider, createContext } from 'react-router' | ||
import { getDomainUrl } from '#app/utils/misc.tsx' | ||
import { type Route } from './+types/sitemap[.]xml.ts' | ||
// recreate context key to match the one set in server getLoadContext | ||
export const serverBuildContext = createContext<Promise<{ error: unknown; build: ServerBuild }> | null>(null) | ||
|
||
export async function loader({ request, context }: Route.LoaderArgs) { | ||
const serverBuild = (await context.serverBuild) as { build: ServerBuild } | ||
const serverBuild = (await (context as Readonly<RouterContextProvider>).get(serverBuildContext)) as { build: ServerBuild } | ||
|
||
// TODO: This is typeerror is coming up since of the remix-run/server-runtime package. We might need to remove/update that one. | ||
// @ts-expect-error | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use this modified version https://gist.github.com/hilja/5e6f6ec6a86a3e06113501f8d60e20a4 |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { searchUsers } from '@prisma/client/sql' | ||
// using $queryRawUnsafe for LIKE query construction | ||
import { Img } from 'openimg/react' | ||
import { redirect, Link } from 'react-router' | ||
import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx' | ||
|
@@ -15,7 +15,10 @@ export async function loader({ request }: Route.LoaderArgs) { | |
} | ||
|
||
const like = `%${searchTerm ?? ''}%` | ||
const users = await prisma.$queryRawTyped(searchUsers(like)) | ||
const users = await prisma.$queryRawUnsafe<{ id: string; username: string; name: string | null; imageObjectKey: string | null }[]>( | ||
`SELECT id, username, name, (SELECT "objectKey" FROM "Image" WHERE "userId" = "User"."id" LIMIT 1) as "imageObjectKey" FROM "User" WHERE username ILIKE $1 OR name ILIKE $1 ORDER BY username ASC`, | ||
like, | ||
) | ||
|
||
return { status: 'idle', users } as const | ||
} | ||
|
||
|
@@ -49,7 +52,7 @@ export default function UsersRoute({ loaderData }: Route.ComponentProps) { | |
> | ||
<Img | ||
alt={user.name ?? user.username} | ||
src={getUserImgSrc(user.imageObjectKey)} | ||
src={getUserImgSrc(user.imageObjectKey ?? undefined)} | ||
className="size-16 rounded-full" | ||
width={256} | ||
height={256} | ||
|
@@ -70,7 +73,7 @@ export default function UsersRoute({ loaderData }: Route.ComponentProps) { | |
<p>No users found</p> | ||
) | ||
) : loaderData.status === 'error' ? ( | ||
<ErrorList errors={['There was an error parsing the results']} /> | ||
<ErrorList errors={["There was an error parsing the results"]} /> | ||
) : null} | ||
</main> | ||
</div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cursor, I don't think this is unstable. Should we remove the prefix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working on it! I'll start making changes in this branch.