refactor(users): eliminar columna orden, listar alfabéticamente
- Migración 012: ALTER TABLE users DROP COLUMN orden - Lookups: abogadoNames y allUsers ordenan por name ASC - API admin: create/update_user dejan de leer/escribir orden - UI admin: removida la columna "Orden" de la tabla y el input "Orden" del modal de usuario
This commit is contained in:
+7
-11
@@ -46,7 +46,6 @@ try {
|
|||||||
$name = trim((string)($b['name'] ?? ''));
|
$name = trim((string)($b['name'] ?? ''));
|
||||||
$role = in_array(($b['role'] ?? ''), ROLES, true) ? $b['role'] : 'usuario';
|
$role = in_array(($b['role'] ?? ''), ROLES, true) ? $b['role'] : 'usuario';
|
||||||
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
|
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
|
||||||
$orden = (int)($b['orden'] ?? 0);
|
|
||||||
|
|
||||||
// Solo admins pueden crear nuevos admins
|
// Solo admins pueden crear nuevos admins
|
||||||
if ($role === 'admin' && !Auth::isAdmin()) {
|
if ($role === 'admin' && !Auth::isAdmin()) {
|
||||||
@@ -58,21 +57,20 @@ try {
|
|||||||
if ($exists->fetch()) err('Ya existe un usuario con ese email', 409);
|
if ($exists->fetch()) err('Ya existe un usuario con ese email', 409);
|
||||||
|
|
||||||
$ins = $pdo->prepare(
|
$ins = $pdo->prepare(
|
||||||
'INSERT INTO users (email, name, role, activo, orden, first_seen_at, last_login_at)
|
'INSERT INTO users (email, name, role, activo, first_seen_at, last_login_at)
|
||||||
VALUES (:email, :name, :role, :activo, :orden, NULL, NULL)'
|
VALUES (:email, :name, :role, :activo, NULL, NULL)'
|
||||||
);
|
);
|
||||||
$ins->execute([
|
$ins->execute([
|
||||||
':email' => $email, ':name' => $name, ':role' => $role,
|
':email' => $email, ':name' => $name, ':role' => $role,
|
||||||
':activo' => $activo, ':orden' => $orden,
|
':activo' => $activo,
|
||||||
]);
|
]);
|
||||||
$id = (int)$pdo->lastInsertId();
|
$id = (int)$pdo->lastInsertId();
|
||||||
|
|
||||||
$sel = $pdo->prepare('SELECT id, email, name, role, activo, orden, first_seen_at, last_login_at FROM users WHERE id = :id');
|
$sel = $pdo->prepare('SELECT id, email, name, role, activo, first_seen_at, last_login_at FROM users WHERE id = :id');
|
||||||
$sel->execute([':id' => $id]);
|
$sel->execute([':id' => $id]);
|
||||||
$row = $sel->fetch();
|
$row = $sel->fetch();
|
||||||
$row['id'] = (int)$row['id'];
|
$row['id'] = (int)$row['id'];
|
||||||
$row['activo'] = (int)$row['activo'];
|
$row['activo'] = (int)$row['activo'];
|
||||||
$row['orden'] = (int)$row['orden'];
|
|
||||||
AuditLog::log('admin', 'create_user', 'user', (string)$id, $email, ['role'=>$role, 'name'=>$name]);
|
AuditLog::log('admin', 'create_user', 'user', (string)$id, $email, ['role'=>$role, 'name'=>$name]);
|
||||||
ok($row);
|
ok($row);
|
||||||
}
|
}
|
||||||
@@ -116,25 +114,23 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$name = trim((string)($b['name'] ?? ''));
|
$name = trim((string)($b['name'] ?? ''));
|
||||||
$orden = (int)($b['orden'] ?? 0);
|
|
||||||
|
|
||||||
$upd = $pdo->prepare(
|
$upd = $pdo->prepare(
|
||||||
'UPDATE users SET email = :email, name = :name, role = :role,
|
'UPDATE users SET email = :email, name = :name, role = :role,
|
||||||
activo = :activo, orden = :orden
|
activo = :activo
|
||||||
WHERE id = :id'
|
WHERE id = :id'
|
||||||
);
|
);
|
||||||
$upd->execute([
|
$upd->execute([
|
||||||
':email' => $newEmail, ':name' => $name, ':role' => $newRole,
|
':email' => $newEmail, ':name' => $name, ':role' => $newRole,
|
||||||
':activo' => $newActivo, ':orden' => $orden,
|
':activo' => $newActivo,
|
||||||
':id' => $id,
|
':id' => $id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$sel = $pdo->prepare('SELECT id, email, name, role, activo, orden, first_seen_at, last_login_at FROM users WHERE id = :id');
|
$sel = $pdo->prepare('SELECT id, email, name, role, activo, first_seen_at, last_login_at FROM users WHERE id = :id');
|
||||||
$sel->execute([':id' => $id]);
|
$sel->execute([':id' => $id]);
|
||||||
$row = $sel->fetch();
|
$row = $sel->fetch();
|
||||||
$row['id'] = (int)$row['id'];
|
$row['id'] = (int)$row['id'];
|
||||||
$row['activo'] = (int)$row['activo'];
|
$row['activo'] = (int)$row['activo'];
|
||||||
$row['orden'] = (int)$row['orden'];
|
|
||||||
$diff = [];
|
$diff = [];
|
||||||
if ($existing['role'] !== $newRole) $diff['role'] = ['from'=>$existing['role'], 'to'=>$newRole];
|
if ($existing['role'] !== $newRole) $diff['role'] = ['from'=>$existing['role'], 'to'=>$newRole];
|
||||||
if ((int)$existing['activo'] !== $newActivo) $diff['activo'] = ['from'=>(int)$existing['activo'], 'to'=>$newActivo];
|
if ((int)$existing['activo'] !== $newActivo) $diff['activo'] = ['from'=>(int)$existing['activo'], 'to'=>$newActivo];
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- Donna — Schema 012: eliminar columna users.orden
|
||||||
|
-- ============================================================
|
||||||
|
-- Decisión: simplificar. Las listas se ordenan alfabéticamente
|
||||||
|
-- por nombre. No hay necesidad de un orden manual.
|
||||||
|
|
||||||
|
ALTER TABLE users DROP COLUMN IF EXISTS orden;
|
||||||
+3
-4
@@ -19,7 +19,7 @@ final class Lookups {
|
|||||||
WHERE activo = 1
|
WHERE activo = 1
|
||||||
AND role IN ('socio','abogado')
|
AND role IN ('socio','abogado')
|
||||||
AND name != ''
|
AND name != ''
|
||||||
ORDER BY orden ASC, name ASC"
|
ORDER BY name ASC"
|
||||||
)->fetchAll();
|
)->fetchAll();
|
||||||
return array_map(fn($r) => $r['name'], $rows);
|
return array_map(fn($r) => $r['name'], $rows);
|
||||||
}
|
}
|
||||||
@@ -43,15 +43,14 @@ final class Lookups {
|
|||||||
* Si $includeAdmins es false, oculta el rol admin (uso para socios).
|
* Si $includeAdmins es false, oculta el rol admin (uso para socios).
|
||||||
*/
|
*/
|
||||||
public static function allUsers(bool $includeAdmins = true): array {
|
public static function allUsers(bool $includeAdmins = true): array {
|
||||||
$sql = "SELECT id, email, name, role, activo, orden, first_seen_at, last_login_at
|
$sql = "SELECT id, email, name, role, activo, first_seen_at, last_login_at
|
||||||
FROM users";
|
FROM users";
|
||||||
if (!$includeAdmins) $sql .= " WHERE role != 'admin'";
|
if (!$includeAdmins) $sql .= " WHERE role != 'admin'";
|
||||||
$sql .= " ORDER BY FIELD(role,'admin','socio','abogado','usuario'), name ASC, email ASC";
|
$sql .= " ORDER BY name ASC, email ASC";
|
||||||
$rows = Db::pdo()->query($sql)->fetchAll();
|
$rows = Db::pdo()->query($sql)->fetchAll();
|
||||||
foreach ($rows as &$r) {
|
foreach ($rows as &$r) {
|
||||||
$r['id'] = (int)$r['id'];
|
$r['id'] = (int)$r['id'];
|
||||||
$r['activo'] = (int)$r['activo'];
|
$r['activo'] = (int)$r['activo'];
|
||||||
$r['orden'] = (int)$r['orden'];
|
|
||||||
}
|
}
|
||||||
return $rows;
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-15
@@ -234,7 +234,6 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
|||||||
<th>Nombre completo</th>
|
<th>Nombre completo</th>
|
||||||
<th>Rol</th>
|
<th>Rol</th>
|
||||||
<th>Activo</th>
|
<th>Activo</th>
|
||||||
<th>Orden</th>
|
|
||||||
<th>Último login</th>
|
<th>Último login</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -339,16 +338,8 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg-row">
|
<div class="fg">
|
||||||
<div class="fg">
|
<label class="fg-check"><input type="checkbox" id="f-activo" checked> Activo — puede entrar a Donna</label>
|
||||||
<label>Orden</label>
|
|
||||||
<input type="number" id="f-orden" value="0" step="1">
|
|
||||||
<div class="fg-hint">Para ordenar el dropdown manualmente.</div>
|
|
||||||
</div>
|
|
||||||
<div class="fg">
|
|
||||||
<label> </label>
|
|
||||||
<label class="fg-check"><input type="checkbox" id="f-activo" checked> Activo — puede entrar a Donna</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-foot" style="justify-content:space-between;">
|
<div class="modal-foot" style="justify-content:space-between;">
|
||||||
@@ -463,7 +454,6 @@ function render(){
|
|||||||
<td>${esc(u.name) || '<span class="placeholder">—</span>'}</td>
|
<td>${esc(u.name) || '<span class="placeholder">—</span>'}</td>
|
||||||
<td><span class="role-pill role-${u.role}">${ROLE_LABEL[u.role] || u.role}</span></td>
|
<td><span class="role-pill role-${u.role}">${ROLE_LABEL[u.role] || u.role}</span></td>
|
||||||
<td><span class="activo-pill activo-${u.activo}">${u.activo ? 'Activo' : 'Inactivo'}</span></td>
|
<td><span class="activo-pill activo-${u.activo}">${u.activo ? 'Activo' : 'Inactivo'}</span></td>
|
||||||
<td>${u.orden}</td>
|
|
||||||
<td class="last-login">${u.last_login_at ? fmtDate(u.last_login_at) : '<span class="placeholder">Nunca</span>'}</td>
|
<td class="last-login">${u.last_login_at ? fmtDate(u.last_login_at) : '<span class="placeholder">Nunca</span>'}</td>
|
||||||
<td><div class="actions"><button class="btn-icon" title="Editar" onclick="openEdit(${u.id})">✎</button></div></td>
|
<td><div class="actions"><button class="btn-icon" title="Editar" onclick="openEdit(${u.id})">✎</button></div></td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
@@ -476,7 +466,6 @@ function openCreate(){
|
|||||||
$('f-email').value = ''; $('f-email').readOnly = false;
|
$('f-email').value = ''; $('f-email').readOnly = false;
|
||||||
$('f-name').value = '';
|
$('f-name').value = '';
|
||||||
$('f-role-edit').value = 'usuario';
|
$('f-role-edit').value = 'usuario';
|
||||||
$('f-orden').value = '0';
|
|
||||||
$('f-activo').checked = true;
|
$('f-activo').checked = true;
|
||||||
$('hint-email').textContent = 'El email debe coincidir exactamente con la cuenta de Mailcow que el usuario usa para entrar.';
|
$('hint-email').textContent = 'El email debe coincidir exactamente con la cuenta de Mailcow que el usuario usa para entrar.';
|
||||||
$('btn-delete').style.display = 'none'; // solo en modo edición
|
$('btn-delete').style.display = 'none'; // solo en modo edición
|
||||||
@@ -493,7 +482,6 @@ function openEdit(id){
|
|||||||
$('f-email').readOnly = false;
|
$('f-email').readOnly = false;
|
||||||
$('f-name').value = u.name || '';
|
$('f-name').value = u.name || '';
|
||||||
$('f-role-edit').value = u.role;
|
$('f-role-edit').value = u.role;
|
||||||
$('f-orden').value = u.orden;
|
|
||||||
$('f-activo').checked = u.activo === 1;
|
$('f-activo').checked = u.activo === 1;
|
||||||
$('hint-email').textContent = (u.email||'').startsWith('placeholder-')
|
$('hint-email').textContent = (u.email||'').startsWith('placeholder-')
|
||||||
? 'Reemplaza este email placeholder por el email real del abogado. Si el email real ya existe como otro usuario, mejor borra el placeholder con el botón de abajo.'
|
? 'Reemplaza este email placeholder por el email real del abogado. Si el email real ya existe como otro usuario, mejor borra el placeholder con el botón de abajo.'
|
||||||
@@ -544,7 +532,6 @@ async function saveUser(){
|
|||||||
email: $('f-email').value.trim().toLowerCase(),
|
email: $('f-email').value.trim().toLowerCase(),
|
||||||
name: $('f-name').value.trim(),
|
name: $('f-name').value.trim(),
|
||||||
role: $('f-role-edit').value,
|
role: $('f-role-edit').value,
|
||||||
orden: parseInt($('f-orden').value, 10) || 0,
|
|
||||||
activo: $('f-activo').checked ? 1 : 0,
|
activo: $('f-activo').checked ? 1 : 0,
|
||||||
};
|
};
|
||||||
if (!payload.email) { toast('Email requerido','error'); $('f-email').focus(); return; }
|
if (!payload.email) { toast('Email requerido','error'); $('f-email').focus(); return; }
|
||||||
|
|||||||
Reference in New Issue
Block a user