mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-27 07:14:56 +00:00
code: nextjs,frontends,node (4 files)
This commit is contained in:
95
frontends/nextjs/src/lib/db/auth/authenticate-user.test.ts
Normal file
95
frontends/nextjs/src/lib/db/auth/authenticate-user.test.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
const mockList = vi.fn()
|
||||
const mockFindFirst = vi.fn()
|
||||
const mockAdapter = { list: mockList, findFirst: mockFindFirst }
|
||||
|
||||
const mockVerifyPassword = vi.fn()
|
||||
|
||||
vi.mock('../dbal-client', () => ({
|
||||
getAdapter: () => mockAdapter,
|
||||
}))
|
||||
|
||||
vi.mock('../verify-password', () => ({
|
||||
verifyPassword: mockVerifyPassword,
|
||||
}))
|
||||
|
||||
import { authenticateUser } from './authenticate-user'
|
||||
|
||||
describe('authenticateUser', () => {
|
||||
beforeEach(() => {
|
||||
mockList.mockReset()
|
||||
mockFindFirst.mockReset()
|
||||
mockVerifyPassword.mockReset()
|
||||
})
|
||||
|
||||
it('returns invalid credentials when credential is missing', async () => {
|
||||
mockList.mockResolvedValue({ data: [] })
|
||||
|
||||
const result = await authenticateUser('alice', 'password')
|
||||
|
||||
expect(mockList).toHaveBeenCalledWith('Credential', { filter: { username: 'alice' } })
|
||||
expect(mockVerifyPassword).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({ success: false, user: null, error: 'invalid_credentials' })
|
||||
})
|
||||
|
||||
it('returns invalid credentials when password is wrong', async () => {
|
||||
mockList.mockResolvedValue({ data: [{ username: 'alice', passwordHash: 'hash' }] })
|
||||
mockVerifyPassword.mockResolvedValue(false)
|
||||
|
||||
const result = await authenticateUser('alice', 'password')
|
||||
|
||||
expect(mockVerifyPassword).toHaveBeenCalledWith('password', 'hash')
|
||||
expect(mockFindFirst).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({ success: false, user: null, error: 'invalid_credentials' })
|
||||
})
|
||||
|
||||
it('returns user_not_found when credential is valid but user missing', async () => {
|
||||
mockList.mockResolvedValue({ data: [{ username: 'alice', passwordHash: 'hash' }] })
|
||||
mockVerifyPassword.mockResolvedValue(true)
|
||||
mockFindFirst.mockResolvedValue(null)
|
||||
|
||||
const result = await authenticateUser('alice', 'password')
|
||||
|
||||
expect(mockFindFirst).toHaveBeenCalledWith('User', { where: { username: 'alice' } })
|
||||
expect(result).toEqual({ success: false, user: null, error: 'user_not_found' })
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ firstLogin: true, expected: true },
|
||||
{ firstLogin: false, expected: false },
|
||||
])('returns requiresPasswordChange=$expected when firstLogin=$firstLogin', async ({ firstLogin, expected }) => {
|
||||
mockList.mockResolvedValue({ data: [{ username: 'alice', passwordHash: 'hash' }] })
|
||||
mockVerifyPassword.mockResolvedValue(true)
|
||||
mockFindFirst.mockResolvedValue({
|
||||
id: 'user_1',
|
||||
username: 'alice',
|
||||
email: 'alice@example.com',
|
||||
role: 'user',
|
||||
profilePicture: null,
|
||||
bio: null,
|
||||
createdAt: BigInt(1000),
|
||||
tenantId: null,
|
||||
isInstanceOwner: false,
|
||||
firstLogin,
|
||||
})
|
||||
|
||||
const result = await authenticateUser('alice', 'password')
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
user: {
|
||||
id: 'user_1',
|
||||
username: 'alice',
|
||||
email: 'alice@example.com',
|
||||
role: 'user',
|
||||
profilePicture: undefined,
|
||||
bio: undefined,
|
||||
createdAt: 1000,
|
||||
tenantId: undefined,
|
||||
isInstanceOwner: false,
|
||||
},
|
||||
requiresPasswordChange: expected,
|
||||
})
|
||||
})
|
||||
})
|
||||
10
frontends/nextjs/src/lib/nerd-mode-ide/delete-node.ts
Normal file
10
frontends/nextjs/src/lib/nerd-mode-ide/delete-node.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { FileNode } from './types'
|
||||
|
||||
export function deleteNode(nodes: FileNode[], id: string): FileNode[] {
|
||||
return nodes
|
||||
.filter((node) => node.id !== id)
|
||||
.map((node) => {
|
||||
if (!node.children) return node
|
||||
return { ...node, children: deleteNode(node.children, id) }
|
||||
})
|
||||
}
|
||||
12
frontends/nextjs/src/lib/nerd-mode-ide/find-node-by-id.ts
Normal file
12
frontends/nextjs/src/lib/nerd-mode-ide/find-node-by-id.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { FileNode } from './types'
|
||||
|
||||
export function findNodeById(nodes: FileNode[], id: string): FileNode | null {
|
||||
for (const node of nodes) {
|
||||
if (node.id === id) return node
|
||||
if (node.children) {
|
||||
const found = findNodeById(node.children, id)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
13
frontends/nextjs/src/lib/nerd-mode-ide/update-node.ts
Normal file
13
frontends/nextjs/src/lib/nerd-mode-ide/update-node.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { FileNode } from './types'
|
||||
|
||||
export function updateNode(nodes: FileNode[], id: string, updates: Partial<FileNode>): FileNode[] {
|
||||
return nodes.map((node) => {
|
||||
if (node.id === id) {
|
||||
return { ...node, ...updates }
|
||||
}
|
||||
if (node.children) {
|
||||
return { ...node, children: updateNode(node.children, id, updates) }
|
||||
}
|
||||
return node
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user