mitlist/be/app/crud/user.py
mohamad f49e15c05c
Some checks failed
Deploy to Production, build images and push to Gitea Registry / build_and_push (pull_request) Failing after 1m24s
feat: Introduce FastAPI and Vue.js guidelines, enhance API structure, and add caching support
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.
2025-06-09 21:02:51 +02:00

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)}")