semblance-dev/backend/app/models/folder.py

320 lines
No EOL
13 KiB
Python

from bson import ObjectId
from app.db import get_db
from datetime import datetime
class Folder:
@staticmethod
def create(folder_data, user_id):
"""Create a new folder."""
db = get_db()
# Add metadata
folder_data["created_at"] = datetime.utcnow()
folder_data["created_by"] = user_id
# Note: No longer storing persona_ids in folders - using persona-centric storage
result = db.folders.insert_one(folder_data)
return str(result.inserted_id)
@staticmethod
def find_by_id(folder_id):
"""Find a folder by its ID."""
db = get_db()
try:
folder = db.folders.find_one({"_id": ObjectId(folder_id)})
if folder:
folder["_id"] = str(folder["_id"])
return folder
except Exception as e:
print(f"Error in find_by_id: {e}")
return None
@staticmethod
def find_by_user(user_id, limit=100):
"""Find all folders created by a specific user."""
db = get_db()
folders = db.folders.find({"created_by": user_id}).sort("created_at", -1).limit(limit)
result = []
for folder in folders:
folder["_id"] = str(folder["_id"])
result.append(folder)
return result
@staticmethod
def get_all(limit=100):
"""Get all folders (for debugging/admin purposes)."""
try:
db = get_db()
folders = list(db.folders.find().sort("created_at", -1).limit(limit))
result = []
for folder in folders:
folder["_id"] = str(folder["_id"])
result.append(folder)
return result
except Exception as e:
print(f"Error in Folder.get_all: {e}")
return []
@staticmethod
def update(folder_id, data):
"""Update a folder."""
db = 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 = db.folders.update_one(
{"_id": ObjectId(folder_id)},
{"$set": filtered_data}
)
return result.modified_count > 0
@staticmethod
def delete(folder_id):
"""Delete a folder."""
db = get_db()
try:
result = db.folders.delete_one({"_id": ObjectId(folder_id)})
return result.deleted_count > 0
except Exception as e:
print(f"Error in delete: {e}")
return False
@staticmethod
def add_persona(folder_id, persona_id):
"""Add a persona to a folder (persona-centric storage)."""
db = get_db()
try:
print(f"🔧 FOLDER ADD_PERSONA: folder_id={folder_id}, persona_id={persona_id}")
# Check if persona exists
persona = db.personas.find_one({"_id": ObjectId(persona_id)})
if not persona:
print(f"❌ FOLDER ADD_PERSONA: Persona {persona_id} not found")
return False
print(f"✅ FOLDER ADD_PERSONA: Found persona {persona.get('name', 'Unknown')} ({persona_id})")
print(f"📋 FOLDER ADD_PERSONA: Current folder_ids: {persona.get('folder_ids', 'None')}")
# Only update the persona's folder_ids - single source of truth
persona_result = db.personas.update_one(
{"_id": ObjectId(persona_id)},
{"$addToSet": {"folder_ids": folder_id}, "$set": {"updated_at": datetime.utcnow()}}
)
print(f"📝 FOLDER ADD_PERSONA: Update result - modified_count: {persona_result.modified_count}, matched_count: {persona_result.matched_count}")
# Verify the update
updated_persona = db.personas.find_one({"_id": ObjectId(persona_id)})
print(f"✅ FOLDER ADD_PERSONA: Updated folder_ids: {updated_persona.get('folder_ids', 'None')}")
# Update folder's updated_at timestamp
db.folders.update_one(
{"_id": ObjectId(folder_id)},
{"$set": {"updated_at": datetime.utcnow()}}
)
return persona_result.modified_count > 0
except Exception as e:
print(f"❌ FOLDER ADD_PERSONA ERROR: {e}")
import traceback
print(f"❌ FOLDER ADD_PERSONA TRACEBACK: {traceback.format_exc()}")
return False
@staticmethod
def remove_persona(folder_id, persona_id):
"""Remove a persona from a folder (persona-centric storage)."""
db = get_db()
try:
print(f"🔧 FOLDER REMOVE_PERSONA: folder_id={folder_id}, persona_id={persona_id}")
# Check if persona exists
persona = db.personas.find_one({"_id": ObjectId(persona_id)})
if not persona:
print(f"❌ FOLDER REMOVE_PERSONA: Persona {persona_id} not found")
return False
print(f"✅ FOLDER REMOVE_PERSONA: Found persona {persona.get('name', 'Unknown')} ({persona_id})")
print(f"📋 FOLDER REMOVE_PERSONA: Current folder_ids: {persona.get('folder_ids', 'None')}")
# Only update the persona's folder_ids - single source of truth
persona_result = db.personas.update_one(
{"_id": ObjectId(persona_id)},
{"$pull": {"folder_ids": folder_id}, "$set": {"updated_at": datetime.utcnow()}}
)
print(f"📝 FOLDER REMOVE_PERSONA: Update result - modified_count: {persona_result.modified_count}, matched_count: {persona_result.matched_count}")
# Verify the update
updated_persona = db.personas.find_one({"_id": ObjectId(persona_id)})
print(f"✅ FOLDER REMOVE_PERSONA: Updated folder_ids: {updated_persona.get('folder_ids', 'None')}")
# Update folder's updated_at timestamp
db.folders.update_one(
{"_id": ObjectId(folder_id)},
{"$set": {"updated_at": datetime.utcnow()}}
)
return persona_result.modified_count > 0
except Exception as e:
print(f"❌ FOLDER REMOVE_PERSONA ERROR: {e}")
import traceback
print(f"❌ FOLDER REMOVE_PERSONA TRACEBACK: {traceback.format_exc()}")
return False
@staticmethod
def add_personas_batch(folder_id, persona_ids):
"""Add multiple personas to a folder (persona-centric storage)."""
db = get_db()
try:
print(f"🔧 FOLDER ADD_PERSONAS_BATCH: folder_id={folder_id}, persona_ids={persona_ids}")
# Add folder to each persona's folder_ids - single source of truth
persona_results = []
for persona_id in persona_ids:
try:
print(f"🔧 FOLDER BATCH: Processing persona {persona_id}")
# Check if persona exists
persona = db.personas.find_one({"_id": ObjectId(persona_id)})
if not persona:
print(f"❌ FOLDER BATCH: Persona {persona_id} not found")
persona_results.append(False)
continue
print(f"✅ FOLDER BATCH: Found persona {persona.get('name', 'Unknown')}")
print(f"📋 FOLDER BATCH: Current folder_ids: {persona.get('folder_ids', 'None')}")
result = db.personas.update_one(
{"_id": ObjectId(persona_id)},
{"$addToSet": {"folder_ids": folder_id}, "$set": {"updated_at": datetime.utcnow()}}
)
print(f"📝 FOLDER BATCH: Update result for {persona_id} - modified: {result.modified_count}")
persona_results.append(result.modified_count > 0)
except Exception as e:
print(f"❌ FOLDER BATCH ERROR for persona {persona_id}: {e}")
persona_results.append(False)
# Update folder's updated_at timestamp
db.folders.update_one(
{"_id": ObjectId(folder_id)},
{"$set": {"updated_at": datetime.utcnow()}}
)
success_count = sum(1 for r in persona_results if r)
print(f"✅ FOLDER ADD_PERSONAS_BATCH: {success_count}/{len(persona_ids)} personas updated successfully")
return any(persona_results)
except Exception as e:
print(f"❌ FOLDER ADD_PERSONAS_BATCH ERROR: {e}")
import traceback
print(f"❌ FOLDER ADD_PERSONAS_BATCH TRACEBACK: {traceback.format_exc()}")
return False
@staticmethod
def remove_personas_batch(folder_id, persona_ids):
"""Remove multiple personas from a folder (persona-centric storage)."""
db = get_db()
try:
print(f"🔧 FOLDER REMOVE_PERSONAS_BATCH: folder_id={folder_id}, persona_ids={persona_ids}")
# Remove folder from each persona's folder_ids - single source of truth
persona_results = []
for persona_id in persona_ids:
try:
print(f"🔧 FOLDER REMOVE_BATCH: Processing persona {persona_id}")
# Check if persona exists
persona = db.personas.find_one({"_id": ObjectId(persona_id)})
if not persona:
print(f"❌ FOLDER REMOVE_BATCH: Persona {persona_id} not found")
persona_results.append(False)
continue
print(f"✅ FOLDER REMOVE_BATCH: Found persona {persona.get('name', 'Unknown')}")
print(f"📋 FOLDER REMOVE_BATCH: Current folder_ids: {persona.get('folder_ids', 'None')}")
result = db.personas.update_one(
{"_id": ObjectId(persona_id)},
{"$pull": {"folder_ids": folder_id}, "$set": {"updated_at": datetime.utcnow()}}
)
print(f"📝 FOLDER REMOVE_BATCH: Update result for {persona_id} - modified: {result.modified_count}")
persona_results.append(result.modified_count > 0)
except Exception as e:
print(f"❌ FOLDER REMOVE_BATCH ERROR for persona {persona_id}: {e}")
persona_results.append(False)
# Update folder's updated_at timestamp
db.folders.update_one(
{"_id": ObjectId(folder_id)},
{"$set": {"updated_at": datetime.utcnow()}}
)
success_count = sum(1 for r in persona_results if r)
print(f"✅ FOLDER REMOVE_PERSONAS_BATCH: {success_count}/{len(persona_ids)} personas updated successfully")
return any(persona_results)
except Exception as e:
print(f"❌ FOLDER REMOVE_PERSONAS_BATCH ERROR: {e}")
import traceback
print(f"❌ FOLDER REMOVE_PERSONAS_BATCH TRACEBACK: {traceback.format_exc()}")
return False
@staticmethod
def get_folders_containing_persona(persona_id, user_id=None):
"""Find all folders that contain a specific persona (persona-centric storage)."""
db = get_db()
try:
# Get the persona to see which folders it belongs to
persona = db.personas.find_one({"_id": ObjectId(persona_id)})
if not persona or not persona.get("folder_ids"):
return []
# Get folders by their IDs
folder_ids = [ObjectId(fid) for fid in persona["folder_ids"]]
query = {"_id": {"$in": folder_ids}}
# Optionally filter by user
if user_id:
query["created_by"] = user_id
folders = list(db.folders.find(query))
result = []
for folder in folders:
folder["_id"] = str(folder["_id"])
result.append(folder)
return result
except Exception as e:
print(f"Error getting folders for persona {persona_id}: {e}")
return []