feat: implement Logs endpoints for web dashboard

This commit is contained in:
2026-04-07 14:56:25 -04:00
parent 5b990743db
commit b46934db46
4 changed files with 242 additions and 1 deletions

View File

@@ -3,12 +3,16 @@ from contextlib import asynccontextmanager
from datetime import timedelta
from typing import Any, AsyncGenerator
from fastapi import FastAPI, HTTPException, status
import jwt
from fastapi import Depends, FastAPI, HTTPException, Query, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
from decnet.web.auth import (
ACCESS_TOKEN_EXPIRE_MINUTES,
ALGORITHM,
SECRET_KEY,
create_access_token,
get_password_hash,
verify_password,
@@ -50,6 +54,25 @@ app.add_middleware(
)
oauth2_scheme: OAuth2PasswordBearer = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
async def get_current_user(token: str = Depends(oauth2_scheme)) -> str:
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload: dict[str, Any] = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_uuid: str | None = payload.get("uuid")
if user_uuid is None:
raise credentials_exception
except jwt.PyJWTError:
raise credentials_exception
return user_uuid
class Token(BaseModel):
access_token: str
token_type: str
@@ -60,6 +83,13 @@ class LoginRequest(BaseModel):
password: str
class LogsResponse(BaseModel):
total: int
limit: int
offset: int
data: list[dict[str, Any]]
@app.post("/api/v1/auth/login", response_model=Token)
async def login(request: LoginRequest) -> dict[str, str]:
user: dict[str, Any] | None = await repo.get_user_by_username(request.username)
@@ -76,3 +106,20 @@ async def login(request: LoginRequest) -> dict[str, str]:
data={"uuid": user["uuid"]}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/api/v1/logs", response_model=LogsResponse)
async def get_logs(
limit: int = Query(50, ge=1, le=1000),
offset: int = Query(0, ge=0),
search: str | None = None,
current_user: str = Depends(get_current_user)
) -> dict[str, Any]:
logs: list[dict[str, Any]] = await repo.get_logs(limit=limit, offset=offset, search=search)
total: int = await repo.get_total_logs(search=search)
return {
"total": total,
"limit": limit,
"offset": offset,
"data": logs
}