Skip to content

fix: Multiple Admin Support#46

Open
SyedHannanMehdi wants to merge 14 commits into
Fahad-Dezloper:mainfrom
SyedHannanMehdi:cashclaw/fix-27-multiple-admin-support
Open

fix: Multiple Admin Support#46
SyedHannanMehdi wants to merge 14 commits into
Fahad-Dezloper:mainfrom
SyedHannanMehdi:cashclaw/fix-27-multiple-admin-support

Conversation

@SyedHannanMehdi
Copy link
Copy Markdown

Automated fix for #27 — implemented by CashClaw agent.

Closes #27

Copilot AI review requested due to automatic review settings March 29, 2026 20:58
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 29, 2026

@SyedHannanMehdi is attempting to deploy a commit to the fahad-dezloper's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an admin-role system intended to support multiple admins by introducing a role enum, invite flow, and admin-only API endpoints.

Changes:

  • Introduces AdminRole, User.role, and an AdminInvite model + migration.
  • Adds admin helper utilities (getCurrentUser, role hierarchy checks) and admin API routes to list users, update roles, and issue/accept invites.
  • Adds a new NextAuth configuration (authOptions) and NextAuth type augmentation for session.user.role.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
types/next-auth.d.ts Extends NextAuth session/user types to include id and role.
prisma/schema.prisma Replaces Prisma schema with AdminRole + invite + (unrelated) new auth/campaign models.
prisma/migrations/20240101000000_add_admin_roles/migration.sql Adds AdminRole enum, User.role, and AdminInvite table.
lib/auth.ts Adds NextAuth authOptions with PrismaAdapter and a session callback adding role/id.
lib/admin.ts Adds helpers for current user lookup, role checks, and seeding a super admin.
app/api/admin/users/route.ts Adds admin-protected endpoint to list users (and roles).
app/api/admin/users/[id]/role/route.ts Adds super-admin-only role update/removal endpoints.
app/api/admin/invite/route.ts Adds super-admin invite creation and pending-invite listing endpoints.
app/api/admin/invite/accept/route.ts Adds endpoint for an authenticated user to accept an invite token.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/api/admin/users/[id]/role/route.ts Outdated
Comment on lines +62 to +66
const updated = await prisma.user.update({
where: { id },
data: { role: null },
select: { id: true, name: true, email: true, role: true },
});
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as PATCH: prisma.user.update will throw if id doesn’t exist, causing an unhandled 500. Consider handling the “user not found” case and returning 404 for invalid ids.

Copilot uses AI. Check for mistakes.
Comment thread app/api/admin/users/route.ts Outdated
Comment on lines +6 to +14
// GET /api/admin/users — list all users with roles (ADMIN+)
export async function GET() {
const user = await getCurrentUser();

if (!user || !hasRole(user.role, AdminRole.ADMIN)) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}

const users = await prisma.user.findMany({
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says this endpoint lists “all users with roles”, but the query returns all users (including those with role: null). Either update the comment to match behavior or filter the query (e.g., where: { role: { not: null } }) if the endpoint should only return admins.

Copilot uses AI. Check for mistakes.
Comment thread prisma/schema.prisma Outdated
Comment on lines 13 to 34
enum AdminRole {
SUPER_ADMIN
ADMIN
MODERATOR
}

model Room {
id String @id @default(uuid())
code String @unique
name String
adminId String
admin User @relation(fields: [adminId], references: [id])
users RoomUser[]
streams Stream[]
messages Message[]
allowSongAdd Boolean @default(true) // Admin can control this
createdAt DateTime @default(now())
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
role AdminRole?
accounts Account[]
sessions Session[]
campaigns Campaign[]
donations Donation[]
adminInvitesSent AdminInvite[] @relation("InvitedBy")

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prisma/schema.prisma has been rewritten to a completely different domain model (Campaign/Donation + NextAuth Account/Session tables) and removes existing models (e.g., Room/RoomUser/Stream/Upvote/Message) that are referenced throughout the app (e.g., prismaClient.room in app/api/room/create). This will break Prisma Client generation and runtime queries, and it also no longer matches the existing migration history. Suggestion: revert to the current schema and apply the “multiple admin support” change incrementally (e.g., add AdminRole + User.role + AdminInvite while keeping the existing Room/Stream models intact).

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +6
-- AlterTable: Add role to User
ALTER TABLE "User" ADD COLUMN "role" "AdminRole";

Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migration folder name 20240101000000_add_admin_roles sorts before the existing 202502..._init migration, but it runs ALTER TABLE "User" ... which will fail if User hasn’t been created yet. Rename/regenerate this migration with a timestamp after the latest migration and ensure it is based on the current schema state so it applies cleanly.

Copilot uses AI. Check for mistakes.
Comment thread lib/auth.ts
Comment on lines +1 to +8
import { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";

export const authOptions: NextAuthOptions = {
// @ts-ignore – PrismaAdapter type mismatch between next-auth versions
adapter: PrismaAdapter(prisma),
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib/auth.ts won’t compile as-is: it imports PrismaAdapter from @auth/prisma-adapter, but that package isn’t listed in package.json, and it also imports prisma from @/lib/prisma which doesn’t exist in the repo. Either add the missing dependency and a lib/prisma.ts singleton (or switch these imports to the existing prismaClient from app/lib/db.ts) so the auth configuration can actually be used.

Copilot uses AI. Check for mistakes.
Comment thread lib/admin.ts
Comment on lines +1 to +12
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { AdminRole } from "@prisma/client";

/**
* Returns the current session's user with their role,
* or null if the user is not authenticated.
*/
export async function getCurrentUser() {
const session = await getServerSession(authOptions);
if (!session?.user?.email) return null;
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getServerSession(authOptions) here will only work if the same authOptions is also used by the NextAuth handler in app/api/auth/[...nextauth]/route.ts. Currently the repo defines NextAuth options inline in that route (no adapter / different callbacks), so this can lead to sessions not being decoded or user data not matching. Consider centralizing the NextAuth config (export authOptions and use it both in the handler and in getServerSession).

Copilot uses AI. Check for mistakes.
Comment thread app/api/admin/users/[id]/role/route.ts Outdated
Comment on lines +36 to +40
const updated = await prisma.user.update({
where: { id },
data: { role: role ?? null },
select: { id: true, name: true, email: true, role: true },
});
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prisma.user.update({ where: { id } ... }) will throw a Prisma P2025 error if the user id doesn’t exist, which will currently surface as a 500 from the route. Handle the “record not found” case explicitly (e.g., catch Prisma known request errors and return 404).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple Admin Support

2 participants