feat: permite rechazar (eliminar) usuarios en pending_verification
Antes solo se podia rechazar un usuario en pending_approval. Una cuenta autorregistrada que nunca confirmo su correo quedaba en pending_verification para siempre, sin ninguna accion disponible en Usuarios para quitarla. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog - project.linkedcorp.net
|
# Changelog - project.linkedcorp.net
|
||||||
|
|
||||||
|
## [1.9.0] - 2026-09-10
|
||||||
|
### Added
|
||||||
|
- Organización → Usuarios: ahora se puede "Rechazar" (eliminar) también a un usuario en
|
||||||
|
`pending_verification` (autorregistro que nunca confirmó su correo) — antes esa acción solo
|
||||||
|
existía para `pending_approval`, así que una cuenta abandonada antes de verificar el correo no
|
||||||
|
tenía ninguna forma de quitarse desde la UI.
|
||||||
|
|
||||||
## [1.8.1] - 2026-09-10
|
## [1.8.1] - 2026-09-10
|
||||||
### Fixed
|
### Fixed
|
||||||
- "Agregar dependencia" en una actividad no daba ninguna señal cuando no había otra actividad del
|
- "Agregar dependencia" en una actividad no daba ninguna señal cuando no había otra actividad del
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-backend",
|
"name": "project-linkedcorp-backend",
|
||||||
"version": "1.8.1",
|
"version": "1.9.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/server.js",
|
"main": "src/server.js",
|
||||||
|
|||||||
@@ -79,10 +79,15 @@ export async function approveUser(id, payload, actorId) {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rechaza y borra una cuenta que aun no esta activa: tanto la que ya paso la verificacion de
|
||||||
|
// correo y espera aprobacion, como la que nunca llego a confirmar su correo (quedo abandonada en
|
||||||
|
// 'pending_verification' — antes no habia forma de quitarla desde la UI).
|
||||||
export async function rejectUser(id, actorId) {
|
export async function rejectUser(id, actorId) {
|
||||||
const existing = await repo.findById(id);
|
const existing = await repo.findById(id);
|
||||||
if (!existing) throw new HttpError(404, 'Usuario no encontrado');
|
if (!existing) throw new HttpError(404, 'Usuario no encontrado');
|
||||||
if (existing.status !== 'pending_approval') throw new HttpError(400, 'El usuario no esta pendiente de aprobacion');
|
if (!['pending_approval', 'pending_verification'].includes(existing.status)) {
|
||||||
await logAudit({ userId: actorId, action: 'reject', entityType: 'user', entityId: id, detail: { email: existing.email } });
|
throw new HttpError(400, 'El usuario no esta pendiente de aprobacion ni de verificacion');
|
||||||
|
}
|
||||||
|
await logAudit({ userId: actorId, action: 'reject', entityType: 'user', entityId: id, detail: { email: existing.email, status: existing.status } });
|
||||||
await repo.remove(id);
|
await repo.remove(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-frontend",
|
"name": "project-linkedcorp-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.8.1",
|
"version": "1.9.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -132,19 +132,23 @@ export default function UsersPanel() {
|
|||||||
getSearchHaystack={(u) => `${u.name} ${u.email} ${u.role_name} ${u.department_name || ''}`}
|
getSearchHaystack={(u) => `${u.name} ${u.email} ${u.role_name} ${u.department_name || ''}`}
|
||||||
getRowKey={(u) => u.id}
|
getRowKey={(u) => u.id}
|
||||||
onRowClick={canManage ? startEdit : undefined}
|
onRowClick={canManage ? startEdit : undefined}
|
||||||
rowActions={canManage ? (u) => (
|
rowActions={canManage ? (u) => {
|
||||||
u.status === 'pending_approval'
|
if (u.status === 'pending_approval') {
|
||||||
? [
|
return [
|
||||||
{ label: t('user_approve'), icon: Check, onClick: () => startApprove(u) },
|
{ label: t('user_approve'), icon: Check, onClick: () => startApprove(u) },
|
||||||
{ label: t('user_reject'), icon: XIcon, danger: true, onClick: () => confirmReject(u) },
|
{ label: t('user_reject'), icon: XIcon, danger: true, onClick: () => confirmReject(u) },
|
||||||
]
|
];
|
||||||
: [
|
}
|
||||||
|
if (u.status === 'pending_verification') {
|
||||||
|
return [{ label: t('user_reject'), icon: XIcon, danger: true, onClick: () => confirmReject(u) }];
|
||||||
|
}
|
||||||
|
return [
|
||||||
{ label: t('common_edit'), onClick: () => startEdit(u) },
|
{ label: t('common_edit'), onClick: () => startEdit(u) },
|
||||||
u.is_active
|
u.is_active
|
||||||
? { label: t('common_inactive'), icon: UserX, danger: true, onClick: () => toggleActive(u) }
|
? { label: t('common_inactive'), icon: UserX, danger: true, onClick: () => toggleActive(u) }
|
||||||
: { label: t('common_active'), icon: UserCheck, onClick: () => toggleActive(u) },
|
: { label: t('common_active'), icon: UserCheck, onClick: () => toggleActive(u) },
|
||||||
]
|
];
|
||||||
) : undefined}
|
} : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DetailPopup open={editing} title={selected ? t('common_edit') : t('user_new')} onClose={() => setEditing(false)} width={560} height={440}>
|
<DetailPopup open={editing} title={selected ? t('common_edit') : t('user_new')} onClose={() => setEditing(false)} width={560} height={440}>
|
||||||
|
|||||||
Reference in New Issue
Block a user