from typing import List, Optional from bson import ObjectId from motor.motor_asyncio import AsyncIOMotorClient from models.Project import Project class ProjectRepo: def __init__(self, client: AsyncIOMotorClient, db_name="bot_db"): self.collection = client[db_name]["projects"] async def create_project(self, project: Project) -> str: res = await self.collection.insert_one(project.model_dump()) return str(res.inserted_id) async def get_project(self, project_id: str) -> Optional[Project]: if not ObjectId.is_valid(project_id): return None res = await self.collection.find_one({"_id": ObjectId(project_id)}) if res: res["id"] = str(res.pop("_id")) return Project(**res) return None async def get_projects_by_user(self, user_id: str) -> List[Project]: # Find projects where user is owner OR in members filter = { "$or": [ {"owner_id": user_id}, {"members": user_id} ], "is_deleted": False } cursor = self.collection.find(filter).sort("created_at", -1) projects = [] async for doc in cursor: doc["id"] = str(doc.pop("_id")) projects.append(Project(**doc)) return projects async def add_member(self, project_id: str, user_id: str) -> bool: res = await self.collection.update_one( {"_id": ObjectId(project_id)}, {"$addToSet": {"members": user_id}} ) return res.modified_count > 0 async def remove_member(self, project_id: str, user_id: str) -> bool: res = await self.collection.update_one( {"_id": ObjectId(project_id)}, {"$pull": {"members": user_id}} ) return res.modified_count > 0 async def update_project(self, project_id: str, updates: dict) -> bool: res = await self.collection.update_one( {"_id": ObjectId(project_id)}, {"$set": updates} ) return res.modified_count > 0 async def delete_project(self, project_id: str) -> bool: res = await self.collection.update_one({"_id": ObjectId(project_id)}, {"$set": {"is_deleted": True}}) return res.modified_count > 0