95 lines
4.5 KiB
Python
95 lines
4.5 KiB
Python
from datetime import datetime
|
||
from typing import List, Optional
|
||
from sqlalchemy import select
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from fastapi import HTTPException, status
|
||
|
||
from app.domain.entities.internships import InternshipCreate, InternshipUpdate
|
||
from app.domain.models import Internship, User
|
||
|
||
|
||
class InternshipsService:
|
||
def __init__(self, db: AsyncSession):
|
||
self.db = db
|
||
|
||
async def create_internship(self, data: InternshipCreate, user: User) -> Internship:
|
||
"""
|
||
Создает новую стажировку, автоматически привязывая её к компании юзера.
|
||
"""
|
||
# 1. Проверяем, что у пользователя заполнена компания
|
||
if not user.company_id:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_403_FORBIDDEN,
|
||
detail="Пользователь не привязан к профилю компании"
|
||
)
|
||
|
||
# 2. Превращаем Pydantic модель в словарь
|
||
internship_data = data.model_dump()
|
||
|
||
# 3. Автозаполнение технических полей, которые фронт не должен присылать
|
||
internship_data['company_id'] = user.company_id
|
||
internship_data['published_at'] = datetime.now()
|
||
|
||
# Устанавливаем статус модерации "Новая" (обычно ID=1)
|
||
if internship_data.get('moderation_status_id') is None:
|
||
internship_data['moderation_status_id'] = 1
|
||
|
||
# Заглушка для location_id, если логика локаций еще не реализована полностью
|
||
if internship_data.get('location_id') is None:
|
||
internship_data['location_id'] = 1
|
||
|
||
# 4. Создаем объект модели SQLAlchemy
|
||
new_internship = Internship(**internship_data)
|
||
|
||
# 5. Сохраняем в базу
|
||
self.db.add(new_internship)
|
||
try:
|
||
await self.db.commit()
|
||
await self.db.refresh(new_internship)
|
||
except Exception as e:
|
||
await self.db.rollback()
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail=f"Ошибка при сохранении в базу данных: {str(e)}"
|
||
)
|
||
|
||
# Подгружаем связанные данные для InternshipRead (если нужно в ответе)
|
||
# Это предотвратит ошибки Lazy Loading при возврате InternshipRead
|
||
query = select(Internship).where(Internship.id == new_internship.id)
|
||
# Если в моделях прописаны отношения, можно добавить .options(selectinload(...))
|
||
|
||
return new_internship
|
||
|
||
async def get_internships(self, limit: int = 10, offset: int = 0) -> List[Internship]:
|
||
"""Получение списка всех активных стажировок."""
|
||
query = select(Internship).where(Internship.is_active == True).limit(limit).offset(offset)
|
||
result = await self.db.execute(query)
|
||
return result.scalars().all()
|
||
|
||
async def get_internship_by_id(self, internship_id: int) -> Optional[Internship]:
|
||
"""Получение конкретной стажировки по ID."""
|
||
query = select(Internship).where(Internship.id == internship_id)
|
||
result = await self.db.execute(query)
|
||
internship = result.scalar_one_or_none()
|
||
|
||
if not internship:
|
||
raise HTTPException(status_code=404, detail="Стажировка не найдена")
|
||
return internship
|
||
|
||
async def update_internship(self, internship_id: int, data: InternshipUpdate, user: User) -> Internship:
|
||
"""Обновление данных стажировки (только для владельца компании)."""
|
||
internship = await self.get_internship_by_id(internship_id)
|
||
|
||
if internship.company_id != user.company_id:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_403_FORBIDDEN,
|
||
detail="Вы не можете редактировать чужую стажировку"
|
||
)
|
||
|
||
update_data = data.model_dump(exclude_unset=True)
|
||
for key, value in update_data.items():
|
||
setattr(internship, key, value)
|
||
|
||
await self.db.commit()
|
||
await self.db.refresh(internship)
|
||
return internship |