Eliminar Usuarios
Eliminar Usuarios
Section titled “Eliminar Usuarios”Dominio: https://test-api-factura.edw-dev.com
Dominio: https://api-financiero.e-dinky.com
Endpoint para eliminar usuarios del sistema de forma segura.
Endpoint Disponible
Section titled “Endpoint Disponible”DELETE /api/v1/users/:id
- Eliminar usuario específico
DELETE /api/v1/users/:id
Section titled “DELETE /api/v1/users/:id”Elimina un usuario específico del sistema. Esta operación es irreversible y requiere permisos de administrador.
Información General
Section titled “Información General”- Método:
DELETE
- Endpoint:
/api/v1/users/:id
- Autenticación: Requerida (Bearer Token)
- Permisos: Administrador
- Tipo de eliminación: Lógica (soft delete)
- Reversible: No (requiere restauración manual)
Headers Requeridos
Section titled “Headers Requeridos”Accept: application/jsonAuthorization: Bearer {token}
Parámetros de URL
Section titled “Parámetros de URL”Parámetro | Tipo | Requerido | Descripción |
---|---|---|---|
id | integer | Sí | ID del usuario a eliminar |
Restricciones de Eliminación
Section titled “Restricciones de Eliminación”No se puede eliminar:
Section titled “No se puede eliminar:”- ✋ El propio usuario (auto-eliminación)
- 👑 Usuarios con rol de super administrador
- 📄 Usuarios con documentos activos pendientes
- 💼 Usuarios que son únicos administradores de una empresa
- 🔗 Usuarios con dependencias críticas en el sistema
Verificaciones previas:
Section titled “Verificaciones previas:”- ✅ Usuario existe y está activo
- ✅ Usuario no tiene documentos en proceso
- ✅ Usuario no es el último administrador
- ✅ No hay dependencias críticas
Ejemplo de Implementación
Section titled “Ejemplo de Implementación”Solicitud Básica
Section titled “Solicitud Básica”DELETE /api/v1/users/123456789
Respuesta Exitosa (200)
Section titled “Respuesta Exitosa (200)”{ "message": "Usuario eliminado correctamente", "status": "OK", "payload": { "uuid": 123456789, "name": "Juan", "last_name": "Pérez", "status": "deleted", "deleted_at": "2025-01-17 16:30:00", "deleted_by": 987654321 }}
Usuario No Encontrado (404)
Section titled “Usuario No Encontrado (404)”{ "message": "Usuario no encontrado", "status": "ERROR"}
Sin Permisos (403)
Section titled “Sin Permisos (403)”{ "message": "No tienes permisos para eliminar usuarios", "status": "ERROR"}
No se puede eliminar (422)
Section titled “No se puede eliminar (422)”{ "message": "No se puede eliminar el usuario", "status": "ERROR", "errors": { "restriction": ["El usuario tiene documentos activos pendientes"], "dependency": ["Es el único administrador de la empresa"] }}
Auto-eliminación no permitida (422)
Section titled “Auto-eliminación no permitida (422)”{ "message": "No puedes eliminar tu propia cuenta", "status": "ERROR"}
Ejemplos de Código
Section titled “Ejemplos de Código”# Eliminar usuariocurl -X DELETE "https://dev-facturacion.e-dinky.test/api/v1/users/123456789" \ -H "Accept: application/json" \ -H "Authorization: Bearer {token}"
# Verificar si usuario puede ser eliminado (opcional)curl -X GET "https://dev-facturacion.e-dinky.test/api/v1/users/123456789/can-delete" \ -H "Accept: application/json" \ -H "Authorization: Bearer {token}"
<?php
use Illuminate\Support\Facades\Http;
$token = 'your-api-token';
// Eliminar usuariofunction deleteUser($userId, $token) { $response = Http::withHeaders([ 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $token, ])->delete("https://dev-facturacion.e-dinky.test/api/v1/users/{$userId}");
if ($response->successful()) { $deletedUser = $response->json()['payload']; echo "Usuario eliminado: " . $deletedUser['name'] . " " . $deletedUser['last_name'] . "\n"; echo "Eliminado el: " . $deletedUser['deleted_at'] . "\n"; return true; } else { $error = $response->json(); echo "Error eliminando usuario: " . $error['message'] . "\n";
if (isset($error['errors'])) { foreach ($error['errors'] as $type => $messages) { echo "- {$type}: " . implode(', ', $messages) . "\n"; } } return false; }}
// Verificar si un usuario puede ser eliminadofunction canDeleteUser($userId, $token) { try { // Obtener información del usuario $userResponse = Http::withHeaders([ 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $token, ])->get("https://dev-facturacion.e-dinky.test/api/v1/users/{$userId}");
if (!$userResponse->successful()) { return ['can_delete' => false, 'reason' => 'Usuario no encontrado']; }
$user = $userResponse->json()['payload'];
// Verificaciones básicas if ($user['status'] === 'deleted') { return ['can_delete' => false, 'reason' => 'Usuario ya está eliminado']; }
// Verificar documentos activos (ejemplo) $documentsResponse = Http::withHeaders([ 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $token, ])->get("https://dev-facturacion.e-dinky.test/api/v1/documents", [ 'filters' => json_encode([ ['field' => 'user_id', 'condition' => 'eq', 'value' => $userId], ['field' => 'status', 'condition' => 'eq', 'value' => 'active'] ]) ]);
if ($documentsResponse->successful()) { $documents = $documentsResponse->json()['payload']; if ($documents['count'] > 0) { return [ 'can_delete' => false, 'reason' => 'Usuario tiene ' . $documents['count'] . ' documentos activos' ]; } }
return ['can_delete' => true, 'reason' => null];
} catch (Exception $e) { return ['can_delete' => false, 'reason' => 'Error verificando usuario: ' . $e->getMessage()]; }}
// Eliminar usuario con verificaciones previasfunction safeDeleteUser($userId, $token, $force = false) { if (!$force) { $canDelete = canDeleteUser($userId, $token);
if (!$canDelete['can_delete']) { echo "No se puede eliminar el usuario: " . $canDelete['reason'] . "\n"; return false; } }
// Confirmar eliminación echo "¿Estás seguro de que quieres eliminar este usuario? (y/n): "; $confirmation = trim(fgets(STDIN));
if (strtolower($confirmation) !== 'y') { echo "Eliminación cancelada\n"; return false; }
return deleteUser($userId, $token);}
// Eliminar múltiples usuariosfunction bulkDeleteUsers($userIds, $token) { $results = [ 'deleted' => [], 'failed' => [], 'skipped' => [] ];
foreach ($userIds as $userId) { echo "Procesando usuario {$userId}...\n";
$canDelete = canDeleteUser($userId, $token);
if (!$canDelete['can_delete']) { $results['skipped'][] = [ 'user_id' => $userId, 'reason' => $canDelete['reason'] ]; continue; }
if (deleteUser($userId, $token)) { $results['deleted'][] = $userId; } else { $results['failed'][] = $userId; }
// Pausa entre eliminaciones sleep(1); }
return $results;}
// Ejemplos de uso
// Eliminar un usuario específicodeleteUser(123456789, $token);
// Verificar antes de eliminar$canDelete = canDeleteUser(123456789, $token);if ($canDelete['can_delete']) { deleteUser(123456789, $token);} else { echo "No se puede eliminar: " . $canDelete['reason'];}
// Eliminación segura con confirmaciónsafeDeleteUser(123456789, $token);
// Eliminación masiva$userIds = [123456789, 987654321, 555666777];$results = bulkDeleteUsers($userIds, $token);echo "Eliminados: " . count($results['deleted']) . "\n";echo "Fallidos: " . count($results['failed']) . "\n";echo "Omitidos: " . count($results['skipped']) . "\n";
const axios = require('axios');const readline = require('readline');
const token = 'your-api-token';
const headers = { 'Accept': 'application/json', 'Authorization': `Bearer ${token}`};
// Eliminar usuarioconst deleteUser = async (userId) => { try { const response = await axios.delete(`https://dev-facturacion.e-dinky.test/api/v1/users/${userId}`, { headers });
const deletedUser = response.data.payload; console.log(`Usuario eliminado: ${deletedUser.name} ${deletedUser.last_name}`); console.log(`Eliminado el: ${deletedUser.deleted_at}`);
return { success: true, data: deletedUser }; } catch (error) { if (error.response?.status === 404) { console.error('Usuario no encontrado'); return { success: false, error: 'Usuario no encontrado' }; } else if (error.response?.status === 403) { console.error('Sin permisos para eliminar usuarios'); return { success: false, error: 'Sin permisos' }; } else if (error.response?.status === 422) { console.error('No se puede eliminar el usuario:'); const errors = error.response.data.errors; Object.keys(errors).forEach(type => { console.error(`- ${type}: ${errors[type].join(', ')}`); }); return { success: false, error: 'Restricciones de eliminación' }; } else { console.error('Error:', error.response?.data?.message || error.message); return { success: false, error: error.message }; } }};
// Verificar si un usuario puede ser eliminadoconst canDeleteUser = async (userId) => { try { // Obtener información del usuario const userResponse = await axios.get(`https://dev-facturacion.e-dinky.test/api/v1/users/${userId}`, { headers });
const user = userResponse.data.payload;
// Verificaciones básicas if (user.status === 'deleted') { return { can_delete: false, reason: 'Usuario ya está eliminado' }; }
// Verificar documentos activos const documentsResponse = await axios.get('https://dev-facturacion.e-dinky.test/api/v1/documents', { headers, params: { filters: JSON.stringify([ { field: 'user_id', condition: 'eq', value: userId }, { field: 'status', condition: 'eq', value: 'active' } ]) } });
const documents = documentsResponse.data.payload; if (documents.count > 0) { return { can_delete: false, reason: `Usuario tiene ${documents.count} documentos activos` }; }
return { can_delete: true, reason: null };
} catch (error) { if (error.response?.status === 404) { return { can_delete: false, reason: 'Usuario no encontrado' }; } return { can_delete: false, reason: `Error verificando usuario: ${error.message}` }; }};
// Función para confirmar eliminaciónconst confirmDeletion = (message) => { return new Promise((resolve) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
rl.question(`${message} (y/n): `, (answer) => { rl.close(); resolve(answer.toLowerCase() === 'y'); }); });};
// Eliminar usuario con verificaciones previasconst safeDeleteUser = async (userId, force = false) => { if (!force) { const canDelete = await canDeleteUser(userId);
if (!canDelete.can_delete) { console.log(`No se puede eliminar el usuario: ${canDelete.reason}`); return { success: false, error: canDelete.reason }; } }
// Confirmar eliminación const confirmed = await confirmDeletion('¿Estás seguro de que quieres eliminar este usuario?');
if (!confirmed) { console.log('Eliminación cancelada'); return { success: false, error: 'Cancelado por el usuario' }; }
return await deleteUser(userId);};
// Eliminar múltiples usuariosconst bulkDeleteUsers = async (userIds) => { const results = { deleted: [], failed: [], skipped: [] };
for (const userId of userIds) { console.log(`Procesando usuario ${userId}...`);
const canDelete = await canDeleteUser(userId);
if (!canDelete.can_delete) { results.skipped.push({ user_id: userId, reason: canDelete.reason }); continue; }
const result = await deleteUser(userId);
if (result.success) { results.deleted.push(userId); } else { results.failed.push({ user_id: userId, error: result.error }); }
// Pausa entre eliminaciones await new Promise(resolve => setTimeout(resolve, 1000)); }
return results;};
// Función para restaurar usuario eliminado (si está disponible)const restoreUser = async (userId) => { try { const response = await axios.put(`https://dev-facturacion.e-dinky.test/api/v1/users/${userId}/restore`, {}, { headers });
console.log('Usuario restaurado correctamente'); return { success: true, data: response.data.payload }; } catch (error) { console.error('Error restaurando usuario:', error.response?.data?.message || error.message); return { success: false, error: error.message }; }};
// Obtener usuarios eliminadosconst getDeletedUsers = async () => { try { const response = await axios.get('https://dev-facturacion.e-dinky.test/api/v1/users', { headers, params: { filters: JSON.stringify([ { field: 'status', condition: 'eq', value: 'deleted' } ]) } });
return response.data.payload.items; } catch (error) { console.error('Error obteniendo usuarios eliminados:', error.message); return []; }};
// Ejemplos de uso(async () => { try { // Eliminar un usuario específico const result1 = await deleteUser(123456789); console.log('Resultado:', result1);
// Verificar antes de eliminar const canDelete = await canDeleteUser(987654321); if (canDelete.can_delete) { await deleteUser(987654321); } else { console.log(`No se puede eliminar: ${canDelete.reason}`); }
// Eliminación segura con confirmación await safeDeleteUser(555666777);
// Eliminación masiva const userIds = [111222333, 444555666, 777888999]; const bulkResults = await bulkDeleteUsers(userIds); console.log(`Eliminados: ${bulkResults.deleted.length}`); console.log(`Fallidos: ${bulkResults.failed.length}`); console.log(`Omitidos: ${bulkResults.skipped.length}`);
// Obtener usuarios eliminados const deletedUsers = await getDeletedUsers(); console.log(`Usuarios eliminados en el sistema: ${deletedUsers.length}`);
// Restaurar usuario (si está disponible) // await restoreUser(123456789);
} catch (error) { console.error('Error en operaciones:', error.message); }})();
Verificaciones de Seguridad
Section titled “Verificaciones de Seguridad”1. Verificación de Dependencias
Section titled “1. Verificación de Dependencias”const checkUserDependencies = async (userId) => { const dependencies = { documents: 0, companies: 0, permissions: 0, active_sessions: 0 };
try { // Verificar documentos const docsResponse = await axios.get('/api/v1/documents', { params: { filters: JSON.stringify([ { field: 'user_id', condition: 'eq', value: userId }, { field: 'status', condition: 'ne', value: 'deleted' } ]) } }); dependencies.documents = docsResponse.data.payload.count;
// Verificar empresas administradas const companiesResponse = await axios.get('/api/v1/companies', { params: { filters: JSON.stringify([ { field: 'admin_user_id', condition: 'eq', value: userId } ]) } }); dependencies.companies = companiesResponse.data.payload.count;
return dependencies; } catch (error) { console.error('Error verificando dependencias:', error.message); return dependencies; }};
2. Backup Antes de Eliminar
Section titled “2. Backup Antes de Eliminar”function backupUserData($userId, $token) { try { // Obtener datos completos del usuario $userResponse = Http::withHeaders([ 'Authorization' => 'Bearer ' . $token, ])->get("https://dev-facturacion.e-dinky.test/api/v1/users/{$userId}");
if (!$userResponse->successful()) { throw new Exception('No se pudo obtener datos del usuario'); }
$userData = $userResponse->json()['payload'];
// Obtener documentos del usuario $documentsResponse = Http::withHeaders([ 'Authorization' => 'Bearer ' . $token, ])->get('https://dev-facturacion.e-dinky.test/api/v1/documents', [ 'filters' => json_encode([ ['field' => 'user_id', 'condition' => 'eq', 'value' => $userId] ]) ]);
$documents = $documentsResponse->successful() ? $documentsResponse->json()['payload']['items'] : [];
// Crear backup $backup = [ 'user' => $userData, 'documents' => $documents, 'backup_date' => date('Y-m-d H:i:s'), 'backup_by' => getCurrentUserId() ];
// Guardar backup $backupFile = "user_backup_{$userId}_" . date('Y-m-d_H-i-s') . '.json'; file_put_contents(storage_path("backups/{$backupFile}"), json_encode($backup, JSON_PRETTY_PRINT));
return $backupFile; } catch (Exception $e) { throw new Exception('Error creando backup: ' . $e->getMessage()); }}
3. Auditoría de Eliminación
Section titled “3. Auditoría de Eliminación”const logUserDeletion = async (userId, deletedBy, reason = null) => { const auditLog = { action: 'user_deletion', user_id: userId, deleted_by: deletedBy, reason: reason, timestamp: new Date().toISOString(), ip_address: getClientIP(), user_agent: getUserAgent() };
try { await axios.post('/api/v1/audit-logs', auditLog, { headers }); console.log('Eliminación registrada en auditoría'); } catch (error) { console.error('Error registrando auditoría:', error.message); }};
Códigos de Respuesta
Section titled “Códigos de Respuesta”Código | Descripción | Acción |
---|---|---|
200 | Usuario eliminado exitosamente | Confirmar eliminación |
401 | Token inválido | Renovar autenticación |
403 | Sin permisos | Verificar permisos de administrador |
404 | Usuario no encontrado | Verificar ID del usuario |
422 | No se puede eliminar | Revisar restricciones |
500 | Error del servidor | Reintentar más tarde |
Mejores Prácticas
Section titled “Mejores Prácticas”1. Eliminación Gradual
Section titled “1. Eliminación Gradual”// Proceso de eliminación en etapasconst gradualUserDeletion = async (userId) => { // Etapa 1: Desactivar usuario await updateUser(userId, { status: 'inactive' }); console.log('Usuario desactivado');
// Etapa 2: Esperar período de gracia (ej: 30 días) const gracePeriod = 30 * 24 * 60 * 60 * 1000; // 30 días console.log('Período de gracia iniciado');
// Etapa 3: Eliminar definitivamente setTimeout(async () => { const result = await deleteUser(userId); if (result.success) { console.log('Usuario eliminado definitivamente'); } }, gracePeriod);};
2. Transferencia de Propiedad
Section titled “2. Transferencia de Propiedad”// Transferir documentos antes de eliminarfunction transferUserAssets($fromUserId, $toUserId, $token) { // Transferir documentos $documentsResponse = Http::withHeaders([ 'Authorization' => 'Bearer ' . $token, ])->get('https://dev-facturacion.e-dinky.test/api/v1/documents', [ 'filters' => json_encode([ ['field' => 'user_id', 'condition' => 'eq', 'value' => $fromUserId] ]) ]);
if ($documentsResponse->successful()) { $documents = $documentsResponse->json()['payload']['items'];
foreach ($documents as $document) { // Transferir cada documento Http::withHeaders([ 'Authorization' => 'Bearer ' . $token, ])->put("https://dev-facturacion.e-dinky.test/api/v1/documents/{$document['id']}/transfer", [ 'new_owner_id' => $toUserId ]); } }
echo "Activos transferidos de usuario {$fromUserId} a {$toUserId}\n";}
3. Notificaciones de Eliminación
Section titled “3. Notificaciones de Eliminación”// Notificar eliminación a administradoresconst notifyUserDeletion = async (deletedUser, deletedBy) => { const notification = { type: 'user_deleted', message: `Usuario ${deletedUser.name} ${deletedUser.last_name} ha sido eliminado`, deleted_user: { id: deletedUser.uuid, name: deletedUser.name, email: deletedUser.email }, deleted_by: deletedBy, timestamp: new Date().toISOString() };
try { await axios.post('/api/v1/notifications/admin', notification, { headers }); console.log('Notificación enviada a administradores'); } catch (error) { console.error('Error enviando notificación:', error.message); }};
4. Recuperación de Emergencia
Section titled “4. Recuperación de Emergencia”// Sistema de recuperación de usuarios eliminadosclass UserRecoveryService { public function createRecoveryPoint($userId, $token) { $userData = $this->getUserData($userId, $token); $recoveryData = [ 'user_data' => $userData, 'created_at' => now(), 'expires_at' => now()->addDays(90) // 90 días para recuperar ];
// Guardar punto de recuperación $recoveryId = $this->saveRecoveryPoint($userId, $recoveryData);
return $recoveryId; }
public function recoverUser($recoveryId, $token) { $recoveryData = $this->getRecoveryPoint($recoveryId);
if (!$recoveryData || $recoveryData['expires_at'] < now()) { throw new Exception('Punto de recuperación expirado o no encontrado'); }
// Recrear usuario $newUser = $this->createUserFromRecovery($recoveryData['user_data'], $token);
return $newUser; }}
Casos de Uso Específicos
Section titled “Casos de Uso Específicos”1. Limpieza de Usuarios Inactivos
Section titled “1. Limpieza de Usuarios Inactivos”// Eliminar usuarios inactivos automáticamenteconst cleanupInactiveUsers = async (daysInactive = 365) => { const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - daysInactive);
const inactiveUsers = await searchUsers([ { field: 'last_login', condition: 'le', value: cutoffDate.toISOString().split('T')[0] }, { field: 'status', condition: 'eq', value: 'inactive' } ]);
console.log(`Encontrados ${inactiveUsers.length} usuarios inactivos`);
for (const user of inactiveUsers) { const canDelete = await canDeleteUser(user.uuid);
if (canDelete.can_delete) { console.log(`Eliminando usuario inactivo: ${user.email}`); await deleteUser(user.uuid); } else { console.log(`Omitiendo ${user.email}: ${canDelete.reason}`); } }};
2. Eliminación por Violación de Políticas
Section titled “2. Eliminación por Violación de Políticas”// Eliminar usuario por violación de políticasfunction deleteUserForPolicyViolation($userId, $violationType, $evidence, $token) { // Registrar violación $violation = [ 'user_id' => $userId, 'violation_type' => $violationType, 'evidence' => $evidence, 'reported_at' => now(), 'action_taken' => 'user_deletion' ];
// Guardar evidencia $evidenceFile = saveViolationEvidence($userId, $evidence);
// Crear backup completo $backupFile = backupUserData($userId, $token);
// Eliminar usuario $result = deleteUser($userId, $token);
if ($result) { // Registrar en sistema de compliance recordComplianceAction($violation, $backupFile, $evidenceFile);
// Notificar a legal/compliance notifyComplianceTeam($violation); }
return $result;}
3. Migración de Datos Antes de Eliminación
Section titled “3. Migración de Datos Antes de Eliminación”// Migrar datos críticos antes de eliminarconst migrateAndDeleteUser = async (userId, migrationTarget) => { try { // 1. Identificar datos críticos const criticalData = await identifyCriticalUserData(userId);
// 2. Migrar documentos importantes if (criticalData.documents.length > 0) { await migrateDocuments(criticalData.documents, migrationTarget.documents); }
// 3. Migrar configuraciones if (criticalData.settings) { await migrateUserSettings(criticalData.settings, migrationTarget.settings); }
// 4. Actualizar referencias await updateUserReferences(userId, migrationTarget.userId);
// 5. Eliminar usuario const result = await deleteUser(userId);
if (result.success) { console.log('Usuario eliminado y datos migrados correctamente'); return { success: true, migrated: criticalData }; }
} catch (error) { console.error('Error en migración y eliminación:', error.message); return { success: false, error: error.message }; }};
Notas Importantes
Section titled “Notas Importantes”- 🚨 Irreversible: La eliminación es permanente y no se puede deshacer fácilmente
- 🔐 Permisos: Solo administradores pueden eliminar usuarios
- 📋 Verificaciones: Siempre verificar dependencias antes de eliminar
- 💾 Backup: Crear respaldo antes de eliminaciones importantes
- 📝 Auditoría: Registrar todas las eliminaciones para auditoría
- 🔄 Transferencia: Transferir activos críticos antes de eliminar
- ⏰ Período de gracia: Considerar período de gracia para recuperación
- 🚫 Restricciones: Respetar restricciones del sistema
- 📧 Notificaciones: Notificar eliminaciones a administradores
- 🔍 Verificación: Verificar que la eliminación se completó correctamente