76 lines
2.0 KiB
TypeScript
76 lines
2.0 KiB
TypeScript
import { getSession, getSessionIdFromCookie, deleteSessionCookie, SESSION_TIMEOUT_MINUTES } from '../../utils/session'
|
|
|
|
/**
|
|
* 본인 로그인 이력 조회
|
|
* GET /api/auth/login-history
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
const sessionId = getSessionIdFromCookie(event)
|
|
|
|
if (!sessionId) {
|
|
throw createError({ statusCode: 401, message: '로그인이 필요합니다.' })
|
|
}
|
|
|
|
const session = await getSession(sessionId)
|
|
|
|
if (!session) {
|
|
deleteSessionCookie(event)
|
|
throw createError({ statusCode: 401, message: '세션이 만료되었습니다.' })
|
|
}
|
|
|
|
// 현재 활성 세션 ID 목록 조회
|
|
const activeSessions = await query<any>(`
|
|
SELECT login_history_id FROM wr_session
|
|
WHERE employee_id = $1 AND expires_at > NOW()
|
|
`, [session.employeeId])
|
|
|
|
const activeHistoryIds = new Set(activeSessions.map(s => s.login_history_id))
|
|
|
|
// 로그인 이력 조회
|
|
const history = await query<any>(`
|
|
SELECT
|
|
history_id,
|
|
login_at,
|
|
login_ip,
|
|
logout_at,
|
|
logout_ip,
|
|
last_active_at
|
|
FROM wr_login_history
|
|
WHERE employee_id = $1
|
|
ORDER BY login_at DESC
|
|
LIMIT 50
|
|
`, [session.employeeId])
|
|
|
|
const SESSION_TIMEOUT_MS = SESSION_TIMEOUT_MINUTES * 60 * 1000
|
|
const now = Date.now()
|
|
|
|
return {
|
|
history: history.map(h => {
|
|
const isCurrentSession = h.history_id === session.loginHistoryId
|
|
const isActiveSession = activeHistoryIds.has(h.history_id)
|
|
|
|
// 세션 상태 판단
|
|
let sessionStatus: 'active' | 'logout' | 'expired'
|
|
if (h.logout_at) {
|
|
sessionStatus = 'logout'
|
|
} else if (isActiveSession) {
|
|
sessionStatus = 'active'
|
|
} else {
|
|
// 활성 세션에 없으면 만료
|
|
sessionStatus = 'expired'
|
|
}
|
|
|
|
return {
|
|
historyId: h.history_id,
|
|
loginAt: h.login_at,
|
|
loginIp: h.login_ip,
|
|
logoutAt: h.logout_at,
|
|
logoutIp: h.logout_ip,
|
|
lastActiveAt: h.last_active_at,
|
|
isCurrentSession,
|
|
sessionStatus
|
|
}
|
|
})
|
|
}
|
|
})
|