Implement async db access in admin

This commit is contained in:
2025-05-19 09:22:02 +02:00
parent fc0c3fb950
commit 5865cc450f
8 changed files with 85 additions and 7 deletions

View File

@ -1,10 +1,11 @@
"""Frontend dependencies."""
from dataclasses import dataclass
from collections.abc import Callable, Awaitable
from collections.abc import AsyncGenerator, Callable, Awaitable
from typing import Self
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from jinja2_fragments.fastapi import Jinja2Blocks
from fastapi import Request
@ -14,6 +15,7 @@ from sshecret_admin.auth.models import User
UserTokenDep = Callable[[Request, Session], Awaitable[User]]
UserLoginDep = Callable[[Request, Session], Awaitable[bool]]
AsyncSessionDep = Callable[[], AsyncGenerator[AsyncSession, None]]
@dataclass
@ -25,6 +27,7 @@ class FrontendDependencies(BaseDependencies):
get_user_from_access_token: UserTokenDep
get_user_from_refresh_token: UserTokenDep
get_login_status: UserLoginDep
get_async_session: AsyncSessionDep
@classmethod
def create(
@ -35,6 +38,7 @@ class FrontendDependencies(BaseDependencies):
get_user_from_access_token: UserTokenDep,
get_user_from_refresh_token: UserTokenDep,
get_login_status: UserLoginDep,
get_async_session: AsyncSessionDep
) -> Self:
"""Create from base dependencies."""
return cls(
@ -45,4 +49,5 @@ class FrontendDependencies(BaseDependencies):
get_user_from_access_token=get_user_from_access_token,
get_user_from_refresh_token=get_user_from_refresh_token,
get_login_status=get_login_status,
get_async_session=get_async_session,
)

View File

@ -19,6 +19,7 @@ from starlette.datastructures import URL
from sshecret_admin.auth import PasswordDB, User, decode_token
from sshecret_admin.core.dependencies import BaseDependencies
from sshecret_admin.services.admin_backend import AdminBackend
from sshecret_admin.core.db import DatabaseSessionManager
from .dependencies import FrontendDependencies
from .exceptions import RedirectException
@ -47,7 +48,9 @@ def create_router(dependencies: BaseDependencies) -> APIRouter:
session: Annotated[Session, Depends(dependencies.get_db_session)]
):
"""Get admin backend API."""
password_db = session.scalars(select(PasswordDB).where(PasswordDB.id == 1)).first()
password_db = session.scalars(
select(PasswordDB).where(PasswordDB.id == 1)
).first()
if not password_db:
raise HTTPException(
500, detail="Error: The password manager has not yet been set up."
@ -116,6 +119,12 @@ def create_router(dependencies: BaseDependencies) -> APIRouter:
return False
return True
async def get_async_session():
"""Get async session."""
sessionmanager = DatabaseSessionManager(dependencies.settings.async_db_url)
async with sessionmanager.session() as session:
yield session
view_dependencies = FrontendDependencies.create(
dependencies,
get_admin_backend,
@ -123,6 +132,7 @@ def create_router(dependencies: BaseDependencies) -> APIRouter:
get_user_from_access_token,
get_user_from_refresh_token,
get_login_status,
get_async_session,
)
app.include_router(audit.create_router(view_dependencies))

View File

@ -8,13 +8,13 @@ from fastapi import APIRouter, Depends, Query, Request, Response, status
from fastapi.responses import RedirectResponse
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from sshecret_admin.services import AdminBackend
from starlette.datastructures import URL
from sshecret_admin.auth import (
User,
authenticate_user,
authenticate_user_async,
create_access_token,
create_refresh_token,
)
@ -80,7 +80,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
async def login_user(
request: Request,
response: Response,
session: Annotated[Session, Depends(dependencies.get_db_session)],
session: Annotated[AsyncSession, Depends(dependencies.get_async_session)],
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
next: Annotated[str, Query()] = "/dashboard",
@ -100,7 +100,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter:
},
)
user = authenticate_user(session, form_data.username, form_data.password)
user = await authenticate_user_async(session, form_data.username, form_data.password)
login_failed = RedirectException(
to=URL("/login").include_query_params(
error_title="Login Error", error_message="Invalid username or password"