Actualizar Usuarios
Actualizar Usuarios
Section titled “Actualizar Usuarios”Dominio: https://test-api-factura.edw-dev.com
Dominio: https://api-financiero.e-dinky.com
Endpoints para actualizar información de usuarios, incluyendo datos personales y información propia.
Endpoints Disponibles
Section titled “Endpoints Disponibles”PUT /api/v1/users/update
- Actualizar usuario (administrador)PUT /api/v1/users/update-my-information
- Actualizar mi información
PUT /api/v1/users/update
Section titled “PUT /api/v1/users/update”Actualiza la información de cualquier usuario del sistema. Requiere permisos de administrador.
Información General
Section titled “Información General”- Método:
PUT
- Endpoint:
/api/v1/users/update
- Autenticación: Requerida (Bearer Token)
- Permisos: Administrador
- Validación: Campos opcionales, solo se actualizan los enviados
Headers Requeridos
Section titled “Headers Requeridos”Content-Type: application/jsonAccept: application/jsonAuthorization: Bearer {token}
Parámetros del Body
Section titled “Parámetros del Body”Campo | Tipo | Requerido | Descripción | Validaciones |
---|---|---|---|---|
uuid | integer | Sí | ID del usuario a actualizar | Debe existir |
name | string | No | Nombre del usuario | 2-50 caracteres, solo letras |
last_name | string | No | Apellido del usuario | 2-50 caracteres, solo letras |
email | string | No | Email del usuario | Formato válido, único |
phone | string | No | Teléfono del usuario | Formato válido |
password | string | No | Nueva contraseña | Mínimo 8 caracteres |
status | string | No | Estado del usuario | active , inactive |
role_id | integer | No | ID del rol | Debe existir |
Validaciones Específicas
Section titled “Validaciones Específicas”Nombre y Apellido
Section titled “Nombre y Apellido”- Mínimo 2 caracteres, máximo 50
- Solo letras y espacios
- No números ni caracteres especiales
- Formato de email válido
- Único en el sistema
- No puede estar en uso por otro usuario
Teléfono
Section titled “Teléfono”- Formato internacional válido
- Ejemplo:
+593987654321
Contraseña
Section titled “Contraseña”- Mínimo 8 caracteres
- Al menos una letra mayúscula
- Al menos una letra minúscula
- Al menos un número
- Al menos un carácter especial
Ejemplo de Implementación
Section titled “Ejemplo de Implementación”Solicitud Básica
Section titled “Solicitud Básica”{ "uuid": 123456789, "name": "Juan Carlos", "last_name": "Pérez González", "phone": "+593987654321"}
Respuesta Exitosa (201)
Section titled “Respuesta Exitosa (201)”{ "message": "Usuario actualizado correctamente", "status": "OK", "payload": { "uuid": 123456789, "name": "Juan Carlos", "last_name": "Pérez González", "phone": "+593987654321", "status": "active", "updated_at": "2025-01-17 15:30:00" }}
Actualización con Cambio de Rol
Section titled “Actualización con Cambio de Rol”{ "uuid": 123456789, "role_id": 2, "status": "active"}
Usuario No Encontrado (404)
Section titled “Usuario No Encontrado (404)”{ "message": "Usuario no encontrado", "status": "ERROR"}
Datos Inválidos (422)
Section titled “Datos Inválidos (422)”{ "message": "Datos de entrada inválidos", "status": "ERROR", "errors": { "email": ["El email ya está en uso"], "phone": ["El formato del teléfono es inválido"] }}
PUT /api/v1/users/update-my-information
Section titled “PUT /api/v1/users/update-my-information”Permite al usuario autenticado actualizar su propia información personal.
Información General
Section titled “Información General”- Método:
PUT
- Endpoint:
/api/v1/users/update-my-information
- Autenticación: Requerida (Bearer Token)
- Permisos: Usuario autenticado
- Limitaciones: No puede cambiar rol ni estado
Headers Requeridos
Section titled “Headers Requeridos”Content-Type: application/jsonAccept: application/jsonAuthorization: Bearer {token}
Parámetros del Body
Section titled “Parámetros del Body”Campo | Tipo | Requerido | Descripción | Validaciones |
---|---|---|---|---|
name | string | No | Nombre del usuario | 2-50 caracteres, solo letras |
last_name | string | No | Apellido del usuario | 2-50 caracteres, solo letras |
email | string | No | Email del usuario | Formato válido, único |
phone | string | No | Teléfono del usuario | Formato válido |
password | string | No | Nueva contraseña | Mínimo 8 caracteres |
current_password | string | Condicional | Contraseña actual | Requerida si se cambia password |
Ejemplo de Implementación
Section titled “Ejemplo de Implementación”Actualizar Información Personal
Section titled “Actualizar Información Personal”{ "name": "María Elena", "last_name": "González Ruiz", "phone": "+593998765432"}
Cambiar Contraseña
Section titled “Cambiar Contraseña”{ "current_password": "mi_password_actual", "password": "nueva_password_segura123!"}
Respuesta Exitosa (201)
Section titled “Respuesta Exitosa (201)”{ "message": "Información actualizada correctamente", "status": "OK", "payload": { "uuid": 123456789, "name": "María Elena", "last_name": "González Ruiz", "phone": "+593998765432", "updated_at": "2025-01-17 16:45:00" }}
Contraseña Actual Incorrecta (422)
Section titled “Contraseña Actual Incorrecta (422)”{ "message": "Datos de entrada inválidos", "status": "ERROR", "errors": { "current_password": ["La contraseña actual es incorrecta"] }}
Ejemplos de Código
Section titled “Ejemplos de Código”# Actualizar usuario (administrador)curl -X PUT "https://dev-facturacion.e-dinky.test/api/v1/users/update" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Authorization: Bearer {token}" \ -d '{ "uuid": 123456789, "name": "Juan Carlos", "last_name": "Pérez González", "email": "[email protected]", "phone": "+593987654321" }'
# Actualizar mi informacióncurl -X PUT "https://dev-facturacion.e-dinky.test/api/v1/users/update-my-information" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Authorization: Bearer {token}" \ -d '{ "name": "María Elena", "last_name": "González Ruiz", "phone": "+593998765432" }'
# Cambiar contraseñacurl -X PUT "https://dev-facturacion.e-dinky.test/api/v1/users/update-my-information" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Authorization: Bearer {token}" \ -d '{ "current_password": "mi_password_actual", "password": "nueva_password_segura123!" }'
<?php
use Illuminate\Support\Facades\Http;
$token = 'your-api-token';
// Actualizar usuario (administrador)function updateUser($userId, $data, $token) { $response = Http::withHeaders([ 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $token, ])->put('https://dev-facturacion.e-dinky.test/api/v1/users/update', array_merge([ 'uuid' => $userId ], $data));
if ($response->successful()) { $user = $response->json()['payload']; echo "Usuario actualizado: " . $user['name'] . " " . $user['last_name'] . "\n"; return $user; } else { $errors = $response->json(); echo "Error actualizando usuario: " . $errors['message'] . "\n"; if (isset($errors['errors'])) { foreach ($errors['errors'] as $field => $messages) { echo "- {$field}: " . implode(', ', $messages) . "\n"; } } return false; }}
// Actualizar mi informaciónfunction updateMyInformation($data, $token) { $response = Http::withHeaders([ 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $token, ])->put('https://dev-facturacion.e-dinky.test/api/v1/users/update-my-information', $data);
if ($response->successful()) { $user = $response->json()['payload']; echo "Mi información actualizada correctamente\n"; return $user; } else { $errors = $response->json(); echo "Error: " . $errors['message'] . "\n"; return false; }}
// Ejemplos de uso
// Actualizar datos básicos de un usuario$userData = [ 'name' => 'Juan Carlos', 'last_name' => 'Pérez González', 'phone' => '+593987654321'];updateUser(123456789, $userData, $token);
// Cambiar rol de usuario$roleData = [ 'role_id' => 2, 'status' => 'active'];updateUser(123456789, $roleData, $token);
// Actualizar mi información personal$myData = [ 'name' => 'María Elena', 'last_name' => 'González Ruiz', 'phone' => '+593998765432'];updateMyInformation($myData, $token);
// Cambiar mi contraseña$passwordData = [ 'current_password' => 'mi_password_actual', 'password' => 'nueva_password_segura123!'];updateMyInformation($passwordData, $token);
// Función para validar datos antes de enviarfunction validateUserData($data) { $errors = [];
if (isset($data['name']) && (strlen($data['name']) < 2 || strlen($data['name']) > 50)) { $errors['name'] = 'El nombre debe tener entre 2 y 50 caracteres'; }
if (isset($data['email']) && !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) { $errors['email'] = 'El formato del email es inválido'; }
if (isset($data['phone']) && !preg_match('/^\+[1-9]\d{1,14}$/', $data['phone'])) { $errors['phone'] = 'El formato del teléfono es inválido'; }
if (isset($data['password']) && strlen($data['password']) < 8) { $errors['password'] = 'La contraseña debe tener al menos 8 caracteres'; }
return empty($errors) ? true : $errors;}
const axios = require('axios');
const token = 'your-api-token';
const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': `Bearer ${token}`};
// Actualizar usuario (administrador)const updateUser = async (userId, data) => { try { const response = await axios.put('https://dev-facturacion.e-dinky.test/api/v1/users/update', { uuid: userId, ...data }, { headers });
console.log('Usuario actualizado:', response.data.payload.name); return response.data.payload; } catch (error) { if (error.response?.status === 404) { console.error('Usuario no encontrado'); } else if (error.response?.status === 422) { console.error('Errores de validación:'); const errors = error.response.data.errors; Object.keys(errors).forEach(field => { console.error(`- ${field}: ${errors[field].join(', ')}`); }); } else { console.error('Error:', error.response?.data?.message || error.message); } throw error; }};
// Actualizar mi informaciónconst updateMyInformation = async (data) => { try { const response = await axios.put('https://dev-facturacion.e-dinky.test/api/v1/users/update-my-information', data, { headers });
console.log('Mi información actualizada correctamente'); return response.data.payload; } catch (error) { if (error.response?.status === 422) { console.error('Errores de validación:'); const errors = error.response.data.errors; Object.keys(errors).forEach(field => { console.error(`- ${field}: ${errors[field].join(', ')}`); }); } else { console.error('Error:', error.response?.data?.message || error.message); } throw error; }};
// Función de validaciónconst validateUserData = (data) => { const errors = {};
if (data.name && (data.name.length < 2 || data.name.length > 50)) { errors.name = 'El nombre debe tener entre 2 y 50 caracteres'; }
if (data.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) { errors.email = 'El formato del email es inválido'; }
if (data.phone && !/^\+[1-9]\d{1,14}$/.test(data.phone)) { errors.phone = 'El formato del teléfono es inválido'; }
if (data.password && data.password.length < 8) { errors.password = 'La contraseña debe tener al menos 8 caracteres'; }
return Object.keys(errors).length === 0 ? null : errors;};
// Función para actualización seguraconst safeUpdateUser = async (userId, data) => { // Validar datos antes de enviar const validationErrors = validateUserData(data); if (validationErrors) { console.error('Errores de validación local:', validationErrors); return { success: false, errors: validationErrors }; }
try { const user = await updateUser(userId, data); return { success: true, data: user }; } catch (error) { return { success: false, error: error.message }; }};
// Función para cambio de contraseña seguroconst changePassword = async (currentPassword, newPassword) => { if (newPassword.length < 8) { throw new Error('La nueva contraseña debe tener al menos 8 caracteres'); }
if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/.test(newPassword)) { throw new Error('La contraseña debe contener al menos: una mayúscula, una minúscula, un número y un carácter especial'); }
return await updateMyInformation({ current_password: currentPassword, password: newPassword });};
// Ejemplos de uso(async () => { try { // Actualizar datos básicos de un usuario const userData = { name: 'Juan Carlos', last_name: 'Pérez González', phone: '+593987654321' }; await updateUser(123456789, userData);
// Cambiar rol de usuario await updateUser(123456789, { role_id: 2, status: 'active' });
// Actualizar mi información personal await updateMyInformation({ name: 'María Elena', last_name: 'González Ruiz', phone: '+593998765432' });
// Cambiar contraseña await changePassword('mi_password_actual', 'Nueva_Password123!');
// Actualización segura con validación const result = await safeUpdateUser(123456789, { name: 'Nuevo Nombre', });
if (result.success) { console.log('Usuario actualizado:', result.data); } else { console.log('Error en actualización:', result.errors || result.error); }
} catch (error) { console.error('Error en operaciones:', error.message); }})();
Validaciones Avanzadas
Section titled “Validaciones Avanzadas”1. Validación de Contraseña Segura
Section titled “1. Validación de Contraseña Segura”const validatePassword = (password) => { const requirements = { length: password.length >= 8, uppercase: /[A-Z]/.test(password), lowercase: /[a-z]/.test(password), number: /\d/.test(password), special: /[@$!%*?&]/.test(password) };
const missing = Object.keys(requirements).filter(req => !requirements[req]);
if (missing.length > 0) { throw new Error(`La contraseña debe cumplir: ${missing.join(', ')}`); }
return true;};
2. Validación de Email Único
Section titled “2. Validación de Email Único”function validateUniqueEmail($email, $currentUserId = null) { $filters = [['field' => 'email', 'condition' => 'eq', 'value' => $email]];
$users = searchUsers($filters);
if (!empty($users)) { foreach ($users as $user) { if ($user['uuid'] !== $currentUserId) { throw new Exception('El email ya está en uso por otro usuario'); } } }
return true;}
3. Validación de Teléfono Internacional
Section titled “3. Validación de Teléfono Internacional”const validateInternationalPhone = (phone) => { // Formato internacional: +[código país][número] const phoneRegex = /^\+[1-9]\d{1,14}$/;
if (!phoneRegex.test(phone)) { throw new Error('El teléfono debe estar en formato internacional (+593987654321)'); }
// Validaciones específicas por país const countryValidations = { '+593': /^\+593[0-9]{9}$/, // Ecuador '+57': /^\+57[0-9]{10}$/, // Colombia '+51': /^\+51[0-9]{9}$/, // Perú };
const countryCode = phone.substring(0, 4); if (countryValidations[countryCode] && !countryValidations[countryCode].test(phone)) { throw new Error(`Formato de teléfono inválido para ${countryCode}`); }
return true;};
Códigos de Respuesta
Section titled “Códigos de Respuesta”Código | Descripción | Acción |
---|---|---|
201 | Actualización exitosa | Procesar datos actualizados |
400 | Datos inválidos | Revisar formato de datos |
401 | Token inválido | Renovar autenticación |
403 | Sin permisos | Verificar permisos de usuario |
404 | Usuario no encontrado | Verificar ID del usuario |
422 | Errores de validación | Corregir datos según errores |
500 | Error del servidor | Reintentar más tarde |
Mejores Prácticas
Section titled “Mejores Prácticas”1. Actualización Parcial
Section titled “1. Actualización Parcial”// Solo enviar campos que realmente cambiaronconst updateUserPartial = (userId, originalData, newData) => { const changes = {};
Object.keys(newData).forEach(key => { if (originalData[key] !== newData[key]) { changes[key] = newData[key]; } });
if (Object.keys(changes).length === 0) { console.log('No hay cambios para actualizar'); return; }
return updateUser(userId, changes);};
2. Confirmación de Cambios Críticos
Section titled “2. Confirmación de Cambios Críticos”// Confirmar cambios importantes como email o rolfunction updateUserWithConfirmation($userId, $data, $confirmationToken = null) { $criticalFields = ['email', 'role_id', 'status']; $hasCriticalChanges = array_intersect(array_keys($data), $criticalFields);
if ($hasCriticalChanges && !$confirmationToken) { throw new Exception('Se requiere confirmación para cambios críticos'); }
if ($confirmationToken) { // Validar token de confirmación validateConfirmationToken($confirmationToken, $userId); }
return updateUser($userId, $data);}
3. Historial de Cambios
Section titled “3. Historial de Cambios”// Registrar cambios para auditoríaconst updateUserWithHistory = async (userId, data) => { // Obtener datos actuales const currentUser = await getUserById(userId);
// Realizar actualización const updatedUser = await updateUser(userId, data);
// Registrar cambios const changes = Object.keys(data).map(field => ({ field, old_value: currentUser[field], new_value: data[field], changed_at: new Date().toISOString(), changed_by: getCurrentUserId() }));
await logUserChanges(userId, changes);
return updatedUser;};
4. Validación en Tiempo Real
Section titled “4. Validación en Tiempo Real”// Validar campos mientras el usuario escribeconst validateFieldRealTime = async (field, value, userId = null) => { const validators = { email: async (email) => { if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { return 'Formato de email inválido'; } // Verificar si está disponible const isAvailable = await checkEmailAvailability(email, userId); return isAvailable ? null : 'Email ya está en uso'; }, phone: (phone) => { return /^\+[1-9]\d{1,14}$/.test(phone) ? null : 'Formato de teléfono inválido'; }, name: (name) => { return (name.length >= 2 && name.length <= 50) ? null : 'Nombre debe tener entre 2 y 50 caracteres'; } };
if (validators[field]) { return await validators[field](value); }
return null;};
Casos de Uso Específicos
Section titled “Casos de Uso Específicos”1. Actualización Masiva de Usuarios
Section titled “1. Actualización Masiva de Usuarios”// Actualizar múltiples usuarios con los mismos cambiosfunction bulkUpdateUsers($userIds, $data) { $results = [];
foreach ($userIds as $userId) { try { $result = updateUser($userId, $data); $results['success'][] = $userId; } catch (Exception $e) { $results['failed'][] = [ 'user_id' => $userId, 'error' => $e->getMessage() ]; } }
return $results;}
2. Migración de Datos de Usuario
Section titled “2. Migración de Datos de Usuario”// Migrar datos de un sistema externoconst migrateUserData = async (externalUserData) => { const mappedData = { name: externalUserData.first_name, last_name: externalUserData.last_name, email: externalUserData.email_address, phone: formatPhoneNumber(externalUserData.phone_number) };
// Validar datos mapeados const validationErrors = validateUserData(mappedData); if (validationErrors) { throw new Error(`Datos inválidos: ${JSON.stringify(validationErrors)}`); }
return await updateUser(externalUserData.internal_id, mappedData);};
3. Sincronización con Sistemas Externos
Section titled “3. Sincronización con Sistemas Externos”// Sincronizar cambios con sistema externofunction syncUserUpdate($userId, $data) { // Actualizar en sistema local $localUser = updateUser($userId, $data);
// Sincronizar con sistema externo try { $externalResponse = syncWithExternalSystem($localUser);
if (!$externalResponse['success']) { // Revertir cambios locales si falla la sincronización rollbackUserUpdate($userId, $data); throw new Exception('Error en sincronización externa'); } } catch (Exception $e) { error_log('Error sincronizando usuario: ' . $e->getMessage()); // Marcar para reintento posterior markForRetrySync($userId, $data); }
return $localUser;}
Notas Importantes
Section titled “Notas Importantes”- 🔐 Seguridad: Validar permisos antes de actualizar
- ✅ Validación: Implementar validación tanto local como del servidor
- 📝 Auditoría: Registrar cambios importantes para auditoría
- 🔄 Sincronización: Considerar sincronización con sistemas externos
- 💾 Backup: Mantener respaldo antes de cambios críticos
- 🚫 Restricciones: Algunos campos pueden tener restricciones especiales
- 📧 Notificaciones: Notificar cambios importantes al usuario
- 🔒 Contraseñas: Usar hash seguro para contraseñas
- 📱 Tiempo real: Validar disponibilidad en tiempo real
- 🎯 Parcial: Enviar solo campos modificados para eficiencia