several changes:
All checks were successful
Backend CI / unit-test (push) Successful in 34s

* api calls for auth

* exchange now bind to user
This commit is contained in:
2025-09-22 22:51:59 +02:00
parent 466e6ce653
commit 1750401278
14 changed files with 259 additions and 45 deletions

View File

@@ -1,16 +1,27 @@
from __future__ import annotations
import asyncio
import logging
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from fastapi import FastAPI, HTTPException, Request
from fastapi import FastAPI, HTTPException, Request, status
from fastapi.responses import JSONResponse
import settings
from trading_journal import db, service
from trading_journal.db import Database
from trading_journal.dto import UserCreate, UserRead
from trading_journal.dto import SessionsBase, SessionsCreate, UserCreate, UserLogin, UserRead
_db = db.create_database(settings.settings.database_url)
logging.basicConfig(
level=logging.WARNING,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # noqa: ARG001
@@ -40,13 +51,57 @@ async def register_user(request: Request, user_in: UserCreate) -> UserRead:
return service.register_user_service(db, user_in)
try:
return await asyncio.to_thread(sync_work)
user = await asyncio.to_thread(sync_work)
return JSONResponse(status_code=status.HTTP_201_CREATED, content=user.model_dump())
except service.UserAlreadyExistsError as e:
raise HTTPException(status_code=400, detail=str(e)) from e
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)) from e
except Exception as e:
raise HTTPException(status_code=500, detail="Internal server error" + str(e)) from e
logger.exception("Failed to register user: \n")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error") from e
@app.post(f"{settings.settings.api_base}/login")
async def login(request: Request, user_in: UserLogin) -> SessionsBase:
db_factory: Database = request.app.state.db_factory
def sync_work() -> tuple[SessionsCreate, str] | None:
with db_factory.get_session_ctx_manager() as db:
return service.authenticate_user_service(db, user_in)
try:
result = await asyncio.to_thread(sync_work)
if result is None:
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={"detail": "Invalid username or password, or user doesn't exist"},
)
session, token = result
session_return = SessionsBase(user_id=session.user_id)
response = JSONResponse(status_code=status.HTTP_200_OK, content=session_return.model_dump())
expires_sec = int((session.expires_at.replace(tzinfo=timezone.utc) - datetime.now(timezone.utc)).total_seconds())
response.set_cookie(
key="session_token",
value=token,
httponly=True,
secure=True,
samesite="lax",
max_age=expires_sec,
path="/",
)
except Exception as e:
logger.exception("Failed to login user: \n")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error") from e
else:
return response
# Exchange
# @app.post(f"{settings.settings.api_base}/exchanges")
# async def create_exchange(request: Request, name: str, notes: str | None) -> dict:
@app.get(f"{settings.settings.api_base}/trades")
async def get_trades() -> dict[str, str]:
return {"trades": []}
async def get_trades(request: Request) -> list:
db_factory: Database = request.app.state.db_factory
with db_factory.get_session_ctx_manager() as db:
return service.get_trades_service(db, request.state.user_id)