import uuid from typing import List from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.core.database import get_db from app.models import User, Space from app.schemas.space import SpaceCreate, SpaceUpdate, SpaceResponse, SpaceWithOwner from app.middleware.auth import get_current_user, check_space_access, check_space_edit_access router = APIRouter(prefix="/api/spaces", tags=["spaces"]) @router.get("", response_model=List[SpaceWithOwner]) async def list_spaces( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ List all active spaces the user can access. """ spaces = db.query(Space).filter(Space.is_active == True).all() # Filter by access (currently all users can see all spaces) accessible_spaces = [s for s in spaces if check_space_access(current_user, s)] result = [] for space in accessible_spaces: result.append(SpaceWithOwner( id=space.id, name=space.name, description=space.description, owner_id=space.owner_id, is_active=space.is_active, created_at=space.created_at, updated_at=space.updated_at, owner_name=space.owner.name if space.owner else None, )) return result @router.post("", response_model=SpaceResponse, status_code=status.HTTP_201_CREATED) async def create_space( space_data: SpaceCreate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Create a new space. """ space = Space( id=str(uuid.uuid4()), name=space_data.name, description=space_data.description, owner_id=current_user.id, is_active=True, ) db.add(space) db.commit() db.refresh(space) return space @router.get("/{space_id}", response_model=SpaceWithOwner) async def get_space( space_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Get a space by ID. """ space = db.query(Space).filter(Space.id == space_id).first() if not space: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Space not found", ) if not check_space_access(current_user, space): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied", ) return SpaceWithOwner( id=space.id, name=space.name, description=space.description, owner_id=space.owner_id, is_active=space.is_active, created_at=space.created_at, updated_at=space.updated_at, owner_name=space.owner.name if space.owner else None, ) @router.patch("/{space_id}", response_model=SpaceResponse) async def update_space( space_id: str, space_data: SpaceUpdate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Update a space. """ space = db.query(Space).filter(Space.id == space_id).first() if not space: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Space not found", ) if not check_space_edit_access(current_user, space): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only space owner can update", ) # Update fields update_data = space_data.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(space, field, value) db.commit() db.refresh(space) return space @router.delete("/{space_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_space( space_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Soft delete a space (set is_active = False). """ space = db.query(Space).filter(Space.id == space_id).first() if not space: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Space not found", ) if not check_space_edit_access(current_user, space): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only space owner can delete", ) # Soft delete space.is_active = False db.commit() return None