from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel from api.dependency import get_dao from api.endpoints.auth import get_current_user from models.Project import Project from repos.dao import DAO router = APIRouter(prefix="/api/projects", tags=["Projects"]) class ProjectCreate(BaseModel): name: str description: Optional[str] = None class ProjectResponse(BaseModel): id: str name: str description: Optional[str] = None owner_id: str members: List[str] is_owner: bool = False @router.post("", response_model=ProjectResponse) async def create_project( project_data: ProjectCreate, dao: DAO = Depends(get_dao), current_user: dict = Depends(get_current_user) ): user_id = str(current_user["_id"]) new_project = Project( name=project_data.name, description=project_data.description, owner_id=user_id, members=[user_id] ) project_id = await dao.projects.create_project(new_project) # Add project to user's project list # Assuming user_repo has a method to add project or we do it directly? # UserRepo doesn't have add_project method yet. # But since UserRepo is just a wrapper around collection, lets add it here or update UserRepo later? # Better to update UserRepo. For now, let's just return success. # But user needs to see it in list. # Update user in DB await dao.users.collection.update_one( {"_id": current_user["_id"]}, {"$addToSet": {"project_ids": project_id}} ) return ProjectResponse( id=project_id, name=new_project.name, description=new_project.description, owner_id=new_project.owner_id, members=new_project.members, is_owner=True ) @router.get("", response_model=List[ProjectResponse]) async def get_my_projects( dao: DAO = Depends(get_dao), current_user: dict = Depends(get_current_user) ): user_id = str(current_user["_id"]) projects = await dao.projects.get_projects_by_user(user_id) responses = [] for p in projects: responses.append(ProjectResponse( id=p.id, name=p.name, description=p.description, owner_id=p.owner_id, members=p.members, is_owner=(p.owner_id == user_id) )) return responses class MemberAdd(BaseModel): username: str @router.post("/{project_id}/members", dependencies=[Depends(get_current_user)]) async def add_member( project_id: str, member_data: MemberAdd, dao: DAO = Depends(get_dao), current_user: dict = Depends(get_current_user) ): user_id = str(current_user["_id"]) project = await dao.projects.get_project(project_id) if not project: raise HTTPException(status_code=404, detail="Project not found") if project.owner_id != user_id: raise HTTPException(status_code=403, detail="Only owner can add members") target_user = await dao.users.get_user_by_username(member_data.username) if not target_user: raise HTTPException(status_code=404, detail="User not found") target_user_id = str(target_user["_id"]) if target_user_id in project.members: return {"message": "User already in project"} await dao.projects.add_member(project_id, target_user_id) # Update target user's project list await dao.users.collection.update_one( {"_id": target_user["_id"]}, {"$addToSet": {"project_ids": project_id}} ) return {"message": "Member added"} @router.post("/{project_id}/join", dependencies=[Depends(get_current_user)]) async def join_project( project_id: str, dao: DAO = Depends(get_dao), current_user: dict = Depends(get_current_user) ): # Retrieve project to verify it exists project = await dao.projects.get_project(project_id) if not project: raise HTTPException(status_code=404, detail="Project not found") user_id = str(current_user["_id"]) # Check if user is ALREADY in project if user_id in project.members: return {"message": "Already a member"} # Add member await dao.projects.add_member(project_id, user_id) # Update user's project list await dao.users.collection.update_one( {"_id": current_user["_id"]}, {"$addToSet": {"project_ids": project_id}} ) return {"message": "Joined project"} @router.delete("/{project_id}", dependencies=[Depends(get_current_user)] ) async def delete_project( project_id: str, dao: DAO = Depends(get_dao), current_user: dict = Depends(get_current_user) ): user_id = str(current_user["_id"]) project = await dao.projects.get_project(project_id) if not project: raise HTTPException(status_code=404, detail="Project not found") if project.owner_id != user_id: raise HTTPException(status_code=403, detail="Only owner can delete project") await dao.projects.delete_project(project_id) # Remove project from user's project list await dao.users.collection.update_one( {"_id": current_user["_id"]}, {"$pull": {"project_ids": project_id}} ) return {"message": "Project deleted"}