feat(auth): add custom adapter for generating unique usernames
This commit is contained in:
+95
-1
@@ -4,10 +4,104 @@ import { db } from "@/lib/db";
|
||||
import { getConfig } from "@/lib/config";
|
||||
import { initializePlugins, getAuthPlugin } from "@/lib/plugins";
|
||||
import type { User } from "@prisma/client";
|
||||
import type { Adapter, AdapterUser } from "next-auth/adapters";
|
||||
|
||||
// Initialize plugins before use
|
||||
initializePlugins();
|
||||
|
||||
// Generate a unique username from email or name
|
||||
async function generateUsername(email: string, name?: string | null): Promise<string> {
|
||||
// Try to use the part before @ in email
|
||||
let baseUsername = email.split("@")[0].toLowerCase().replace(/[^a-z0-9_]/g, "");
|
||||
|
||||
// If too short, use name
|
||||
if (baseUsername.length < 3 && name) {
|
||||
baseUsername = name.toLowerCase().replace(/[^a-z0-9_]/g, "").slice(0, 15);
|
||||
}
|
||||
|
||||
// Ensure minimum length
|
||||
if (baseUsername.length < 3) {
|
||||
baseUsername = "user";
|
||||
}
|
||||
|
||||
// Check if username exists and append number if needed
|
||||
let username = baseUsername;
|
||||
let counter = 1;
|
||||
while (await db.user.findUnique({ where: { username } })) {
|
||||
username = `${baseUsername}${counter}`;
|
||||
counter++;
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
// Custom adapter that wraps PrismaAdapter to add username
|
||||
function CustomPrismaAdapter(): Adapter {
|
||||
const prismaAdapter = PrismaAdapter(db);
|
||||
|
||||
return {
|
||||
...prismaAdapter,
|
||||
async createUser(data: AdapterUser & { username?: string }) {
|
||||
// Use GitHub username if provided, otherwise generate one
|
||||
let username = (data as any).username;
|
||||
if (!username) {
|
||||
username = await generateUsername(data.email, data.name);
|
||||
} else {
|
||||
username = username.toLowerCase();
|
||||
|
||||
// Check if there's an unclaimed account with this username
|
||||
const unclaimedEmail = `${username}@unclaimed.prompts.chat`;
|
||||
const unclaimedUser = await db.user.findUnique({
|
||||
where: { email: unclaimedEmail },
|
||||
});
|
||||
|
||||
if (unclaimedUser) {
|
||||
// Claim this account - update with real user info
|
||||
const claimedUser = await db.user.update({
|
||||
where: { id: unclaimedUser.id },
|
||||
data: {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
avatar: data.image,
|
||||
emailVerified: data.emailVerified,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...claimedUser,
|
||||
image: claimedUser.avatar,
|
||||
} as AdapterUser;
|
||||
}
|
||||
|
||||
// Ensure GitHub username is unique, append number if taken
|
||||
const baseUsername = username;
|
||||
let finalUsername = baseUsername;
|
||||
let counter = 1;
|
||||
while (await db.user.findUnique({ where: { username: finalUsername } })) {
|
||||
finalUsername = `${baseUsername}${counter}`;
|
||||
counter++;
|
||||
}
|
||||
username = finalUsername;
|
||||
}
|
||||
|
||||
const user = await db.user.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
avatar: data.image,
|
||||
emailVerified: data.emailVerified,
|
||||
username,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...user,
|
||||
image: user.avatar,
|
||||
} as AdapterUser;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Build auth config dynamically based on prompts.config.ts
|
||||
async function buildAuthConfig() {
|
||||
const config = await getConfig();
|
||||
@@ -18,7 +112,7 @@ async function buildAuthConfig() {
|
||||
}
|
||||
|
||||
return {
|
||||
adapter: PrismaAdapter(db),
|
||||
adapter: CustomPrismaAdapter(),
|
||||
providers: [authPlugin.getProvider()],
|
||||
session: {
|
||||
strategy: "jwt" as const,
|
||||
|
||||
@@ -8,5 +8,14 @@ export const githubPlugin: AuthPlugin = {
|
||||
GitHub({
|
||||
clientId: process.env.GITHUB_CLIENT_ID!,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.id.toString(),
|
||||
name: profile.name || profile.login,
|
||||
email: profile.email,
|
||||
image: profile.avatar_url,
|
||||
username: profile.login, // GitHub username
|
||||
};
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user