278 lines
No EOL
11 KiB
Python
Executable file
278 lines
No EOL
11 KiB
Python
Executable file
from quart import Blueprint, request, jsonify
|
|
from app.auth.quart_jwt import jwt_required, get_jwt_identity
|
|
from app.models.folder import Folder
|
|
from bson import ObjectId
|
|
import datetime
|
|
|
|
# Helper function to make MongoDB documents JSON serializable
|
|
def make_serializable(obj):
|
|
if isinstance(obj, dict):
|
|
return {k: make_serializable(v) for k, v in obj.items()}
|
|
elif isinstance(obj, list):
|
|
return [make_serializable(item) for item in obj]
|
|
elif isinstance(obj, ObjectId):
|
|
return str(obj)
|
|
elif isinstance(obj, datetime.datetime):
|
|
return obj.isoformat()
|
|
else:
|
|
return obj
|
|
|
|
folders_bp = Blueprint('folders', __name__)
|
|
|
|
@folders_bp.route('', methods=['GET'])
|
|
@folders_bp.route('/', methods=['GET'])
|
|
@jwt_required(optional=True) # Make JWT optional for development
|
|
async def get_folders():
|
|
"""Get all folders in hierarchical tree structure - shared across all users."""
|
|
try:
|
|
# Return folders in hierarchical tree structure
|
|
folders = await Folder.get_folder_tree()
|
|
|
|
# Make folders serializable
|
|
serializable_folders = make_serializable(folders)
|
|
return jsonify(serializable_folders), 200
|
|
except Exception as e:
|
|
print(f"Error in get_folders: {e}")
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
@folders_bp.route('/<folder_id>', methods=['GET'])
|
|
@jwt_required(optional=True) # Make JWT optional for development
|
|
async def get_folder(folder_id):
|
|
"""Get a specific folder by ID."""
|
|
try:
|
|
folder = await Folder.find_by_id(folder_id)
|
|
if not folder:
|
|
return jsonify({"message": "Folder not found"}), 404
|
|
|
|
# Make folder serializable
|
|
serializable_folder = make_serializable(folder)
|
|
return jsonify(serializable_folder), 200
|
|
except Exception as e:
|
|
print(f"Error in get_folder: {e}")
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
@folders_bp.route('', methods=['POST'])
|
|
@folders_bp.route('/', methods=['POST'])
|
|
@jwt_required()
|
|
async def create_folder():
|
|
"""Create a new folder."""
|
|
user_id = get_jwt_identity()
|
|
data = await request.get_json()
|
|
|
|
if not data:
|
|
return jsonify({"message": "No data provided"}), 400
|
|
|
|
if not data.get('name'):
|
|
return jsonify({"message": "Folder name is required"}), 400
|
|
|
|
folder_id = await Folder.create(data, user_id)
|
|
|
|
return jsonify({
|
|
"message": "Folder created successfully",
|
|
"folder_id": folder_id
|
|
}), 201
|
|
|
|
@folders_bp.route('/<folder_id>', methods=['PUT'])
|
|
@jwt_required()
|
|
async def update_folder(folder_id):
|
|
"""Update a folder."""
|
|
try:
|
|
data = await request.get_json()
|
|
|
|
if not data:
|
|
return jsonify({"message": "No data provided"}), 400
|
|
|
|
folder = await Folder.find_by_id(folder_id)
|
|
if not folder:
|
|
return jsonify({"message": "Folder not found"}), 404
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
# Ensure _id is not being modified
|
|
if '_id' in data:
|
|
del data['_id']
|
|
|
|
# Ensure id is not being used for update
|
|
if 'id' in data:
|
|
del data['id']
|
|
|
|
success = await Folder.update(folder_id, data)
|
|
|
|
if success:
|
|
# Get the updated folder and return it
|
|
updated_folder = await Folder.find_by_id(folder_id)
|
|
return jsonify({
|
|
"message": "Folder updated successfully",
|
|
"folder": make_serializable(updated_folder)
|
|
}), 200
|
|
else:
|
|
return jsonify({"message": "No changes made to folder"}), 200
|
|
except Exception as e:
|
|
print(f"Error updating folder: {e}")
|
|
return jsonify({"message": f"Failed to update folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>', methods=['DELETE'])
|
|
@jwt_required(optional=True) # Make JWT optional for development
|
|
async def delete_folder(folder_id):
|
|
"""Delete a folder and its entire hierarchy."""
|
|
user_id = get_jwt_identity()
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
try:
|
|
success, message = await Folder.delete_hierarchy(folder_id, user_id)
|
|
|
|
if success:
|
|
return jsonify({"message": message}), 200
|
|
else:
|
|
return jsonify({"message": message}), 400
|
|
except Exception as e:
|
|
print(f"Error deleting folder hierarchy: {e}")
|
|
return jsonify({"message": f"Failed to delete folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>/personas', methods=['POST'])
|
|
@jwt_required()
|
|
async def add_persona_to_folder(folder_id):
|
|
"""Add a persona to a folder (supports multiple folders per persona)."""
|
|
try:
|
|
data = await request.get_json()
|
|
|
|
if not data or not data.get('persona_id'):
|
|
return jsonify({"message": "Persona ID is required"}), 400
|
|
|
|
folder = await Folder.find_by_id(folder_id)
|
|
if not folder:
|
|
return jsonify({"message": "Folder not found"}), 404
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
persona_id = data['persona_id']
|
|
success = await Folder.add_persona(folder_id, persona_id)
|
|
|
|
if success:
|
|
return jsonify({"message": "Persona added to folder successfully"}), 200
|
|
else:
|
|
return jsonify({"message": "Persona was already in folder or update failed"}), 200
|
|
except Exception as e:
|
|
print(f"Error adding persona to folder: {e}")
|
|
return jsonify({"message": f"Failed to add persona to folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>/personas/<persona_id>', methods=['DELETE'])
|
|
@jwt_required()
|
|
async def remove_persona_from_folder(folder_id, persona_id):
|
|
"""Remove a persona from a folder (persona can remain in other folders)."""
|
|
try:
|
|
folder = await Folder.find_by_id(folder_id)
|
|
if not folder:
|
|
return jsonify({"message": "Folder not found"}), 404
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
success = await Folder.remove_persona(folder_id, persona_id)
|
|
|
|
if success:
|
|
return jsonify({"message": "Persona removed from folder successfully"}), 200
|
|
else:
|
|
return jsonify({"message": "Persona was not in folder or removal failed"}), 200
|
|
except Exception as e:
|
|
print(f"Error removing persona from folder: {e}")
|
|
return jsonify({"message": f"Failed to remove persona from folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>/personas/batch', methods=['POST'])
|
|
@jwt_required()
|
|
async def add_personas_to_folder_batch(folder_id):
|
|
"""Add multiple personas to a folder (personas can be in multiple folders)."""
|
|
try:
|
|
data = await request.get_json()
|
|
|
|
if not data or not data.get('persona_ids'):
|
|
return jsonify({"message": "Persona IDs are required"}), 400
|
|
|
|
folder = await Folder.find_by_id(folder_id)
|
|
if not folder:
|
|
return jsonify({"message": "Folder not found"}), 404
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
persona_ids = data['persona_ids']
|
|
if not isinstance(persona_ids, list):
|
|
return jsonify({"message": "persona_ids must be a list"}), 400
|
|
|
|
success = await Folder.add_personas_batch(folder_id, persona_ids)
|
|
|
|
if success:
|
|
return jsonify({"message": f"Successfully added {len(persona_ids)} personas to folder"}), 200
|
|
else:
|
|
return jsonify({"message": "Update failed or no changes made"}), 200
|
|
except Exception as e:
|
|
print(f"Error adding personas to folder: {e}")
|
|
return jsonify({"message": f"Failed to add personas to folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>/personas/remove-batch', methods=['POST'])
|
|
@jwt_required()
|
|
async def remove_personas_from_folder_batch(folder_id):
|
|
"""Remove multiple personas from a folder (personas remain in other folders)."""
|
|
print(f"🌐 BACKEND: POST /folders/{folder_id}/personas/remove-batch endpoint hit")
|
|
try:
|
|
data = await request.get_json()
|
|
print(f"🌐 BACKEND: Raw request data: {data}")
|
|
print(f"🌐 BACKEND: Request content type: {request.content_type}")
|
|
print(f"🌐 BACKEND: Request method: {request.method}")
|
|
|
|
if not data or not data.get('persona_ids'):
|
|
print(f"❌ BACKEND: Missing persona_ids in data: {data}")
|
|
return jsonify({"message": "Persona IDs are required"}), 400
|
|
|
|
folder = await Folder.find_by_id(folder_id)
|
|
if not folder:
|
|
return jsonify({"message": "Folder not found"}), 404
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
persona_ids = data['persona_ids']
|
|
if not isinstance(persona_ids, list):
|
|
return jsonify({"message": "persona_ids must be a list"}), 400
|
|
|
|
success = await Folder.remove_personas_batch(folder_id, persona_ids)
|
|
|
|
if success:
|
|
return jsonify({"message": f"Successfully removed {len(persona_ids)} personas from folder"}), 200
|
|
else:
|
|
return jsonify({"message": "Update failed or no changes made"}), 200
|
|
except Exception as e:
|
|
print(f"Error removing personas from folder: {e}")
|
|
return jsonify({"message": f"Failed to remove personas from folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>/move', methods=['PUT'])
|
|
@jwt_required(optional=True) # Make JWT optional for development
|
|
async def move_folder(folder_id):
|
|
"""Move a folder to a new parent."""
|
|
try:
|
|
data = await request.get_json()
|
|
user_id = get_jwt_identity()
|
|
|
|
new_parent_id = data.get('parent_folder_id') # None for root level
|
|
|
|
# Folder operations are shared across all users in this system
|
|
|
|
success, message = await Folder.move_folder(folder_id, new_parent_id, user_id)
|
|
|
|
if success:
|
|
return jsonify({"message": message}), 200
|
|
else:
|
|
return jsonify({"message": message}), 400
|
|
except Exception as e:
|
|
print(f"Error moving folder: {e}")
|
|
return jsonify({"message": f"Failed to move folder: {str(e)}"}), 500
|
|
|
|
@folders_bp.route('/<folder_id>/descendants', methods=['GET'])
|
|
@jwt_required(optional=True)
|
|
async def get_folder_descendants(folder_id):
|
|
"""Get all descendant folders of a given folder."""
|
|
try:
|
|
descendants = await Folder.get_descendants(folder_id)
|
|
serializable_descendants = make_serializable(descendants)
|
|
return jsonify(serializable_descendants), 200
|
|
except Exception as e:
|
|
print(f"Error getting folder descendants: {e}")
|
|
return jsonify({"error": str(e)}), 500 |