diff --git a/.changeset/funny-roses-wink.md b/.changeset/funny-roses-wink.md new file mode 100644 index 0000000..887398e --- /dev/null +++ b/.changeset/funny-roses-wink.md @@ -0,0 +1,5 @@ +--- +"namesake": patch +--- + +Default the user role to admin during signup when the environment is set to development. diff --git a/convex/auth.test.ts b/convex/auth.test.ts new file mode 100644 index 0000000..e41a227 --- /dev/null +++ b/convex/auth.test.ts @@ -0,0 +1,50 @@ +import { convexTest } from "convex-test"; +import { describe, expect, it, vi } from "vitest"; +import { api } from "./_generated/api"; +import { createOrUpdateUser } from "./auth"; +import schema from "./schema"; +import { modules } from "./test.setup"; + +describe("auth", () => { + describe("createOrUpdateUser", () => { + it("should set role to admin in development environment", async () => { + const t = convexTest(schema, modules); + + vi.stubEnv("NODE_ENV", "development"); + await t.run(async (ctx) => { + return await createOrUpdateUser(ctx, { + profile: { + email: "devUser@test.com", + }, + }); + }); + + const user = await t.query(api.users.getByEmail, { + email: "devUser@test.com", + }); + + expect(user?.role).toBe("admin"); + vi.unstubAllEnvs(); + }); + + it("should set role to user in production environment", async () => { + const t = convexTest(schema, modules); + + vi.stubEnv("NODE_ENV", "production"); + await t.run(async (ctx) => { + return await createOrUpdateUser(ctx, { + profile: { + email: "prodUser@test.com", + }, + }); + }); + + const user = await t.query(api.users.getByEmail, { + email: "prodUser@test.com", + }); + + expect(user?.role).toBe("user"); + vi.unstubAllEnvs(); + }); + }); +}); diff --git a/convex/auth.ts b/convex/auth.ts index 76c7eb6..0c6ebf8 100644 --- a/convex/auth.ts +++ b/convex/auth.ts @@ -4,41 +4,42 @@ import type { MutationCtx } from "./_generated/server"; import { ResendOTPPasswordReset } from "./passwordReset"; import { getByEmail } from "./users"; -export const { auth, signIn, signOut, store } = convexAuth({ - providers: [Password({ reset: ResendOTPPasswordReset })], +export const createOrUpdateUser = async (ctx: MutationCtx, args: any) => { + // Handle merging updated fields into existing user + if (args.existingUserId) { + return args.existingUserId; + } - callbacks: { - async createOrUpdateUser(ctx: MutationCtx, args) { - // Handle merging updated fields into existing user - if (args.existingUserId) { - return args.existingUserId; - } + // Handle account linking + if (args.profile.email) { + const existingUser = await getByEmail(ctx, { + email: args.profile.email, + }); + if (existingUser) return existingUser._id; + } - // Handle account linking - if (args.profile.email) { - const existingUser = await getByEmail(ctx, { - email: args.profile.email, - }); - if (existingUser) return existingUser._id; - } + // Create a new user with defaults + return ctx.db + .insert("users", { + email: args.profile.email, + emailVerified: args.profile.emailVerified ?? false, + role: process.env.NODE_ENV === "development" ? "admin" : "user", + }) + .then((userId) => { + ctx.db.insert("userSettings", { + userId, + theme: "system", + groupQuestsBy: "dateAdded", + }); + return userId; + }); +}; - // Create a new user with defaults - return ctx.db - .insert("users", { - email: args.profile.email, - emailVerified: args.profile.emailVerified ?? false, - role: "user", - }) - .then((userId) => { - ctx.db.insert("userSettings", { - userId, - theme: "system", - groupQuestsBy: "dateAdded", - }); - return userId; - }); - }, +export const { auth, signIn, signOut, store } = convexAuth({ + providers: [Password({ reset: ResendOTPPasswordReset })], + callbacks: { + createOrUpdateUser, async redirect({ redirectTo }) { return redirectTo; },