Backend (FastAPI): - REST API: auth, plants, beds, plantings - CRUD layer with CRUDBase - Pydantic v2 schemas for all entities - Alembic migration: complete schema + all enums - Seed data: 28 global plants + 15 compatibilities Frontend (Vue 3 + PrimeVue): - Axios client with JWT interceptor + auto-refresh - Pinia stores: auth, beds, plants - Views: Login, Beds, BedDetail, PlantLibrary - Components: AppLayout, BedForm, PlantingForm, PlantForm Docker: - docker-compose.yml (production) - docker-compose.dev.yml (development with hot-reload) - Nginx config with SPA fallback + API proxy - Multi-stage frontend Dockerfile - .env.example, .gitignore Version: 1.0.0-alpha
49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
from uuid import UUID
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.security import get_password_hash, verify_password
|
|
from app.crud.base import CRUDBase
|
|
from app.models.user import User
|
|
from app.schemas.user import UserCreate, UserUpdate
|
|
|
|
|
|
class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]):
|
|
async def get_by_email(self, db: AsyncSession, *, email: str) -> User | None:
|
|
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, **extra) -> User:
|
|
data = obj_in.model_dump(exclude={"password"})
|
|
data["hashed_password"] = get_password_hash(obj_in.password)
|
|
data.update(extra)
|
|
db_obj = User(**data)
|
|
db.add(db_obj)
|
|
await db.flush()
|
|
await db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
async def authenticate(self, db: AsyncSession, *, email: str, password: str) -> User | None:
|
|
user = await self.get_by_email(db, email=email)
|
|
if not user:
|
|
return None
|
|
if not verify_password(password, user.hashed_password):
|
|
return None
|
|
return user
|
|
|
|
async def get_tenants(self, db: AsyncSession, *, user_id: UUID):
|
|
from sqlalchemy.orm import selectinload
|
|
from app.models.user import UserTenant
|
|
from app.models.tenant import Tenant
|
|
|
|
result = await db.execute(
|
|
select(Tenant)
|
|
.join(UserTenant, UserTenant.tenant_id == Tenant.id)
|
|
.where(UserTenant.user_id == user_id)
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
|
|
crud_user = CRUDUser(User)
|