3 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
b53934ebf2 Make all users admins: update schema default, add migration, simplify registration and OAuth flows
Co-authored-by: xCyanGrizzly <53275238+xCyanGrizzly@users.noreply.github.com>
2026-03-04 20:23:54 +00:00
copilot-swe-agent[bot]
464c86b32a Initial plan 2026-03-04 20:16:22 +00:00
xCyanGrizzly
fc00fb6f2e Merge pull request #8 from xCyanGrizzly/copilot/fix-admin-account-login
Fix first user not getting ADMIN role when signing up via OAuth
2026-03-04 20:24:38 +01:00
4 changed files with 26 additions and 32 deletions

View File

@@ -0,0 +1,5 @@
-- Promote all existing users to ADMIN (self-hosted: every user is an admin)
UPDATE "User" SET "role" = 'ADMIN' WHERE "role" = 'USER';
-- Change the default role for new users to ADMIN
ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'ADMIN';

View File

@@ -22,7 +22,7 @@ model User {
emailVerified DateTime? emailVerified DateTime?
image String? image String?
hashedPassword String? hashedPassword String?
role Role @default(USER) role Role @default(ADMIN)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt

View File

@@ -21,17 +21,13 @@ export async function registerUser(input: unknown): Promise<ActionResult<{ id: s
const hashedPassword = await bcrypt.hash(parsed.data.password, 10); const hashedPassword = await bcrypt.hash(parsed.data.password, 10);
// First user to register becomes ADMIN (self-hosted owner) // Self-hosted: all users are admins
const user = await prisma.$transaction(async (tx) => { const user = await prisma.user.create({
const userCount = await tx.user.count();
const role = userCount === 0 ? "ADMIN" : "USER";
return tx.user.create({
data: { data: {
name: parsed.data.name, name: parsed.data.name,
email: parsed.data.email, email: parsed.data.email,
hashedPassword, hashedPassword,
role, role: "ADMIN",
settings: { settings: {
create: { create: {
lowStockThreshold: 10, lowStockThreshold: 10,
@@ -42,7 +38,6 @@ export async function registerUser(input: unknown): Promise<ActionResult<{ id: s
}, },
}, },
}); });
});
return { success: true, data: { id: user.id } }; return { success: true, data: { id: user.id } };
} }

View File

@@ -18,12 +18,12 @@ export const { auth, handlers, signIn, signOut } = NextAuth({
async jwt({ token, user }) { async jwt({ token, user }) {
if (user) { if (user) {
token.id = user.id!; token.id = user.id!;
// Fetch the role from the database to pick up first-user ADMIN promotion // Fetch the role from the database to ensure token reflects current role
const dbUser = await prisma.user.findUnique({ const dbUser = await prisma.user.findUnique({
where: { id: user.id! }, where: { id: user.id! },
select: { role: true }, select: { role: true },
}); });
token.role = dbUser?.role ?? user.role ?? "USER"; token.role = dbUser?.role ?? user.role ?? "ADMIN";
} }
return token; return token;
}, },
@@ -38,17 +38,11 @@ export const { auth, handlers, signIn, signOut } = NextAuth({
events: { events: {
async createUser({ user }) { async createUser({ user }) {
if (user.id) { if (user.id) {
// First user to register becomes ADMIN (self-hosted owner) // Self-hosted: all users are admins
const adminExists = await prisma.user.findFirst({
where: { role: "ADMIN" },
select: { id: true },
});
if (!adminExists) {
await prisma.user.update({ await prisma.user.update({
where: { id: user.id }, where: { id: user.id },
data: { role: "ADMIN" }, data: { role: "ADMIN" },
}); });
}
await prisma.userSettings.upsert({ await prisma.userSettings.upsert({
where: { userId: user.id }, where: { userId: user.id },