security-history: acción y estado web multiidioma
La lib devolvía la acción ("Token de seguridad solicitado") y el estado del login
web ("Conexión exitosa"/"Contraseña incorrecta") en español. Ahora devuelve claves
(actionKey='tokenRequested'; statusKey='success'/'wrongPassword'/'other' + statusRaw)
y la página las traduce (History.security.action/webStatus). El coloreado rojo pasa
a depender de statusKey==='wrongPassword'. Verificado con datos reales.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -106,7 +106,7 @@ export default async function SecurityHistoryPage({ params }: { params: Promise<
|
|||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<UserCell label={a.user} bnet={bnetEmail} />
|
<UserCell label={a.user} bnet={bnetEmail} />
|
||||||
<td>
|
<td>
|
||||||
<span>{a.action}</span>
|
<span>{t(`security.action.${a.actionKey}`)}</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="long-td">
|
<td className="long-td">
|
||||||
<span>{a.ip}</span>
|
<span>{a.ip}</span>
|
||||||
@@ -190,7 +190,9 @@ export default async function SecurityHistoryPage({ params }: { params: Promise<
|
|||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<UserCell label={c.user} bnet={bnetEmail} />
|
<UserCell label={c.user} bnet={bnetEmail} />
|
||||||
<td>
|
<td>
|
||||||
<span className={c.status === 'Conexión exitosa' ? '' : 'red-info2'}>{c.status}</span>
|
<span className={c.statusKey === 'wrongPassword' ? 'red-info2' : ''}>
|
||||||
|
{c.statusKey === 'other' ? c.statusRaw : t(`security.webStatus.${c.statusKey}`)}
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="long-td">
|
<td className="long-td">
|
||||||
<span>{c.ip}</span>
|
<span>{c.ip}</span>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { db, DB } from './db'
|
|||||||
|
|
||||||
export interface ActivityEntry {
|
export interface ActivityEntry {
|
||||||
user: string
|
user: string
|
||||||
action: string
|
actionKey: string // clave de acción traducible (p.ej. 'tokenRequested')
|
||||||
ip: string
|
ip: string
|
||||||
date: Date
|
date: Date
|
||||||
}
|
}
|
||||||
@@ -13,17 +13,18 @@ export interface RealmConnection {
|
|||||||
}
|
}
|
||||||
export interface WebConnection {
|
export interface WebConnection {
|
||||||
user: string
|
user: string
|
||||||
status: string
|
statusKey: 'success' | 'wrongPassword' | 'other'
|
||||||
|
statusRaw: string // texto original (para el caso 'other')
|
||||||
ip: string
|
ip: string
|
||||||
date: Date
|
date: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Traduce el estado guardado del intento de login web a la etiqueta del diseño. */
|
/** Clasifica el estado guardado del intento de login web en una clave traducible. */
|
||||||
function webStatusLabel(raw: string): string {
|
function webStatusKey(raw: string): 'success' | 'wrongPassword' | 'other' {
|
||||||
const s = (raw || '').toLowerCase()
|
const s = (raw || '').toLowerCase()
|
||||||
if (s.includes('exito') || s.includes('éxito') || s.includes('success')) return 'Conexión exitosa'
|
if (s.includes('exito') || s.includes('éxito') || s.includes('success')) return 'success'
|
||||||
if (s.includes('fracaso') || s.includes('fail') || s.includes('incorrect')) return 'Contraseña incorrecta'
|
if (s.includes('fracaso') || s.includes('fail') || s.includes('incorrect')) return 'wrongPassword'
|
||||||
return raw || '—'
|
return 'other'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +53,7 @@ export async function getSecurityHistory(
|
|||||||
[accountId, limit],
|
[accountId, limit],
|
||||||
)
|
)
|
||||||
for (const r of rows) {
|
for (const r of rows) {
|
||||||
activity.push({ user: displayUser, action: 'Token de seguridad solicitado', ip: String(r.ip_address || '—'), date: new Date(r.created_at) })
|
activity.push({ user: displayUser, actionKey: 'tokenRequested', ip: String(r.ip_address || '—'), date: new Date(r.created_at) })
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
/* tabla ausente */
|
/* tabla ausente */
|
||||||
@@ -93,7 +94,8 @@ export async function getSecurityHistory(
|
|||||||
[email, limit],
|
[email, limit],
|
||||||
)
|
)
|
||||||
for (const r of rows) {
|
for (const r of rows) {
|
||||||
web.push({ user: displayUser, status: webStatusLabel(String(r.status)), ip: String(r.ip_address || '—'), date: new Date(r.timestamp) })
|
const raw = String(r.status || '')
|
||||||
|
web.push({ user: displayUser, statusKey: webStatusKey(raw), statusRaw: raw, ip: String(r.ip_address || '—'), date: new Date(r.timestamp) })
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
/* tabla ausente */
|
/* tabla ausente */
|
||||||
|
|||||||
@@ -1058,7 +1058,14 @@
|
|||||||
"thUser": "User",
|
"thUser": "User",
|
||||||
"thAction": "Action",
|
"thAction": "Action",
|
||||||
"thStatus": "Status",
|
"thStatus": "Status",
|
||||||
"thDate": "Date"
|
"thDate": "Date",
|
||||||
|
"action": {
|
||||||
|
"tokenRequested": "Security token requested"
|
||||||
|
},
|
||||||
|
"webStatus": {
|
||||||
|
"success": "Successful login",
|
||||||
|
"wrongPassword": "Wrong password"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Legal": {
|
"Legal": {
|
||||||
|
|||||||
@@ -1058,7 +1058,14 @@
|
|||||||
"thUser": "Usuario",
|
"thUser": "Usuario",
|
||||||
"thAction": "Acción",
|
"thAction": "Acción",
|
||||||
"thStatus": "Estado",
|
"thStatus": "Estado",
|
||||||
"thDate": "Fecha"
|
"thDate": "Fecha",
|
||||||
|
"action": {
|
||||||
|
"tokenRequested": "Token de seguridad solicitado"
|
||||||
|
},
|
||||||
|
"webStatus": {
|
||||||
|
"success": "Conexión exitosa",
|
||||||
|
"wrongPassword": "Contraseña incorrecta"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Legal": {
|
"Legal": {
|
||||||
|
|||||||
Reference in New Issue
Block a user