
Some checks failed
Deploy to Production, build images and push to Gitea Registry / build_and_push (pull_request) Failing after 1m24s
This commit adds new guidelines for FastAPI and Vue.js development, emphasizing best practices for component structure, API performance, and data handling. It also introduces caching mechanisms using Redis for improved performance and updates the API structure to streamline authentication and user management. Additionally, new endpoints for categories and time entries are implemented, enhancing the overall functionality of the application.
81 lines
3.7 KiB
Python
81 lines
3.7 KiB
Python
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.future import select
|
|
from sqlalchemy.orm import selectinload
|
|
from sqlalchemy.exc import SQLAlchemyError, IntegrityError, OperationalError
|
|
from typing import Optional
|
|
import logging
|
|
|
|
from app.models import User as UserModel, UserGroup as UserGroupModel
|
|
from app.schemas.user import UserCreate
|
|
from app.core.security import hash_password
|
|
from app.core.exceptions import (
|
|
UserCreationError,
|
|
EmailAlreadyRegisteredError,
|
|
DatabaseConnectionError,
|
|
DatabaseIntegrityError,
|
|
DatabaseQueryError,
|
|
DatabaseTransactionError,
|
|
UserOperationError
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
async def get_user_by_email(db: AsyncSession, email: str) -> Optional[UserModel]:
|
|
"""Fetches a user from the database by email, with common relationships."""
|
|
try:
|
|
stmt = (
|
|
select(UserModel)
|
|
.filter(UserModel.email == email)
|
|
.options(
|
|
selectinload(UserModel.group_associations).selectinload(UserGroupModel.group),
|
|
)
|
|
)
|
|
result = await db.execute(stmt)
|
|
return result.scalars().first()
|
|
except OperationalError as e:
|
|
logger.error(f"Database connection error while fetching user by email '{email}': {str(e)}", exc_info=True)
|
|
raise DatabaseConnectionError(f"Failed to connect to database: {str(e)}")
|
|
except SQLAlchemyError as e:
|
|
logger.error(f"Unexpected SQLAlchemy error while fetching user by email '{email}': {str(e)}", exc_info=True)
|
|
raise DatabaseQueryError(f"Failed to query user: {str(e)}")
|
|
|
|
async def create_user(db: AsyncSession, user_in: UserCreate, is_guest: bool = False) -> UserModel:
|
|
"""Creates a new user record in the database with common relationships loaded."""
|
|
try:
|
|
async with db.begin_nested() if db.in_transaction() else db.begin() as transaction:
|
|
_hashed_password = hash_password(user_in.password)
|
|
db_user = UserModel(
|
|
email=user_in.email,
|
|
hashed_password=_hashed_password,
|
|
name=user_in.name,
|
|
is_guest=is_guest
|
|
)
|
|
db.add(db_user)
|
|
await db.flush()
|
|
|
|
stmt = (
|
|
select(UserModel)
|
|
.where(UserModel.id == db_user.id)
|
|
.options(
|
|
selectinload(UserModel.group_associations).selectinload(UserGroupModel.group),
|
|
selectinload(UserModel.created_groups)
|
|
)
|
|
)
|
|
result = await db.execute(stmt)
|
|
loaded_user = result.scalar_one_or_none()
|
|
|
|
if loaded_user is None:
|
|
raise UserOperationError("Failed to load user after creation.")
|
|
|
|
return loaded_user
|
|
except IntegrityError as e:
|
|
logger.error(f"Database integrity error during user creation for email '{user_in.email}': {str(e)}", exc_info=True)
|
|
if "unique constraint" in str(e).lower() and ("users_email_key" in str(e).lower() or "ix_users_email" in str(e).lower()):
|
|
raise EmailAlreadyRegisteredError(email=user_in.email)
|
|
raise DatabaseIntegrityError(f"Failed to create user due to integrity issue: {str(e)}")
|
|
except OperationalError as e:
|
|
logger.error(f"Database connection error during user creation for email '{user_in.email}': {str(e)}", exc_info=True)
|
|
raise DatabaseConnectionError(f"Database connection error during user creation: {str(e)}")
|
|
except SQLAlchemyError as e:
|
|
logger.error(f"Unexpected SQLAlchemy error during user creation for email '{user_in.email}': {str(e)}", exc_info=True)
|
|
raise DatabaseTransactionError(f"Failed to create user due to other DB error: {str(e)}") |