clerkauth
implemented, sync with db to be added
This commit is contained in:
1 parent
ca790a7b97
commit
3a58d420d6
49 files changed
+9423
-779
No files matched your search
@@ -0,0 +1,198 @@
|
||||
import { clerkClient } from '@clerk/nextjs/server';
|
||||
|
||||
/**
|
||||
* User roles available in the application
|
||||
*/
|
||||
export type UserRole = 'admin' | 'trainer' | 'client';
|
||||
|
||||
/**
|
||||
* Set a user's role in Clerk public metadata
|
||||
* This will trigger a webhook that syncs the role to the database
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @param role - Role to assign (admin, trainer, or client)
|
||||
* @returns Updated user object
|
||||
*
|
||||
* @example
|
||||
* await setUserRole('user_abc123', 'admin');
|
||||
*/
|
||||
export async function setUserRole(userId: string, role: UserRole) {
|
||||
const client = await clerkClient();
|
||||
|
||||
return await client.users.updateUser(userId, {
|
||||
publicMetadata: { role },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user's role from Clerk public metadata
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @returns User role or null if not set
|
||||
*
|
||||
* @example
|
||||
* const role = await getUserRole('user_abc123');
|
||||
* console.log(role); // 'admin' | 'trainer' | 'client' | null
|
||||
*/
|
||||
export async function getUserRole(userId: string): Promise<UserRole | null> {
|
||||
const client = await clerkClient();
|
||||
const user = await client.users.getUser(userId);
|
||||
|
||||
const role = user.publicMetadata?.role as UserRole | undefined;
|
||||
return role || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user has a specific role
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @param role - Role to check
|
||||
* @returns True if user has the role
|
||||
*
|
||||
* @example
|
||||
* const isAdmin = await hasRole('user_abc123', 'admin');
|
||||
*/
|
||||
export async function hasRole(userId: string, role: UserRole): Promise<boolean> {
|
||||
const userRole = await getUserRole(userId);
|
||||
return userRole === role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is an admin
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @returns True if user is an admin
|
||||
*
|
||||
* @example
|
||||
* const isAdmin = await isAdmin('user_abc123');
|
||||
*/
|
||||
export async function isAdmin(userId: string): Promise<boolean> {
|
||||
return hasRole(userId, 'admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is a trainer
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @returns True if user is a trainer
|
||||
*
|
||||
* @example
|
||||
* const isTrainer = await isTrainer('user_abc123');
|
||||
*/
|
||||
export async function isTrainer(userId: string): Promise<boolean> {
|
||||
return hasRole(userId, 'trainer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is a client
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @returns True if user is a client
|
||||
*
|
||||
* @example
|
||||
* const isClient = await isClient('user_abc123');
|
||||
*/
|
||||
export async function isClient(userId: string): Promise<boolean> {
|
||||
return hasRole(userId, 'client');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk update roles for multiple users
|
||||
*
|
||||
* @param userRoles - Array of {userId, role} objects
|
||||
* @returns Array of updated users
|
||||
*
|
||||
* @example
|
||||
* await bulkSetUserRoles([
|
||||
* { userId: 'user_abc123', role: 'admin' },
|
||||
* { userId: 'user_def456', role: 'trainer' },
|
||||
* ]);
|
||||
*/
|
||||
export async function bulkSetUserRoles(
|
||||
userRoles: Array<{ userId: string; role: UserRole }>
|
||||
): Promise<void> {
|
||||
const client = await clerkClient();
|
||||
|
||||
await Promise.all(
|
||||
userRoles.map(({ userId, role }) =>
|
||||
client.users.updateUser(userId, {
|
||||
publicMetadata: { role },
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users with a specific role
|
||||
*
|
||||
* @param role - Role to filter by
|
||||
* @returns Array of users with the specified role
|
||||
*
|
||||
* @example
|
||||
* const admins = await getUsersByRole('admin');
|
||||
*/
|
||||
export async function getUsersByRole(role: UserRole) {
|
||||
const client = await clerkClient();
|
||||
|
||||
// Clerk doesn't support filtering by metadata directly, so we fetch all users
|
||||
// and filter client-side. For large user bases, consider caching or database queries.
|
||||
const { data: users } = await client.users.getUserList();
|
||||
|
||||
return users.filter(
|
||||
(user) => (user.publicMetadata?.role as UserRole) === role
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user count by role
|
||||
*
|
||||
* @returns Object with counts for each role
|
||||
*
|
||||
* @example
|
||||
* const counts = await getUserCountByRole();
|
||||
* console.log(counts); // { admin: 2, trainer: 5, client: 100 }
|
||||
*/
|
||||
export async function getUserCountByRole(): Promise<Record<UserRole, number>> {
|
||||
const client = await clerkClient();
|
||||
const { data: users } = await client.users.getUserList();
|
||||
|
||||
const counts: Record<UserRole, number> = {
|
||||
admin: 0,
|
||||
trainer: 0,
|
||||
client: 0,
|
||||
};
|
||||
|
||||
users.forEach((user) => {
|
||||
const role = (user.publicMetadata?.role as UserRole) || 'client';
|
||||
counts[role]++;
|
||||
});
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync user role between Clerk and database manually
|
||||
* Useful for fixing inconsistencies or after manual changes
|
||||
*
|
||||
* @param userId - Clerk user ID
|
||||
* @returns Success status
|
||||
*
|
||||
* @example
|
||||
* await syncUserRole('user_abc123');
|
||||
*/
|
||||
export async function syncUserRole(userId: string): Promise<boolean> {
|
||||
try {
|
||||
const client = await clerkClient();
|
||||
const user = await client.users.getUser(userId);
|
||||
|
||||
// Trigger a webhook by updating the user (even with same data)
|
||||
await client.users.updateUser(userId, {
|
||||
publicMetadata: user.publicMetadata,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error syncing user role:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user