feat(logs): date filter + clear log endpoints
- API GET /api/logs now accepts from_ts / to_ts (unix epoch, half-open [from, to)) so callers can scope by arbitrary time range. - API DELETE /api/logs added. Same from_ts / to_ts semantics. No params = wipe everything and reset the AUTOINCREMENT counter. - Dashboard Logs page: date picker that scopes both the view and the delete button to the selected day in the user's local timezone. The clear button is red and confirms before deleting; label switches between "전체 로그 초기화" and "<날짜> 하루치 삭제".
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""접속 로그 조회."""
|
||||
"""접속 로그 조회 및 초기화."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
@@ -15,16 +15,26 @@ def list_logs(
|
||||
limit: int = Query(50, ge=1, le=500),
|
||||
offset: int = Query(0, ge=0),
|
||||
action: str | None = Query(None),
|
||||
from_ts: float | None = Query(None, description="unix epoch seconds, inclusive"),
|
||||
to_ts: float | None = Query(None, description="unix epoch seconds, exclusive"),
|
||||
) -> dict:
|
||||
if not LOG_DB.exists():
|
||||
return {"total": 0, "items": []}
|
||||
con = sqlite3.connect(LOG_DB)
|
||||
try:
|
||||
con.row_factory = sqlite3.Row
|
||||
where, params = "", []
|
||||
conds: list[str] = []
|
||||
params: list = []
|
||||
if action:
|
||||
where = "WHERE action = ?"
|
||||
conds.append("action = ?")
|
||||
params.append(action)
|
||||
if from_ts is not None:
|
||||
conds.append("ts >= ?")
|
||||
params.append(from_ts)
|
||||
if to_ts is not None:
|
||||
conds.append("ts < ?")
|
||||
params.append(to_ts)
|
||||
where = ("WHERE " + " AND ".join(conds)) if conds else ""
|
||||
total = con.execute(
|
||||
f"SELECT COUNT(*) FROM connections {where}", params
|
||||
).fetchone()[0]
|
||||
@@ -36,3 +46,40 @@ def list_logs(
|
||||
finally:
|
||||
con.close()
|
||||
return {"total": total, "items": [dict(r) for r in rows]}
|
||||
|
||||
|
||||
@router.delete("/logs")
|
||||
def clear_logs(
|
||||
from_ts: float | None = Query(None, description="ts >= from_ts 만 삭제"),
|
||||
to_ts: float | None = Query(None, description="ts < to_ts 만 삭제"),
|
||||
) -> dict:
|
||||
"""접속 로그를 삭제한다.
|
||||
|
||||
- from_ts/to_ts 둘 다 없으면 전체 삭제 (AUTOINCREMENT 카운터까지 리셋)
|
||||
- 둘 중 하나만 있으면 그 조건만 적용
|
||||
- 둘 다 있으면 [from_ts, to_ts) 범위 삭제 — 날짜 선택 삭제 용도
|
||||
"""
|
||||
if not LOG_DB.exists():
|
||||
return {"deleted": 0}
|
||||
con = sqlite3.connect(LOG_DB, timeout=5)
|
||||
try:
|
||||
conds: list[str] = []
|
||||
params: list = []
|
||||
if from_ts is not None:
|
||||
conds.append("ts >= ?")
|
||||
params.append(from_ts)
|
||||
if to_ts is not None:
|
||||
conds.append("ts < ?")
|
||||
params.append(to_ts)
|
||||
if conds:
|
||||
where = "WHERE " + " AND ".join(conds)
|
||||
cur = con.execute(f"DELETE FROM connections {where}", params)
|
||||
deleted = cur.rowcount
|
||||
else:
|
||||
cur = con.execute("DELETE FROM connections")
|
||||
deleted = cur.rowcount
|
||||
con.execute("DELETE FROM sqlite_sequence WHERE name='connections'")
|
||||
con.commit()
|
||||
finally:
|
||||
con.close()
|
||||
return {"deleted": deleted}
|
||||
|
||||
Reference in New Issue
Block a user