aee0f09db8
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
"""Invitation endpoints."""
|
|
from typing import Optional
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database import get_db
|
|
from app.dependencies import get_current_user, require_admin, require_manager
|
|
from app.models import User
|
|
from app.schemas import InvitationCreate, InvitationOut, AcceptInvitationRequest, UserOut
|
|
from app.services.invitation_service import InvitationService
|
|
|
|
router = APIRouter(prefix="/invitations", tags=["Invitations"])
|
|
|
|
|
|
@router.get("", response_model=list[InvitationOut])
|
|
async def list_invitations(
|
|
tenant_id: Optional[UUID] = Query(None),
|
|
pending_only: bool = Query(True),
|
|
skip: int = Query(0, ge=0),
|
|
limit: int = Query(100, ge=1, le=500),
|
|
current_user: User = Depends(require_manager),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
service = InvitationService(db)
|
|
effective_tenant = tenant_id
|
|
if not current_user.is_superuser and current_user.role.value == "manager":
|
|
effective_tenant = current_user.tenant_id
|
|
|
|
items, total = await service.list_invitations(
|
|
tenant_id=effective_tenant,
|
|
pending_only=pending_only,
|
|
skip=skip,
|
|
limit=limit,
|
|
)
|
|
return items
|
|
|
|
|
|
@router.post("", response_model=InvitationOut, status_code=201)
|
|
async def create_invitation(
|
|
data: InvitationCreate,
|
|
current_user: User = Depends(require_admin),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
service = InvitationService(db)
|
|
invitation = await service.create_invitation(data, invited_by=current_user)
|
|
return InvitationOut.model_validate(invitation)
|
|
|
|
|
|
@router.post("/accept", response_model=UserOut)
|
|
async def accept_invitation(
|
|
data: AcceptInvitationRequest,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
service = InvitationService(db)
|
|
user = await service.accept_invitation(data)
|
|
return UserOut.model_validate(user)
|
|
|
|
|
|
@router.get("/validate/{token}")
|
|
async def validate_invitation(
|
|
token: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
service = InvitationService(db)
|
|
invitation = await service.get_by_token(token)
|
|
if invitation is None:
|
|
return {"valid": False, "reason": "not_found"}
|
|
if invitation.accepted_at is not None:
|
|
return {"valid": False, "reason": "already_accepted"}
|
|
if invitation.expires_at < datetime.utcnow():
|
|
return {"valid": False, "reason": "expired"}
|
|
return {
|
|
"valid": True,
|
|
"email": invitation.email,
|
|
"role": invitation.role.value,
|
|
"expires_at": invitation.expires_at.isoformat(),
|
|
}
|
|
|
|
|
|
@router.delete("/{invitation_id}", status_code=204)
|
|
async def revoke_invitation(
|
|
invitation_id: UUID,
|
|
current_user: User = Depends(require_admin),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
service = InvitationService(db)
|
|
await service.revoke_invitation(invitation_id, actor=current_user)
|
|
return None
|
|
|
|
|
|
from datetime import datetime
|