This commit is contained in:
2025-12-13 14:39:50 +03:00
commit b666cdcb95
79 changed files with 3081 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
from app.crud.user import user, CRUDUser
from app.crud.schedule import schedule, CRUDSchedule
from app.crud.task import task, CRUDTask
__all__ = [
"user",
"CRUDUser",
"schedule",
"CRUDSchedule",
"task",
"CRUDTask",
]

View File

@@ -0,0 +1,66 @@
from typing import Generic, TypeVar, Type, Optional, List, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, delete
from sqlalchemy.orm import selectinload
from app.db.base import BaseModel
ModelType = TypeVar("ModelType", bound=BaseModel)
class CRUDBase(Generic[ModelType]):
def __init__(self, model: Type[ModelType]):
self.model = model
async def get(self, db: AsyncSession, id: str) -> Optional[ModelType]:
"""Получить объект по ID"""
result = await db.execute(select(self.model).where(self.model.id == id))
return result.scalar_one_or_none()
async def get_multi(
self,
db: AsyncSession,
skip: int = 0,
limit: int = 100,
filters: Optional[Dict[str, Any]] = None
) -> List[ModelType]:
"""Получить список объектов"""
query = select(self.model)
if filters:
for key, value in filters.items():
if hasattr(self.model, key):
query = query.where(getattr(self.model, key) == value)
query = query.offset(skip).limit(limit)
result = await db.execute(query)
return result.scalars().all()
async def create(self, db: AsyncSession, obj_in: Dict[str, Any]) -> ModelType:
"""Создать объект"""
db_obj = self.model(**obj_in)
db.add(db_obj)
await db.commit()
await db.refresh(db_obj)
return db_obj
async def update(
self,
db: AsyncSession,
db_obj: ModelType,
obj_in: Dict[str, Any]
) -> ModelType:
"""Обновить объект"""
for field, value in obj_in.items():
if hasattr(db_obj, field) and value is not None:
setattr(db_obj, field, value)
await db.commit()
await db.refresh(db_obj)
return db_obj
async def delete(self, db: AsyncSession, id: str) -> bool:
"""Удалить объект"""
result = await db.execute(delete(self.model).where(self.model.id == id))
await db.commit()
return result.rowcount > 0

View File

@@ -0,0 +1,55 @@
from typing import List, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from datetime import date
from app.models.schedule import Schedule
from app.schemas.schedule import ScheduleCreate, ScheduleUpdate
from app.crud.base import CRUDBase
class CRUDSchedule(CRUDBase[Schedule]):
async def get_by_user(
self,
db: AsyncSession,
user_id: str,
skip: int = 0,
limit: int = 100
) -> List[Schedule]:
"""Получить расписания пользователя"""
result = await db.execute(
select(Schedule)
.where(Schedule.user_id == user_id)
.options(selectinload(Schedule.tasks))
.offset(skip)
.limit(limit)
.order_by(Schedule.date.desc())
)
return result.scalars().all()
async def get_by_date(
self,
db: AsyncSession,
user_id: str,
schedule_date: date
) -> Optional[Schedule]:
"""Получить расписание на конкретную дату"""
result = await db.execute(
select(Schedule)
.where(Schedule.user_id == user_id, Schedule.date == schedule_date)
.options(selectinload(Schedule.tasks))
)
return result.scalar_one_or_none()
async def get_with_tasks(self, db: AsyncSession, id: str) -> Optional[Schedule]:
"""Получить расписание с задачами"""
result = await db.execute(
select(Schedule)
.where(Schedule.id == id)
.options(selectinload(Schedule.tasks))
)
return result.scalar_one_or_none()
schedule = CRUDSchedule(Schedule)

View File

@@ -0,0 +1,39 @@
from typing import List, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.task import Task
from app.schemas.task import TaskCreate, TaskUpdate
from app.crud.base import CRUDBase
class CRUDTask(CRUDBase[Task]):
async def get_by_schedule(
self,
db: AsyncSession,
schedule_id: str
) -> List[Task]:
"""Получить все задачи расписания"""
result = await db.execute(
select(Task)
.where(Task.schedule_id == schedule_id)
.order_by(Task.order)
)
return result.scalars().all()
async def update_completion(
self,
db: AsyncSession,
task_id: str,
completed: bool
) -> Optional[Task]:
"""Обновить статус выполнения задачи"""
task = await self.get(db, task_id)
if task:
task.completed = completed
await db.commit()
await db.refresh(task)
return task
task = CRUDTask(Task)

View File

@@ -0,0 +1,51 @@
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.user import User
from app.schemas.user import UserCreate, UserUpdate
from app.crud.base import CRUDBase
class CRUDUser(CRUDBase[User]):
async def get_by_email(self, db: AsyncSession, email: str) -> Optional[User]:
"""Получить пользователя по email"""
result = await db.execute(select(User).where(User.email == email))
return result.scalar_one_or_none()
async def create(self, db: AsyncSession, obj_in: UserCreate, hashed_password: str) -> User:
"""Создать пользователя"""
db_obj = User(
email=obj_in.email,
hashed_password=hashed_password,
role=obj_in.role,
full_name=obj_in.full_name
)
db.add(db_obj)
await db.commit()
await db.refresh(db_obj)
return db_obj
async def update(
self,
db: AsyncSession,
db_obj: User,
obj_in: UserUpdate
) -> User:
"""Обновить пользователя"""
update_data = obj_in.model_dump(exclude_unset=True)
if "password" in update_data:
# Пароль нужно хешировать отдельно
from app.core.security import get_password_hash
update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
for field, value in update_data.items():
setattr(db_obj, field, value)
await db.commit()
await db.refresh(db_obj)
return db_obj
user = CRUDUser(User)