db management fix

This commit is contained in:
root
2026-05-22 17:21:52 -04:00
parent bae4942276
commit 48ecde2a51
13 changed files with 294 additions and 7 deletions
@@ -0,0 +1,31 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('../../lib/prisma', () => ({
prisma: {
adminUser: {
findFirst: vi.fn(),
},
},
}))
import { prisma } from '../../lib/prisma'
import { findAdminByEmail } from './admin.repo'
describe('admin.repo', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('looks up admin email case-insensitively', async () => {
await findAdminByEmail('Admin@Example.com')
expect(prisma.adminUser.findFirst).toHaveBeenCalledWith({
where: {
email: {
equals: 'Admin@Example.com',
mode: 'insensitive',
},
},
})
})
})
+8 -1
View File
@@ -31,7 +31,14 @@ function parseOptionalDate(value?: string | null) {
}
export function findAdminByEmail(email: string) {
return prisma.adminUser.findUnique({ where: { email } })
return prisma.adminUser.findFirst({
where: {
email: {
equals: email,
mode: 'insensitive',
},
},
})
}
export function findAdminByIdOrThrow(id: string) {
@@ -0,0 +1,49 @@
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('./admin.repo', () => ({
findAdminByEmail: vi.fn(),
setAdminPasswordReset: vi.fn(),
}))
vi.mock('../../services/notificationService', () => ({
sendTransactionalEmail: vi.fn().mockResolvedValue(undefined),
}))
import * as repo from './admin.repo'
import { sendTransactionalEmail } from '../../services/notificationService'
import { forgotPassword } from './admin.service'
describe('admin.service forgotPassword', () => {
const originalAdminUrl = process.env.ADMIN_URL
beforeEach(() => {
vi.clearAllMocks()
process.env.ADMIN_URL = 'http://localhost:3002'
})
afterAll(() => {
process.env.ADMIN_URL = originalAdminUrl
})
it('sends the reset email to the canonical stored admin address', async () => {
vi.mocked(repo.findAdminByEmail).mockResolvedValue({
id: 'admin_1',
email: 'admin@rentaldrivego.com',
firstName: 'Samir',
isActive: true,
} as any)
await forgotPassword('Admin@RentalDriveGo.com')
expect(repo.setAdminPasswordReset).toHaveBeenCalledWith(
'admin_1',
expect.any(String),
expect.any(Date),
)
expect(sendTransactionalEmail).toHaveBeenCalledWith(
expect.objectContaining({
to: 'admin@rentaldrivego.com',
}),
)
})
})
+1 -1
View File
@@ -93,7 +93,7 @@ export async function forgotPassword(email: string) {
const resetUrl = `${adminUrl}/reset-password?token=${rawToken}`
await sendTransactionalEmail({
to: email,
to: admin.email,
subject: 'Reset your RentalDriveGo admin password',
html: `<p>Hi ${admin.firstName},</p><p><a href="${resetUrl}">Reset password</a></p><p>Expires in ${ADMIN_RESET_TTL_MINUTES} minutes.</p>`,
text: `Hi ${admin.firstName},\n\nReset here: ${resetUrl}\n\nExpires in ${ADMIN_RESET_TTL_MINUTES} minutes.`,
@@ -0,0 +1,46 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('../../lib/prisma', () => ({
prisma: {
employee: {
findFirst: vi.fn(),
},
},
}))
import { prisma } from '../../lib/prisma'
import { findActiveEmployeeByEmail, findEmployeeWithCompanyByEmail } from './auth.employee.repo'
describe('auth.employee.repo', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('looks up employee login email case-insensitively', async () => {
await findEmployeeWithCompanyByEmail('Owner@Example.com')
expect(prisma.employee.findFirst).toHaveBeenCalledWith({
where: {
email: {
equals: 'Owner@Example.com',
mode: 'insensitive',
},
},
include: { company: true },
})
})
it('looks up active employee reset email case-insensitively', async () => {
await findActiveEmployeeByEmail('Owner@Example.com')
expect(prisma.employee.findFirst).toHaveBeenCalledWith({
where: {
email: {
equals: 'Owner@Example.com',
mode: 'insensitive',
},
isActive: true,
},
})
})
})
@@ -9,14 +9,25 @@ export function findEmployeeWithCompanyById(id: string) {
export function findEmployeeWithCompanyByEmail(email: string) {
return prisma.employee.findFirst({
where: { email },
where: {
email: {
equals: email,
mode: 'insensitive',
},
},
include: { company: true },
})
}
export function findActiveEmployeeByEmail(email: string) {
return prisma.employee.findFirst({
where: { email, isActive: true },
where: {
email: {
equals: email,
mode: 'insensitive',
},
isActive: true,
},
})
}
@@ -0,0 +1,49 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('./auth.employee.repo', () => ({
findActiveEmployeeByEmail: vi.fn(),
setPasswordResetToken: vi.fn(),
}))
vi.mock('../../services/notificationService', () => ({
sendTransactionalEmail: vi.fn().mockResolvedValue(undefined),
}))
import * as repo from './auth.employee.repo'
import { sendTransactionalEmail } from '../../services/notificationService'
import { forgotPassword } from './auth.employee.service'
describe('auth.employee.service forgotPassword', () => {
const originalDashboardUrl = process.env.DASHBOARD_URL
beforeEach(() => {
vi.clearAllMocks()
process.env.DASHBOARD_URL = 'http://localhost:3001'
})
afterAll(() => {
process.env.DASHBOARD_URL = originalDashboardUrl
})
it('sends the reset email to the canonical stored address', async () => {
vi.mocked(repo.findActiveEmployeeByEmail).mockResolvedValue({
id: 'emp_1',
email: 'owner@company.com',
firstName: 'Aya',
preferredLanguage: 'en',
} as any)
await forgotPassword('Owner@Company.com')
expect(repo.setPasswordResetToken).toHaveBeenCalledWith(
'emp_1',
expect.any(String),
expect.any(Date),
)
expect(sendTransactionalEmail).toHaveBeenCalledWith(
expect.objectContaining({
to: 'owner@company.com',
}),
)
})
})
@@ -78,7 +78,7 @@ export async function forgotPassword(email: string) {
const lang = (employee.preferredLanguage as Lang) ?? 'fr'
await sendTransactionalEmail({
to: email,
to: employee.email,
subject: resetPasswordEmail.subject(lang),
html: resetPasswordEmail.html(resetUrl, employee.firstName, RESET_TOKEN_TTL_MINUTES, lang),
text: resetPasswordEmail.text(resetUrl, employee.firstName, RESET_TOKEN_TTL_MINUTES, lang),