feat(admin-auth): support username login and add dashboard logout
This commit is contained in:
@@ -2,8 +2,10 @@ import {
|
||||
authRouteHandlers,
|
||||
canUserSelfRegister,
|
||||
ensureSupportUserBootstrap,
|
||||
ensureUserUsername,
|
||||
hasOwnerUser,
|
||||
promoteFirstRegisteredUserToOwner,
|
||||
resolveEmailFromLoginIdentifier,
|
||||
} from "@/lib/auth/server"
|
||||
|
||||
export const runtime = "nodejs"
|
||||
@@ -12,6 +14,9 @@ type AuthPostResponse = {
|
||||
user?: {
|
||||
id?: string
|
||||
role?: string
|
||||
email?: string
|
||||
name?: string
|
||||
username?: string
|
||||
}
|
||||
message?: string
|
||||
}
|
||||
@@ -20,9 +25,54 @@ function jsonResponse(payload: unknown, status: number): Response {
|
||||
return Response.json(payload, { status })
|
||||
}
|
||||
|
||||
async function parseJsonBody(request: Request): Promise<Record<string, unknown> | null> {
|
||||
return (await request.json().catch(() => null)) as Record<string, unknown> | null
|
||||
}
|
||||
|
||||
function buildJsonRequest(request: Request, body: Record<string, unknown>): Request {
|
||||
const headers = new Headers(request.headers)
|
||||
headers.set("content-type", "application/json")
|
||||
|
||||
return new Request(request.url, {
|
||||
method: request.method,
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
}
|
||||
|
||||
async function handleSignInPost(request: Request): Promise<Response> {
|
||||
await ensureSupportUserBootstrap()
|
||||
|
||||
const body = await parseJsonBody(request)
|
||||
const identifier = typeof body?.identifier === "string" ? body.identifier : null
|
||||
const rawEmail = typeof body?.email === "string" ? body.email : null
|
||||
const resolvedEmail = await resolveEmailFromLoginIdentifier(identifier ?? rawEmail)
|
||||
|
||||
if (!resolvedEmail) {
|
||||
return jsonResponse(
|
||||
{
|
||||
message: "Invalid email or username.",
|
||||
},
|
||||
401,
|
||||
)
|
||||
}
|
||||
|
||||
const rewrittenBody = {
|
||||
...(body ?? {}),
|
||||
email: resolvedEmail,
|
||||
}
|
||||
|
||||
return authRouteHandlers.POST(buildJsonRequest(request, rewrittenBody))
|
||||
}
|
||||
|
||||
async function handleSignUpPost(request: Request): Promise<Response> {
|
||||
await ensureSupportUserBootstrap()
|
||||
|
||||
const signUpBody = await parseJsonBody(request)
|
||||
const preferredUsername =
|
||||
typeof signUpBody?.username === "string" ? signUpBody.username : undefined
|
||||
const { username: _ignoredUsername, ...signUpBodyWithoutUsername } = signUpBody ?? {}
|
||||
|
||||
const hadOwnerBeforeSignUp = await hasOwnerUser()
|
||||
const registrationEnabled = await canUserSelfRegister()
|
||||
|
||||
@@ -35,7 +85,11 @@ async function handleSignUpPost(request: Request): Promise<Response> {
|
||||
)
|
||||
}
|
||||
|
||||
const response = await authRouteHandlers.POST(request)
|
||||
const response = await authRouteHandlers.POST(
|
||||
buildJsonRequest(request, {
|
||||
...signUpBodyWithoutUsername,
|
||||
}),
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
return response
|
||||
@@ -51,6 +105,12 @@ async function handleSignUpPost(request: Request): Promise<Response> {
|
||||
return response
|
||||
}
|
||||
|
||||
await ensureUserUsername(userId, {
|
||||
preferred: preferredUsername,
|
||||
fallbackEmail: payload?.user?.email,
|
||||
fallbackName: payload?.user?.name,
|
||||
})
|
||||
|
||||
if (hadOwnerBeforeSignUp || !payload?.user) {
|
||||
return response
|
||||
}
|
||||
@@ -82,6 +142,10 @@ export async function GET(request: Request): Promise<Response> {
|
||||
export async function POST(request: Request): Promise<Response> {
|
||||
const pathname = new URL(request.url).pathname
|
||||
|
||||
if (pathname.endsWith("/sign-in/email")) {
|
||||
return handleSignInPost(request)
|
||||
}
|
||||
|
||||
if (pathname.endsWith("/sign-up/email")) {
|
||||
return handleSignUpPost(request)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user