from bson import ObjectId from app.db import get_db from datetime import datetime class Persona: @staticmethod async def create(persona_data, user_id=None): db = await get_db() # Add metadata persona_data["created_at"] = datetime.utcnow() persona_data["created_by"] = user_id # Initialize folder_ids array if not present if "folder_ids" not in persona_data: persona_data["folder_ids"] = [] result = await db.personas.insert_one(persona_data) print(f"✅ PERSONA CREATED: {persona_data.get('name', 'Unknown')} with folder_ids: {persona_data['folder_ids']}") return str(result.inserted_id) @staticmethod async def find_by_id(persona_id): db = await get_db() try: # If persona_id is already an ObjectId, use it directly if isinstance(persona_id, ObjectId): object_id = persona_id else: try: # Try to convert to ObjectId object_id = ObjectId(persona_id) except Exception as e: print(f"Invalid ObjectId format: {persona_id}, error: {e}") # Try lookup by string ID as fallback persona = await db.personas.find_one({"id": persona_id}) if persona: persona["_id"] = str(persona["_id"]) return persona return None # Lookup by ObjectId persona = await db.personas.find_one({"_id": object_id}) if persona: persona["_id"] = str(persona["_id"]) return persona except Exception as e: print(f"Error in find_by_id: {e}, persona_id: {persona_id}") return None @staticmethod async def find_by_user(user_id, limit=100): db = await get_db() personas = db.personas.find({"created_by": user_id}).sort("created_at", -1).limit(limit) result = [] async for persona in personas: persona["_id"] = str(persona["_id"]) result.append(persona) return result @staticmethod async def get_all(limit=100): try: db = await get_db() personas = db.personas.find().sort("created_at", -1).limit(limit) result = [] async for persona in personas: persona["_id"] = str(persona["_id"]) result.append(persona) return result except Exception as e: print(f"Error in Persona.get_all: {e}") return [] @staticmethod async def update(persona_id, data): db = await get_db() # Create a copy of the data to avoid modifying the original filtered_data = data.copy() # Remove fields that shouldn't be updated if '_id' in filtered_data: del filtered_data['_id'] if 'id' in filtered_data: del filtered_data['id'] if 'created_at' in filtered_data: del filtered_data['created_at'] if 'created_by' in filtered_data: del filtered_data['created_by'] # Set the updated timestamp filtered_data["updated_at"] = datetime.utcnow() result = await db.personas.update_one( {"_id": ObjectId(persona_id)}, {"$set": filtered_data} ) return result.modified_count > 0 @staticmethod async def delete(persona_id): db = await get_db() try: # Convert to ObjectId if needed if isinstance(persona_id, ObjectId): object_id = persona_id persona_id_str = str(persona_id) else: try: # Try to convert to ObjectId object_id = ObjectId(persona_id) persona_id_str = persona_id except Exception as e: print(f"Invalid ObjectId format for delete: {persona_id}, error: {e}") # Try delete by string ID as fallback result = await db.personas.delete_one({"id": persona_id}) # Note: No folder cleanup needed - using persona-centric storage return result.deleted_count > 0 # Note: No folder cleanup needed - using persona-centric storage # Folder membership is only stored in persona.folder_ids, which gets deleted with the persona # Delete by ObjectId result = await db.personas.delete_one({"_id": object_id}) return result.deleted_count > 0 except Exception as e: print(f"Error in delete: {e}, persona_id: {persona_id}") return False