This commit is contained in:
123
.history/scripts/patch_20250808211820.sh
Normal file
123
.history/scripts/patch_20250808211820.sh
Normal file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# 1) Репозиторий: приводить user_id к uuid.UUID
|
||||
cat > services/profiles/src/app/repositories/profile_repository.py <<'PY'
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.profile import Profile
|
||||
from app.schemas.profile import ProfileCreate
|
||||
|
||||
class ProfileRepository:
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
@staticmethod
|
||||
def _to_uuid(v) -> uuid.UUID:
|
||||
if isinstance(v, uuid.UUID):
|
||||
return v
|
||||
return uuid.UUID(str(v))
|
||||
|
||||
def get_by_user(self, user_id) -> Optional[Profile]:
|
||||
uid = self._to_uuid(user_id)
|
||||
stmt = select(Profile).where(Profile.user_id == uid)
|
||||
return self.db.execute(stmt).scalar_one_or_none()
|
||||
|
||||
def create(self, user_id, obj: ProfileCreate) -> Profile:
|
||||
uid = self._to_uuid(user_id)
|
||||
p = Profile(
|
||||
user_id=uid,
|
||||
gender=obj.gender,
|
||||
city=obj.city,
|
||||
languages=obj.languages or [],
|
||||
interests=obj.interests or [],
|
||||
)
|
||||
self.db.add(p)
|
||||
self.db.commit()
|
||||
self.db.refresh(p)
|
||||
return p
|
||||
PY
|
||||
|
||||
# 2) Схемы: дефолты - пустые списки (чтобы не было None → JSONB)
|
||||
cat > services/profiles/src/app/schemas/profile.py <<'PY'
|
||||
from __future__ import annotations
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class ProfileBase(BaseModel):
|
||||
gender: str
|
||||
city: str
|
||||
languages: List[str] = Field(default_factory=list)
|
||||
interests: List[str] = Field(default_factory=list)
|
||||
|
||||
class ProfileCreate(ProfileBase):
|
||||
pass
|
||||
|
||||
class ProfileOut(ProfileBase):
|
||||
id: str
|
||||
user_id: str
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
PY
|
||||
|
||||
# 3) Роут: ловим ошибки явно → 400 вместо 500
|
||||
cat > services/profiles/src/app/api/routes/profiles.py <<'PY'
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.exc import IntegrityError, DataError
|
||||
|
||||
from app.db.deps import get_db
|
||||
from app.schemas.profile import ProfileCreate, ProfileOut
|
||||
from app.services.profile_service import ProfileService
|
||||
from app.core.security import get_current_user # возвращает объект с полями sub, email, role
|
||||
|
||||
router = APIRouter(prefix="/v1/profiles", tags=["profiles"])
|
||||
|
||||
@router.get("/me", response_model=ProfileOut)
|
||||
def get_my_profile(db: Session = Depends(get_db), user=Depends(get_current_user)):
|
||||
svc = ProfileService(db)
|
||||
p = svc.get_by_user(user.sub)
|
||||
if not p:
|
||||
# 404, если профиль отсутствует
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found")
|
||||
return p
|
||||
|
||||
@router.post("", response_model=ProfileOut, status_code=status.HTTP_201_CREATED)
|
||||
def create_profile(payload: ProfileCreate, db: Session = Depends(get_db), user=Depends(get_current_user)):
|
||||
svc = ProfileService(db)
|
||||
try:
|
||||
existing = svc.get_by_user(user.sub)
|
||||
if existing:
|
||||
return existing
|
||||
p = svc.create(user.sub, payload)
|
||||
return p
|
||||
except (IntegrityError, DataError, ValueError) as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=400, detail=f"Invalid data: {exc}")
|
||||
PY
|
||||
|
||||
# 4) Сервис — тонкая обёртка над репозиторием
|
||||
cat > services/profiles/src/app/services/profile_service.py <<'PY'
|
||||
from sqlalchemy.orm import Session
|
||||
from app.repositories.profile_repository import ProfileRepository
|
||||
from app.schemas.profile import ProfileCreate
|
||||
|
||||
class ProfileService:
|
||||
def __init__(self, db: Session):
|
||||
self.repo = ProfileRepository(db)
|
||||
|
||||
def get_by_user(self, user_id):
|
||||
return self.repo.get_by_user(user_id)
|
||||
|
||||
def create(self, user_id, obj: ProfileCreate):
|
||||
return self.repo.create(user_id, obj)
|
||||
PY
|
||||
|
||||
echo "[profiles] rebuilding..."
|
||||
docker compose build profiles
|
||||
docker compose restart profiles
|
||||
Reference in New Issue
Block a user