import {queryAll, queryOne, run} from '../../shared/database'; import bcrypt from 'bcrypt'; const USER_DB_NAME = 'userdata'; const SALT_ROUNDS = 10; interface User { id: number; username: string; profile_picture_url: string | null; has_password: boolean; } export async function userExists(id: number): Promise { const sql = 'SELECT 1 FROM User WHERE id = ?'; const row = await queryOne(sql, [id], USER_DB_NAME); return !!row; } export async function createUser(username: string, profilePictureUrl?: string, password?: string): Promise<{ lastID: number }> { let passwordHash = null; if (password && password.trim()) { passwordHash = await bcrypt.hash(password.trim(), SALT_ROUNDS); } const sql = ` INSERT INTO User (username, profile_picture_url, password_hash) VALUES (?, ?, ?) `; const params = [username, profilePictureUrl || null, passwordHash]; const result = await run(sql, params, USER_DB_NAME); return { lastID: result.lastID }; } export async function updateUser(userId: number, updates: any): Promise { const fields: string[] = []; const values: (string | number | null)[] = []; if (updates.username !== undefined) { fields.push('username = ?'); values.push(updates.username); } if (updates.profilePictureUrl !== undefined) { fields.push('profile_picture_url = ?'); values.push(updates.profilePictureUrl); } if (updates.password !== undefined) { if (updates.password === null || updates.password === '') { // Eliminar contraseƱa fields.push('password_hash = ?'); values.push(null); } else { // Actualizar contraseƱa const hash = await bcrypt.hash(updates.password.trim(), SALT_ROUNDS); fields.push('password_hash = ?'); values.push(hash); } } if (fields.length === 0) { return { changes: 0, lastID: userId }; } const setClause = fields.join(', '); const sql = `UPDATE User SET ${setClause} WHERE id = ?`; values.push(userId); return await run(sql, values, USER_DB_NAME); } export async function deleteUser(userId: number): Promise { await run( `DELETE FROM ListEntry WHERE user_id = ?`, [userId], USER_DB_NAME ); await run( `DELETE FROM UserIntegration WHERE user_id = ?`, [userId], USER_DB_NAME ); await run( `DELETE FROM favorites WHERE user_id = ?`, [userId], 'favorites' ); const result = await run( `DELETE FROM User WHERE id = ?`, [userId], USER_DB_NAME ); return result; } export async function getAllUsers(): Promise { const sql = ` SELECT id, username, profile_picture_url, CASE WHEN password_hash IS NOT NULL THEN 1 ELSE 0 END as has_password FROM User ORDER BY id `; const users = await queryAll(sql, [], USER_DB_NAME); return users.map((user: any) => ({ id: user.id, username: user.username, profile_picture_url: user.profile_picture_url || null, has_password: !!user.has_password })) as User[]; } export async function getUserById(id: number): Promise { const sql = ` SELECT id, username, profile_picture_url, CASE WHEN password_hash IS NOT NULL THEN 1 ELSE 0 END as has_password FROM User WHERE id = ? `; const user = await queryOne(sql, [id], USER_DB_NAME); if (!user) return null; return { id: user.id, username: user.username, profile_picture_url: user.profile_picture_url || null, has_password: !!user.has_password }; } export async function verifyPassword(userId: number, password: string): Promise { const sql = 'SELECT password_hash FROM User WHERE id = ?'; const user = await queryOne(sql, [userId], USER_DB_NAME); if (!user || !user.password_hash) { return false; } return await bcrypt.compare(password, user.password_hash); } export async function getAniListIntegration(userId: number) { const sql = ` SELECT anilist_user_id, expires_at FROM UserIntegration WHERE user_id = ? AND platform = ? `; const row = await queryOne(sql, [userId, "AniList"], USER_DB_NAME); if (!row) { return { connected: false }; } return { connected: true, anilistUserId: row.anilist_user_id, expiresAt: row.expires_at }; } export async function removeAniListIntegration(userId: number) { const sql = ` DELETE FROM UserIntegration WHERE user_id = ? AND platform = ? `; return run(sql, [userId, "AniList"], USER_DB_NAME); }