From d54b0bcdef59d2d612c64be006f9ec9f46091ac3 Mon Sep 17 00:00:00 2001 From: lenafx Date: Thu, 18 Dec 2025 16:06:35 +0100 Subject: [PATCH] if user has pass ask for it before deleting it --- desktop/src/api/user/user.controller.ts | 40 +++++++++--- desktop/src/scripts/users.js | 86 +++++++++++++++++++++++-- docker/src/api/user/user.controller.ts | 40 +++++++++--- docker/src/scripts/users.js | 86 +++++++++++++++++++++++-- 4 files changed, 218 insertions(+), 34 deletions(-) diff --git a/desktop/src/api/user/user.controller.ts b/desktop/src/api/user/user.controller.ts index 3a89d69..0ff40cd 100644 --- a/desktop/src/api/user/user.controller.ts +++ b/desktop/src/api/user/user.controller.ts @@ -168,20 +168,39 @@ export async function deleteUser(req: FastifyRequest, reply: FastifyReply) { const { id } = req.params as { id: string }; const userId = parseInt(id, 10); + const body = (req.body ?? {}) as { password?: string }; + const password = body.password; + if (!userId || isNaN(userId)) { return reply.code(400).send({ error: "Invalid user id" }); } - const result = await userService.deleteUser(userId); - - if (result && result.changes > 0) { - return { success: true, message: "User deleted successfully" }; - } else { + const user = await userService.getUserById(userId); + if (!user) { return reply.code(404).send({ error: "User not found" }); } + if (user.has_password) { + if (!password) { + return reply.code(401).send({ error: "Password required" }); + } + + const isValid = await userService.verifyPassword(userId, password); + if (!isValid) { + return reply.code(401).send({ error: "Incorrect password" }); + } + } + + const result = await userService.deleteUser(userId); + + if (result.changes > 0) { + return reply.send({ success: true }); + } + + return reply.code(500).send({ error: "Failed to delete user" }); + } catch (err) { - console.error("Delete User Error:", (err as Error).message); + console.error("Delete User Error:", err); return reply.code(500).send({ error: "Failed to delete user" }); } } @@ -246,16 +265,17 @@ export async function changePassword(req: FastifyRequest, reply: FastifyReply) { return reply.code(404).send({ error: "User not found" }); } - // Si el usuario tiene contraseña actual, debe proporcionar la contraseña actual - if (user.has_password && currentPassword) { - const isValid = await userService.verifyPassword(userId, currentPassword); + if (user.has_password) { + if (!currentPassword) { + return reply.code(401).send({ error: "Current password required" }); + } + const isValid = await userService.verifyPassword(userId, currentPassword); if (!isValid) { return reply.code(401).send({ error: "Current password is incorrect" }); } } - // Actualizar la contraseña (null para eliminarla, string para establecerla) await userService.updateUser(userId, { password: newPassword }); return reply.send({ diff --git a/desktop/src/scripts/users.js b/desktop/src/scripts/users.js index 8a268e6..ea09f67 100644 --- a/desktop/src/scripts/users.js +++ b/desktop/src/scripts/users.js @@ -694,30 +694,102 @@ window.handleDeleteConfirmation = function(userId) { closeModal(); + if (user.has_password) { + modalAniList.innerHTML = ` + + + `; + modalAniList.classList.add('active'); + + document + .getElementById('deleteWithPasswordForm') + .addEventListener('submit', e => { + e.preventDefault(); + const password = document.getElementById('deletePassword').value; + handleConfirmedDeleteUser(userId, password); + }); + + return; + } + showConfirmationModal( 'Confirm Deletion', - `Are you absolutely sure you want to delete profile ${user.username}? This action cannot be undone.`, + `Are you absolutely sure you want to delete profile ${user.username}?`, `handleConfirmedDeleteUser(${userId})` ); }; -window.handleConfirmedDeleteUser = async function(userId) { +window.handleConfirmedDeleteUser = async function(userId, password = null) { closeModal(); - showUserToast('Deleting user...', 'info'); try { - const res = await fetch(`${API_BASE}/users/${userId}`, { method: 'DELETE' }); + const options = { method: 'DELETE' }; + + if (password) { + options.headers = { 'Content-Type': 'application/json' }; + options.body = JSON.stringify({ password }); + } + + const res = await fetch(`${API_BASE}/users/${userId}`, options); if (!res.ok) { const error = await res.json(); - throw new Error(error.error || 'Error deleting user'); + throw new Error(error.error); } await loadUsers(); showUserToast('User deleted successfully!', 'success'); } catch (err) { - console.error(err); - showUserToast('Error deleting user', 'error'); + showUserToast(err.message || 'Error deleting user', 'error'); } }; diff --git a/docker/src/api/user/user.controller.ts b/docker/src/api/user/user.controller.ts index 3a89d69..0ff40cd 100644 --- a/docker/src/api/user/user.controller.ts +++ b/docker/src/api/user/user.controller.ts @@ -168,20 +168,39 @@ export async function deleteUser(req: FastifyRequest, reply: FastifyReply) { const { id } = req.params as { id: string }; const userId = parseInt(id, 10); + const body = (req.body ?? {}) as { password?: string }; + const password = body.password; + if (!userId || isNaN(userId)) { return reply.code(400).send({ error: "Invalid user id" }); } - const result = await userService.deleteUser(userId); - - if (result && result.changes > 0) { - return { success: true, message: "User deleted successfully" }; - } else { + const user = await userService.getUserById(userId); + if (!user) { return reply.code(404).send({ error: "User not found" }); } + if (user.has_password) { + if (!password) { + return reply.code(401).send({ error: "Password required" }); + } + + const isValid = await userService.verifyPassword(userId, password); + if (!isValid) { + return reply.code(401).send({ error: "Incorrect password" }); + } + } + + const result = await userService.deleteUser(userId); + + if (result.changes > 0) { + return reply.send({ success: true }); + } + + return reply.code(500).send({ error: "Failed to delete user" }); + } catch (err) { - console.error("Delete User Error:", (err as Error).message); + console.error("Delete User Error:", err); return reply.code(500).send({ error: "Failed to delete user" }); } } @@ -246,16 +265,17 @@ export async function changePassword(req: FastifyRequest, reply: FastifyReply) { return reply.code(404).send({ error: "User not found" }); } - // Si el usuario tiene contraseña actual, debe proporcionar la contraseña actual - if (user.has_password && currentPassword) { - const isValid = await userService.verifyPassword(userId, currentPassword); + if (user.has_password) { + if (!currentPassword) { + return reply.code(401).send({ error: "Current password required" }); + } + const isValid = await userService.verifyPassword(userId, currentPassword); if (!isValid) { return reply.code(401).send({ error: "Current password is incorrect" }); } } - // Actualizar la contraseña (null para eliminarla, string para establecerla) await userService.updateUser(userId, { password: newPassword }); return reply.send({ diff --git a/docker/src/scripts/users.js b/docker/src/scripts/users.js index 8a268e6..ea09f67 100644 --- a/docker/src/scripts/users.js +++ b/docker/src/scripts/users.js @@ -694,30 +694,102 @@ window.handleDeleteConfirmation = function(userId) { closeModal(); + if (user.has_password) { + modalAniList.innerHTML = ` + + + `; + modalAniList.classList.add('active'); + + document + .getElementById('deleteWithPasswordForm') + .addEventListener('submit', e => { + e.preventDefault(); + const password = document.getElementById('deletePassword').value; + handleConfirmedDeleteUser(userId, password); + }); + + return; + } + showConfirmationModal( 'Confirm Deletion', - `Are you absolutely sure you want to delete profile ${user.username}? This action cannot be undone.`, + `Are you absolutely sure you want to delete profile ${user.username}?`, `handleConfirmedDeleteUser(${userId})` ); }; -window.handleConfirmedDeleteUser = async function(userId) { +window.handleConfirmedDeleteUser = async function(userId, password = null) { closeModal(); - showUserToast('Deleting user...', 'info'); try { - const res = await fetch(`${API_BASE}/users/${userId}`, { method: 'DELETE' }); + const options = { method: 'DELETE' }; + + if (password) { + options.headers = { 'Content-Type': 'application/json' }; + options.body = JSON.stringify({ password }); + } + + const res = await fetch(`${API_BASE}/users/${userId}`, options); if (!res.ok) { const error = await res.json(); - throw new Error(error.error || 'Error deleting user'); + throw new Error(error.error); } await loadUsers(); showUserToast('User deleted successfully!', 'success'); } catch (err) { - console.error(err); - showUserToast('Error deleting user', 'error'); + showUserToast(err.message || 'Error deleting user', 'error'); } };