120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
import { getDb } from './db'
|
|
import { getLibraries } from './libraries'
|
|
import type { Library } from '@/types'
|
|
|
|
export interface User {
|
|
id: string
|
|
username: string
|
|
role: 'admin' | 'user'
|
|
createdAt: number
|
|
}
|
|
|
|
export interface UserWithHash extends User {
|
|
passwordHash: string
|
|
}
|
|
|
|
export function getUserCount(): number {
|
|
const db = getDb()
|
|
const row = db.prepare('SELECT COUNT(*) as count FROM users').get() as { count: number }
|
|
return row.count
|
|
}
|
|
|
|
export function getUserByUsername(username: string): UserWithHash | undefined {
|
|
const db = getDb()
|
|
const row = db
|
|
.prepare('SELECT id, username, password_hash, role, created_at FROM users WHERE username = ?')
|
|
.get(username) as { id: string; username: string; password_hash: string; role: string; created_at: number } | undefined
|
|
if (!row) return undefined
|
|
return {
|
|
id: row.id,
|
|
username: row.username,
|
|
passwordHash: row.password_hash,
|
|
role: row.role as 'admin' | 'user',
|
|
createdAt: row.created_at,
|
|
}
|
|
}
|
|
|
|
export function getUserById(id: string): User | undefined {
|
|
const db = getDb()
|
|
const row = db
|
|
.prepare('SELECT id, username, role, created_at FROM users WHERE id = ?')
|
|
.get(id) as { id: string; username: string; role: string; created_at: number } | undefined
|
|
if (!row) return undefined
|
|
return {
|
|
id: row.id,
|
|
username: row.username,
|
|
role: row.role as 'admin' | 'user',
|
|
createdAt: row.created_at,
|
|
}
|
|
}
|
|
|
|
export function createUser(username: string, passwordHash: string, role: 'admin' | 'user'): User {
|
|
const db = getDb()
|
|
const id = crypto.randomUUID()
|
|
const now = Math.floor(Date.now() / 1000)
|
|
db.prepare(
|
|
'INSERT INTO users (id, username, password_hash, role, created_at) VALUES (?, ?, ?, ?, ?)'
|
|
).run(id, username, passwordHash, role, now)
|
|
return { id, username, role, createdAt: now }
|
|
}
|
|
|
|
export function deleteUser(id: string): boolean {
|
|
const db = getDb()
|
|
const result = db.prepare('DELETE FROM users WHERE id = ?').run(id)
|
|
return result.changes > 0
|
|
}
|
|
|
|
export function listUsers(): User[] {
|
|
const db = getDb()
|
|
const rows = db
|
|
.prepare('SELECT id, username, role, created_at FROM users ORDER BY created_at ASC')
|
|
.all() as { id: string; username: string; role: string; created_at: number }[]
|
|
return rows.map((r) => ({
|
|
id: r.id,
|
|
username: r.username,
|
|
role: r.role as 'admin' | 'user',
|
|
createdAt: r.created_at,
|
|
}))
|
|
}
|
|
|
|
export function getPermittedLibraryIds(userId: string): string[] {
|
|
const db = getDb()
|
|
const rows = db
|
|
.prepare('SELECT library_id FROM library_permissions WHERE user_id = ?')
|
|
.all(userId) as { library_id: string }[]
|
|
return rows.map((r) => r.library_id)
|
|
}
|
|
|
|
export function setLibraryPermissions(userId: string, libraryIds: string[]): void {
|
|
const db = getDb()
|
|
const tx = db.transaction(() => {
|
|
db.prepare('DELETE FROM library_permissions WHERE user_id = ?').run(userId)
|
|
const insert = db.prepare('INSERT INTO library_permissions (user_id, library_id) VALUES (?, ?)')
|
|
for (const libraryId of libraryIds) {
|
|
insert.run(userId, libraryId)
|
|
}
|
|
})
|
|
tx()
|
|
}
|
|
|
|
export function getLibrariesForUser(userId: string, role: 'admin' | 'user'): Library[] {
|
|
if (role === 'admin') return getLibraries()
|
|
const db = getDb()
|
|
const rows = db
|
|
.prepare(
|
|
`SELECT l.id, l.name, l.path, l.type, l.cover_ext
|
|
FROM libraries l
|
|
INNER JOIN library_permissions lp ON lp.library_id = l.id
|
|
WHERE lp.user_id = ?
|
|
ORDER BY l.name ASC`
|
|
)
|
|
.all(userId) as { id: string; name: string; path: string; type: string; cover_ext: string | null }[]
|
|
return rows.map((r) => ({
|
|
id: r.id,
|
|
name: r.name,
|
|
path: r.path,
|
|
type: r.type as Library['type'],
|
|
coverExt: r.cover_ext,
|
|
}))
|
|
}
|