This repository has been archived on 2026-06-15. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MediaLore/src/lib/users.ts
Garret Patti eecee9bc5f add auth
2026-04-05 17:44:24 -04:00

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,
}))
}