refactor: remove username from User model, login by email only

This commit is contained in:
2026-06-16 16:18:42 +02:00
parent caf19575c6
commit 68c2983d36
30 changed files with 42 additions and 198 deletions
-2
View File
@@ -14,7 +14,6 @@ function nextSuffix() {
export async function createTestUser(
prisma: PrismaClient,
overrides: Partial<{
username: string
email: string
name: string
role: UserRole
@@ -25,7 +24,6 @@ export async function createTestUser(
return prisma.user.create({
data: {
username: overrides.username ?? `test-user-${suffix}`,
email: overrides.email ?? `test-user-${suffix}@example.test`,
name: overrides.name ?? "Test User",
password: "hashed-password",
@@ -41,7 +41,6 @@ afterAll(async () => {
describe("user use-cases", () => {
it("creates a user with a hashed password", async () => {
const result = await createUserUseCase({
username: "new-user",
name: "New User",
email: "new-user@example.test",
password: "secure-password",
@@ -52,11 +51,10 @@ describe("user use-cases", () => {
expect(result).toEqual({ success: true })
const user = await prisma.user.findUniqueOrThrow({
where: { username: "new-user" },
where: { email: "new-user@example.test" },
})
expect(user).toMatchObject({
username: "new-user",
name: "New User",
email: "new-user@example.test",
role: "STAFF",
@@ -68,29 +66,13 @@ describe("user use-cases", () => {
).resolves.toBe(true)
})
it("rejects duplicate usernames and duplicate emails", async () => {
it("rejects duplicate emails", async () => {
await createTestUser(prisma, {
username: "existing-user",
email: "existing@example.test",
})
await expect(
createUserUseCase({
username: "existing-user",
name: "Duplicate Username",
email: "unique@example.test",
password: "secure-password",
role: "STAFF",
isActive: true,
}),
).resolves.toEqual({
success: false,
errors: { username: ["Username already exists"] },
})
await expect(
createUserUseCase({
username: "unique-user",
name: "Duplicate Email",
email: "existing@example.test",
password: "secure-password",
@@ -104,19 +86,17 @@ describe("user use-cases", () => {
await expect(prisma.user.count()).resolves.toBe(1)
await expect(
prisma.user.findUniqueOrThrow({ where: { username: "existing-user" } }),
prisma.user.findUniqueOrThrow({ where: { email: "existing@example.test" } }),
).resolves.toMatchObject({ email: "existing@example.test" })
})
it("updates a user while preserving uniqueness constraints", async () => {
const actor = await createTestUser(prisma, { role: "ADMIN" })
const user = await createTestUser(prisma, {
username: "editable-user",
email: "editable@example.test",
role: "STAFF",
})
const other = await createTestUser(prisma, {
username: "other-user",
email: "other@example.test",
role: "STAFF",
})
@@ -125,7 +105,6 @@ describe("user use-cases", () => {
updateUserUseCase({
actorId: actor.id,
id: user.id,
username: "edited-user",
name: "Edited User",
email: "edited@example.test",
role: "MANAGER",
@@ -136,7 +115,6 @@ describe("user use-cases", () => {
await expect(
prisma.user.findUniqueOrThrow({ where: { id: user.id } }),
).resolves.toMatchObject({
username: "edited-user",
name: "Edited User",
email: "edited@example.test",
role: "MANAGER",
@@ -147,21 +125,19 @@ describe("user use-cases", () => {
updateUserUseCase({
actorId: actor.id,
id: user.id,
username: other.username,
name: "Edited User",
email: "another-email@example.test",
email: other.email,
role: "MANAGER",
isActive: true,
}),
).resolves.toEqual({
success: false,
errors: { username: ["Username already exists"] },
errors: { email: ["Email already exists"] },
})
await expect(
prisma.user.findUniqueOrThrow({ where: { id: user.id } }),
).resolves.toMatchObject({
username: "edited-user",
email: "edited@example.test",
})
})
@@ -173,7 +149,6 @@ describe("user use-cases", () => {
updateUserUseCase({
actorId: admin.id,
id: admin.id,
username: admin.username,
name: admin.name,
email: admin.email,
role: "STAFF",
@@ -191,12 +166,10 @@ describe("user use-cases", () => {
it("protects the last active administrator but allows deactivation when another active admin exists", async () => {
const firstAdmin = await createTestUser(prisma, {
username: "first-admin",
email: "first-admin@example.test",
role: "ADMIN",
})
const staffActor = await createTestUser(prisma, {
username: "staff-actor",
email: "staff-actor@example.test",
role: "STAFF",
})
@@ -215,7 +188,6 @@ describe("user use-cases", () => {
})
const secondAdmin = await createTestUser(prisma, {
username: "second-admin",
email: "second-admin@example.test",
role: "ADMIN",
})
@@ -255,7 +227,6 @@ describe("user use-cases", () => {
it("resets a user password and rejects missing users", async () => {
const user = await createTestUser(prisma, {
username: "password-user",
email: "password-user@example.test",
role: "STAFF",
})