PMFlow/backend/app/api/workspaces_api.py

117 lines
3.2 KiB
Python

"""Workspace API.
Product language: workspace/space. Database compatibility: tenants.
"""
from __future__ import annotations
from pydantic import BaseModel, Field
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from ..core.database import get_db
from ..core.response import success_response
from ..dependencies import get_current_user, get_optional_current_user
from ..models import User
from ..services.workspace_service import (
accept_invitation,
create_invitation,
create_team_workspace,
leave_workspace,
list_user_workspaces,
switch_workspace,
)
router = APIRouter(prefix="/workspaces", tags=["workspaces"])
class TeamWorkspaceCreateRequest(BaseModel):
name: str = Field(min_length=1, max_length=120)
class WorkspaceSwitchRequest(BaseModel):
tenant_id: int
class WorkspaceInvitationCreateRequest(BaseModel):
phone_country_code: str = "+86"
phone_number: str
email: str | None = None
role: str = "BUILDER"
project_ids: list[int] = Field(default_factory=list)
class WorkspaceInvitationNewUserRequest(BaseModel):
username: str
password: str
name: str
email: str
class WorkspaceInvitationAcceptRequest(BaseModel):
token: str
user: WorkspaceInvitationNewUserRequest | None = None
@router.get("/me")
async def get_my_workspaces(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
return success_response(await list_user_workspaces(db, user=current_user))
@router.post("/teams")
async def create_team(
body: TeamWorkspaceCreateRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
return success_response(await create_team_workspace(db, current_user=current_user, name=body.name))
@router.post("/switch")
async def switch_current_workspace(
body: WorkspaceSwitchRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
return success_response(await switch_workspace(db, current_user=current_user, tenant_id=body.tenant_id))
@router.post("/invitations")
async def invite_member(
body: WorkspaceInvitationCreateRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
return success_response(
await create_invitation(
db,
current_user=current_user,
email=body.email,
phone_country_code=body.phone_country_code,
phone_number=body.phone_number,
role=body.role,
project_ids=body.project_ids,
)
)
@router.post("/invitations/accept")
async def accept_member_invitation(
body: WorkspaceInvitationAcceptRequest,
current_user: User | None = Depends(get_optional_current_user),
db: AsyncSession = Depends(get_db),
):
return success_response(await accept_invitation(db, token=body.token, current_user=current_user, new_user=body.user))
@router.post("/{tenant_id}/leave")
async def leave_current_workspace(
tenant_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
return success_response(await leave_workspace(db, current_user=current_user, tenant_id=tenant_id))