conflict warning
This commit is contained in:
@@ -11,7 +11,7 @@ export async function GET(event: APIEvent) {
|
|||||||
if (error) {
|
if (error) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: `/login?error=${encodeURIComponent(error)}` },
|
headers: { Location: `/login?error=${encodeURIComponent(error)}` }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export async function GET(event: APIEvent) {
|
|||||||
if (!code) {
|
if (!code) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: "/login?error=missing_code" },
|
headers: { Location: "/login?error=missing_code" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,20 +35,33 @@ export async function GET(event: APIEvent) {
|
|||||||
// Redirect to account page on success
|
// Redirect to account page on success
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: result.redirectTo || "/account" },
|
headers: { Location: result.redirectTo || "/account" }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Redirect to login with error
|
// Redirect to login with error
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: "/login?error=auth_failed" },
|
headers: { Location: "/login?error=auth_failed" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("GitHub OAuth callback error:", error);
|
console.error("GitHub OAuth callback error:", error);
|
||||||
|
|
||||||
|
// Handle specific TRPC errors
|
||||||
|
if (error && typeof error === "object" && "code" in error) {
|
||||||
|
const trpcError = error as { code: string; message?: string };
|
||||||
|
|
||||||
|
if (trpcError.code === "CONFLICT") {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: { Location: "/login?error=email_in_use" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: "/login?error=server_error" },
|
headers: { Location: "/login?error=server_error" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function GET(event: APIEvent) {
|
|||||||
if (error) {
|
if (error) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: `/login?error=${encodeURIComponent(error)}` },
|
headers: { Location: `/login?error=${encodeURIComponent(error)}` }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export async function GET(event: APIEvent) {
|
|||||||
if (!code) {
|
if (!code) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: "/login?error=missing_code" },
|
headers: { Location: "/login?error=missing_code" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,20 +35,33 @@ export async function GET(event: APIEvent) {
|
|||||||
// Redirect to account page on success
|
// Redirect to account page on success
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: result.redirectTo || "/account" },
|
headers: { Location: result.redirectTo || "/account" }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Redirect to login with error
|
// Redirect to login with error
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: "/login?error=auth_failed" },
|
headers: { Location: "/login?error=auth_failed" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Google OAuth callback error:", error);
|
console.error("Google OAuth callback error:", error);
|
||||||
|
|
||||||
|
// Handle specific TRPC errors
|
||||||
|
if (error && typeof error === "object" && "code" in error) {
|
||||||
|
const trpcError = error as { code: string; message?: string };
|
||||||
|
|
||||||
|
if (trpcError.code === "CONFLICT") {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: { Location: "/login?error=email_in_use" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: { Location: "/login?error=server_error" },
|
headers: { Location: "/login?error=server_error" }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,9 @@ export default function LoginPage() {
|
|||||||
server_error: "Server error - please try again later",
|
server_error: "Server error - please try again later",
|
||||||
missing_params: "Invalid login link - missing parameters",
|
missing_params: "Invalid login link - missing parameters",
|
||||||
link_expired: "Login link has expired - please request a new one",
|
link_expired: "Login link has expired - please request a new one",
|
||||||
access_denied: "Access denied - you cancelled the login"
|
access_denied: "Access denied - you cancelled the login",
|
||||||
|
email_in_use:
|
||||||
|
"This email is already associated with another account. Please sign in with that account instead."
|
||||||
};
|
};
|
||||||
setError(errorMessages[errorParam] || "An error occurred during login");
|
setError(errorMessages[errorParam] || "An error occurred during login");
|
||||||
}
|
}
|
||||||
@@ -333,11 +335,22 @@ export default function LoginPage() {
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<div class="pt-12 md:pt-24">
|
<div class="pt-12 md:pt-24">
|
||||||
{/* Error message */}
|
{/* Error message */}
|
||||||
<div class="absolute -mt-12 text-center text-3xl text-red-400 italic">
|
<div class="absolute -mt-12 text-center text-red-400 italic">
|
||||||
<Show when={error() === "passwordMismatch"}>
|
<Show when={error() === "passwordMismatch"}>
|
||||||
Passwords did not match!
|
<div class="text-3xl">Passwords did not match!</div>
|
||||||
|
</Show>
|
||||||
|
<Show when={error() === "duplicate"}>
|
||||||
|
<div class="text-3xl">Email Already Exists!</div>
|
||||||
|
</Show>
|
||||||
|
<Show
|
||||||
|
when={
|
||||||
|
error() &&
|
||||||
|
error() !== "passwordMismatch" &&
|
||||||
|
error() !== "duplicate"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div class="max-w-md px-4 text-base">{error()}</div>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={error() === "duplicate"}>Email Already Exists!</Show>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
|
|||||||
@@ -154,10 +154,25 @@ export const authRouter = createTRPCRouter({
|
|||||||
// User exists - update email and image if changed
|
// User exists - update email and image if changed
|
||||||
userId = (res.rows[0] as unknown as User).id;
|
userId = (res.rows[0] as unknown as User).id;
|
||||||
|
|
||||||
await conn.execute({
|
try {
|
||||||
sql: `UPDATE User SET email = ?, email_verified = ?, image = ? WHERE id = ?`,
|
await conn.execute({
|
||||||
args: [email, emailVerified ? 1 : 0, icon, userId]
|
sql: `UPDATE User SET email = ?, email_verified = ?, image = ? WHERE id = ?`,
|
||||||
});
|
args: [email, emailVerified ? 1 : 0, icon, userId]
|
||||||
|
});
|
||||||
|
} catch (updateError: any) {
|
||||||
|
// Handle unique constraint error on email
|
||||||
|
if (
|
||||||
|
updateError.code === "SQLITE_CONSTRAINT" &&
|
||||||
|
updateError.message?.includes("User.email")
|
||||||
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "CONFLICT",
|
||||||
|
message:
|
||||||
|
"This email is already associated with another account. Please sign in with that account or use a different email address."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw updateError;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create new user
|
// Create new user
|
||||||
userId = uuidV4();
|
userId = uuidV4();
|
||||||
@@ -171,7 +186,23 @@ export const authRouter = createTRPCRouter({
|
|||||||
"github",
|
"github",
|
||||||
icon
|
icon
|
||||||
];
|
];
|
||||||
await conn.execute({ sql: insertQuery, args: insertParams });
|
|
||||||
|
try {
|
||||||
|
await conn.execute({ sql: insertQuery, args: insertParams });
|
||||||
|
} catch (insertError: any) {
|
||||||
|
// Handle unique constraint error on email
|
||||||
|
if (
|
||||||
|
insertError.code === "SQLITE_CONSTRAINT" &&
|
||||||
|
insertError.message?.includes("User.email")
|
||||||
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "CONFLICT",
|
||||||
|
message:
|
||||||
|
"This email is already associated with another account. Please sign in with that account or use a different email address."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw insertError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create JWT token
|
// Create JWT token
|
||||||
@@ -291,6 +322,7 @@ export const authRouter = createTRPCRouter({
|
|||||||
// User exists - update email, email_verified, display_name, and image if changed
|
// User exists - update email, email_verified, display_name, and image if changed
|
||||||
userId = (res.rows[0] as unknown as User).id;
|
userId = (res.rows[0] as unknown as User).id;
|
||||||
|
|
||||||
|
// No need to catch constraint error here since we're updating the same user's record
|
||||||
await conn.execute({
|
await conn.execute({
|
||||||
sql: `UPDATE User SET email = ?, email_verified = ?, display_name = ?, image = ? WHERE id = ?`,
|
sql: `UPDATE User SET email = ?, email_verified = ?, display_name = ?, image = ? WHERE id = ?`,
|
||||||
args: [email, email_verified ? 1 : 0, name, image, userId]
|
args: [email, email_verified ? 1 : 0, name, image, userId]
|
||||||
@@ -308,10 +340,26 @@ export const authRouter = createTRPCRouter({
|
|||||||
"google",
|
"google",
|
||||||
image
|
image
|
||||||
];
|
];
|
||||||
await conn.execute({
|
|
||||||
sql: insertQuery,
|
try {
|
||||||
args: insertParams
|
await conn.execute({
|
||||||
});
|
sql: insertQuery,
|
||||||
|
args: insertParams
|
||||||
|
});
|
||||||
|
} catch (insertError: any) {
|
||||||
|
// Handle unique constraint error on email
|
||||||
|
if (
|
||||||
|
insertError.code === "SQLITE_CONSTRAINT" &&
|
||||||
|
insertError.message?.includes("User.email")
|
||||||
|
) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "CONFLICT",
|
||||||
|
message:
|
||||||
|
"This email is already associated with another account. Please sign in with that account instead."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw insertError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create JWT token
|
// Create JWT token
|
||||||
|
|||||||
Reference in New Issue
Block a user