import { APIErrorCode, APIException, type RegisterUserRequest, type UpdateUserRequest, type User, } from "../model/interfaces.ts"; import { db, isUserRow, userApiToRow, userRowToApi } from "../model/db.ts"; import { hashPassword } from "../lib/jwt.ts"; export async function createUser( request: RegisterUserRequest, ): Promise { const userId = crypto.randomUUID(); const createdAt = new Date(); const existingUser = db.prepare( "SELECT id FROM users WHERE username = ?;", ).get(request.username); if (existingUser) { throw new APIException( APIErrorCode.VALIDATION_ERROR, 400, "Username already exists", ); } const passwordHash = await hashPassword(request.password); db.prepare( `INSERT INTO users (id, username, password_hash, is_admin, created_at) VALUES (?, ?, ?, ?, ?);`, ).run( userId, request.username, passwordHash, 0, createdAt.toISOString(), ); return { id: userId, username: request.username, passwordHash, isAdmin: false, createdAt, }; } export function getUserById(userId: string): User { const userRow = db.prepare( `SELECT id, username, password_hash, is_admin, created_at FROM users WHERE id = ?`, ).get(userId); if (!userRow || !isUserRow(userRow)) { throw new APIException(APIErrorCode.NOT_FOUND, 404, "User not found"); } return userRowToApi(userRow); } export function getUserByUsername(username: string): User { const userRow = db.prepare( `SELECT id, username, password_hash, is_admin, created_at FROM users WHERE username = ?`, ).get(username); if (!userRow || !isUserRow(userRow)) { throw new APIException(APIErrorCode.NOT_FOUND, 404, "User not found"); } return userRowToApi(userRow); } export function listUsers(): User[] { const userRows = db.prepare( `SELECT id, username, password_hash, is_admin, created_at FROM users`, ).all(); if (!userRows || !userRows.every(isUserRow)) { throw new APIException(APIErrorCode.NOT_FOUND, 404, "No user found"); } return userRows.map(userRowToApi); } export async function updateUser( userId: string, request: UpdateUserRequest, ): Promise { const user = getUserById(userId); const { password, ...requestFields } = request; const updatedUser: User = { ...user, passwordHash: password ? await hashPassword(password) : user.passwordHash, ...requestFields, }; const updatedUserRow = userApiToRow(updatedUser); const userResult = db.prepare( `UPDATE users SET username = ?, password_hash = ?, is_admin = ? WHERE id = ?`, ).run( updatedUserRow.username, updatedUserRow.password_hash, updatedUserRow.is_admin, updatedUserRow.id, ); if (userResult.changes === 0) { throw new APIException(APIErrorCode.NOT_FOUND, 404, "Dump not found"); } return updatedUser; } export function deleteUser(userId: string): void { const result = db.prepare( `DELETE FROM users WHERE id = ?;`, ).run(userId); if (result.changes === 0) { throw new APIException(APIErrorCode.NOT_FOUND, 404, "User not found"); } }