364 lines
16 KiB
Python
364 lines
16 KiB
Python
from dotenv import load_dotenv, find_dotenv
|
|
load_dotenv(find_dotenv())
|
|
import os
|
|
import modules.logger_tool as logger
|
|
log_name = 'api_routers_database_tools_tldraw_filesystem'
|
|
log_dir = os.getenv("LOG_PATH", "/logs") # Default path as fallback
|
|
logging = logger.get_logger(
|
|
name=log_name,
|
|
log_level=os.getenv("LOG_LEVEL", "DEBUG"),
|
|
log_path=log_dir,
|
|
log_file=log_name,
|
|
runtime=True,
|
|
log_format='default'
|
|
)
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from typing import Dict
|
|
import json
|
|
|
|
from modules.database.tools.filesystem_tools import ClassroomCopilotFilesystem
|
|
from modules.database.schemas.nodes.users import UserNode
|
|
from modules.database.tools.neo4j_db_formatter import format_user_email_for_neo_db
|
|
|
|
router = APIRouter()
|
|
|
|
@router.post("/get_tldraw_user_node_file")
|
|
async def read_tldraw_user_node_file(user_node: UserNode):
|
|
logging.debug(f"Reading tldraw file for user node: {user_node.user_email}")
|
|
|
|
# Format the database name using the email
|
|
formatted_email = format_user_email_for_neo_db(user_node.user_email)
|
|
db_name = f"cc.users.{formatted_email}"
|
|
|
|
fs = ClassroomCopilotFilesystem(db_name=db_name, init_run_type="user")
|
|
|
|
logging.debug(f"Filesystem root path: {fs.root_path}")
|
|
|
|
# Use the path directly as provided - it represents the structure from root
|
|
if not user_node.node_storage_path:
|
|
raise HTTPException(status_code=400, detail="Node path not found")
|
|
|
|
# The path might already contain parts of the filesystem structure
|
|
# We need to construct the full path carefully
|
|
if user_node.node_storage_path.startswith("users/"):
|
|
# If path starts with users/, remove it since filesystem already has users/ structure
|
|
base_path = user_node.node_storage_path[6:] # Remove "users/" prefix
|
|
logging.debug(f"Removed 'users/' prefix, base_path is now: {base_path}")
|
|
else:
|
|
base_path = user_node.node_storage_path
|
|
logging.debug(f"No 'users/' prefix found, using path as-is: {base_path}")
|
|
|
|
base_path = os.path.normpath(base_path)
|
|
logging.debug(f"Using base path: {base_path}")
|
|
|
|
# Construct final path including tldraw file
|
|
file_path = os.path.join(base_path, "tldraw_file.json")
|
|
logging.debug(f"File path: {file_path}")
|
|
file_location = os.path.normpath(os.path.join(fs.root_path, file_path))
|
|
logging.debug(f"File location: {file_location}")
|
|
|
|
logging.debug(f"Attempting to read file at: {file_location}")
|
|
|
|
if os.path.exists(file_location):
|
|
logging.debug(f"File exists: {file_location}")
|
|
try:
|
|
with open(file_location, "r") as file:
|
|
data = json.load(file)
|
|
return data
|
|
except json.JSONDecodeError as e:
|
|
logging.error(f"Failed to parse JSON from file: {e}")
|
|
raise HTTPException(status_code=500, detail="Invalid JSON in file")
|
|
except Exception as e:
|
|
logging.error(f"Error reading file: {e}")
|
|
raise HTTPException(status_code=500, detail="Error reading file")
|
|
else:
|
|
# Check if directory exists
|
|
directory_location = os.path.dirname(file_location)
|
|
if os.path.exists(directory_location):
|
|
logging.debug(f"Directory exists but file doesn't, creating default tldraw file at: {file_location}")
|
|
try:
|
|
# Create default tldraw content
|
|
default_tldraw_content = create_default_tldraw_content()
|
|
|
|
# Ensure directory exists (should already exist, but just in case)
|
|
os.makedirs(directory_location, exist_ok=True)
|
|
|
|
# Write the default file
|
|
with open(file_location, "w") as file:
|
|
json.dump(default_tldraw_content, file, indent=4)
|
|
|
|
logging.info(f"Default tldraw file created at: {file_location}")
|
|
return default_tldraw_content
|
|
|
|
except Exception as e:
|
|
logging.error(f"Error creating default tldraw file: {e}")
|
|
raise HTTPException(status_code=500, detail="Error creating default tldraw file")
|
|
else:
|
|
logging.debug(f"Neither directory nor file exists: {directory_location}")
|
|
raise HTTPException(status_code=404, detail="Directory not found")
|
|
|
|
@router.post("/set_tldraw_user_node_file")
|
|
async def set_tldraw_user_node_file(user_node: UserNode, data: Dict):
|
|
logging.debug(f"Setting tldraw file for user node: {user_node.user_email}")
|
|
|
|
# Format the database name using the email
|
|
formatted_email = format_user_email_for_neo_db(user_node.user_email)
|
|
db_name = f"cc.users.{formatted_email}"
|
|
|
|
fs = ClassroomCopilotFilesystem(db_name=db_name, init_run_type="user")
|
|
|
|
# Use the path directly as provided - it represents the structure from root
|
|
if not user_node.node_storage_path:
|
|
raise HTTPException(status_code=400, detail="Node path not found")
|
|
|
|
# The path might already contain parts of the filesystem structure
|
|
# We need to construct the full path carefully
|
|
if user_node.node_storage_path.startswith("users/"):
|
|
# If path starts with users/, remove it since filesystem already has users/ structure
|
|
base_path = user_node.node_storage_path[6:] # Remove "users/" prefix
|
|
logging.debug(f"Removed 'users/' prefix, base_path is now: {base_path}")
|
|
else:
|
|
base_path = user_node.node_storage_path
|
|
logging.debug(f"No 'users/' prefix found, using path as-is: {base_path}")
|
|
|
|
base_path = os.path.normpath(base_path)
|
|
logging.debug(f"Using base path: {base_path}")
|
|
|
|
# Construct final path including tldraw file
|
|
file_path = os.path.join(base_path, "tldraw_file.json")
|
|
file_location = os.path.normpath(os.path.join(fs.root_path, file_path))
|
|
|
|
logging.debug(f"Attempting to write file at: {file_location}")
|
|
|
|
try:
|
|
# Ensure directory exists
|
|
directory_location = os.path.dirname(file_location)
|
|
os.makedirs(directory_location, exist_ok=True)
|
|
logging.debug(f"Ensured directory exists: {directory_location}")
|
|
|
|
# Write the file
|
|
with open(file_location, "w") as file:
|
|
json.dump(data, file, indent=4)
|
|
|
|
logging.info(f"tldraw file successfully written to: {file_location}")
|
|
return {"status": "success"}
|
|
except Exception as e:
|
|
logging.error(f"Error writing file: {e}")
|
|
raise HTTPException(status_code=500, detail="Error writing file")
|
|
|
|
@router.get("/get_tldraw_node_file")
|
|
async def read_tldraw_node_file(path: str, db_name: str):
|
|
logging.debug(f"Reading tldraw file for path: {path}")
|
|
logging.debug(f"Database name: {db_name}")
|
|
|
|
fs = ClassroomCopilotFilesystem(db_name=db_name, init_run_type="user")
|
|
|
|
logging.debug(f"Filesystem root path: {fs.root_path}")
|
|
|
|
# Use the path directly as provided - it represents the structure from root
|
|
if not path:
|
|
raise HTTPException(status_code=400, detail="Path not provided")
|
|
|
|
# The path might already contain parts of the filesystem structure
|
|
# We need to construct the full path carefully
|
|
if path.startswith("users/"):
|
|
# If path starts with users/, remove it since filesystem already has users/ structure
|
|
base_path = path[6:] # Remove "users/" prefix
|
|
logging.debug(f"Removed 'users/' prefix, base_path is now: {base_path}")
|
|
else:
|
|
base_path = path
|
|
logging.debug(f"No 'users/' prefix found, using path as-is: {base_path}")
|
|
|
|
base_path = os.path.normpath(base_path)
|
|
logging.debug(f"Using base path: {base_path}")
|
|
|
|
# Construct final path including tldraw file
|
|
file_path = os.path.join(base_path, "tldraw_file.json")
|
|
logging.debug(f"File path: {file_path}")
|
|
file_location = os.path.normpath(os.path.join(fs.root_path, file_path))
|
|
logging.debug(f"Final file location: {file_location}")
|
|
|
|
# Debug: Check what directories exist
|
|
logging.debug(f"Checking if root path exists: {fs.root_path} - {os.path.exists(fs.root_path)}")
|
|
logging.debug(f"Checking if base path exists: {os.path.join(fs.root_path, base_path)} - {os.path.exists(os.path.join(fs.root_path, base_path))}")
|
|
|
|
logging.debug(f"Attempting to read file at: {file_location}")
|
|
|
|
if os.path.exists(file_location):
|
|
logging.debug(f"File exists: {file_location}")
|
|
try:
|
|
with open(file_location, "r") as file:
|
|
data = json.load(file)
|
|
return data
|
|
except json.JSONDecodeError as e:
|
|
logging.error(f"Failed to parse JSON from file: {e}")
|
|
raise HTTPException(status_code=500, detail="Invalid JSON in file")
|
|
except Exception as e:
|
|
logging.error(f"Error reading file: {e}")
|
|
raise HTTPException(status_code=500, detail="Error reading file")
|
|
else:
|
|
# Check if directory exists
|
|
directory_location = os.path.dirname(file_location)
|
|
logging.debug(f"Checking if directory exists: {directory_location} - {os.path.exists(directory_location)}")
|
|
|
|
if os.path.exists(directory_location):
|
|
logging.debug(f"Directory exists but file doesn't, creating default tldraw file at: {file_location}")
|
|
try:
|
|
# Create default tldraw content
|
|
default_tldraw_content = create_default_tldraw_content()
|
|
|
|
# Ensure directory exists (should already exist, but just in case)
|
|
os.makedirs(directory_location, exist_ok=True)
|
|
|
|
# Write the default file
|
|
with open(file_location, "w") as file:
|
|
json.dump(default_tldraw_content, file, indent=4)
|
|
|
|
logging.info(f"Default tldraw file created at: {file_location}")
|
|
return default_tldraw_content
|
|
|
|
except Exception as e:
|
|
logging.error(f"Error creating default tldraw file: {e}")
|
|
raise HTTPException(status_code=500, detail="Error creating default tldraw file")
|
|
else:
|
|
logging.debug(f"Neither directory nor file exists: {directory_location}")
|
|
# List contents of parent directories to help debug
|
|
parent_dir = os.path.dirname(directory_location)
|
|
if os.path.exists(parent_dir):
|
|
logging.debug(f"Parent directory exists: {parent_dir}")
|
|
try:
|
|
contents = os.listdir(parent_dir)
|
|
logging.debug(f"Parent directory contents: {contents}")
|
|
except Exception as e:
|
|
logging.debug(f"Could not list parent directory contents: {e}")
|
|
else:
|
|
logging.debug(f"Parent directory does not exist: {parent_dir}")
|
|
|
|
raise HTTPException(status_code=404, detail="Directory not found")
|
|
|
|
@router.post("/set_tldraw_node_file")
|
|
async def set_tldraw_node_file(path: str, db_name: str, data: Dict):
|
|
logging.debug(f"Setting tldraw file for path: {path}")
|
|
|
|
fs = ClassroomCopilotFilesystem(db_name=db_name, init_run_type="user")
|
|
|
|
logging.debug(f"Filesystem root path: {fs.root_path}")
|
|
|
|
# Use the path directly as provided - it represents the structure from root
|
|
if not path:
|
|
raise HTTPException(status_code=400, detail="Path not provided")
|
|
|
|
# The path might already contain parts of the filesystem structure
|
|
# We need to construct the full path carefully
|
|
if path.startswith("users/"):
|
|
# If path starts with users/, remove it since filesystem already has users/ structure
|
|
base_path = path[6:] # Remove "users/" prefix
|
|
logging.debug(f"Removed 'users/' prefix, base_path is now: {base_path}")
|
|
else:
|
|
base_path = path
|
|
logging.debug(f"No 'users/' prefix found, using path as-is: {base_path}")
|
|
|
|
base_path = os.path.normpath(base_path)
|
|
logging.debug(f"Using base path: {base_path}")
|
|
|
|
# Construct final path including tldraw file
|
|
file_path = os.path.join(base_path, "tldraw_file.json")
|
|
file_location = os.path.normpath(os.path.join(fs.root_path, file_path))
|
|
logging.debug(f"File location: {file_location}")
|
|
|
|
logging.debug(f"Attempting to set file at: {file_location}")
|
|
|
|
try:
|
|
# Ensure directory exists
|
|
directory_location = os.path.dirname(file_location)
|
|
os.makedirs(directory_location, exist_ok=True)
|
|
logging.debug(f"Ensured directory exists: {directory_location}")
|
|
|
|
# Write the file
|
|
with open(file_location, "w") as file:
|
|
json.dump(data, file, indent=4)
|
|
|
|
logging.info(f"tldraw file successfully written to: {file_location}")
|
|
return {"status": "success"}
|
|
except Exception as e:
|
|
logging.error(f"Error writing file: {e}")
|
|
raise HTTPException(status_code=500, detail="Error writing file")
|
|
|
|
def create_default_tldraw_content():
|
|
"""Create default tldraw content structure."""
|
|
return {
|
|
"document": {
|
|
"store": {
|
|
"document:document": {
|
|
"gridSize": 10,
|
|
"name": "",
|
|
"meta": {},
|
|
"id": "document:document",
|
|
"typeName": "document"
|
|
},
|
|
"page:page": {
|
|
"meta": {},
|
|
"id": "page:page",
|
|
"name": "Page 1",
|
|
"index": "a1",
|
|
"typeName": "page"
|
|
}
|
|
},
|
|
"schema": {
|
|
"schemaVersion": 2,
|
|
"sequences": {
|
|
"com.tldraw.store": 4,
|
|
"com.tldraw.asset": 1,
|
|
"com.tldraw.camera": 1,
|
|
"com.tldraw.document": 2,
|
|
"com.tldraw.instance": 25,
|
|
"com.tldraw.instance_page_state": 5,
|
|
"com.tldraw.page": 1,
|
|
"com.tldraw.instance_presence": 5,
|
|
"com.tldraw.pointer": 1,
|
|
"com.tldraw.shape": 4,
|
|
"com.tldraw.asset.bookmark": 2,
|
|
"com.tldraw.asset.image": 5,
|
|
"com.tldraw.asset.video": 5,
|
|
"com.tldraw.shape.arrow": 5,
|
|
"com.tldraw.shape.bookmark": 2,
|
|
"com.tldraw.shape.draw": 2,
|
|
"com.tldraw.shape.embed": 4,
|
|
"com.tldraw.shape.frame": 0,
|
|
"com.tldraw.shape.geo": 9,
|
|
"com.tldraw.shape.group": 0,
|
|
"com.tldraw.shape.highlight": 1,
|
|
"com.tldraw.shape.image": 4,
|
|
"com.tldraw.shape.line": 5,
|
|
"com.tldraw.shape.note": 8,
|
|
"com.tldraw.shape.text": 2,
|
|
"com.tldraw.shape.video": 2,
|
|
"com.tldraw.binding.arrow": 0
|
|
}
|
|
},
|
|
"recordVersions": {
|
|
"asset": {"version": 1, "subTypeKey": "type", "subTypeVersions": {}},
|
|
"camera": {"version": 1},
|
|
"document": {"version": 2},
|
|
"instance": {"version": 21},
|
|
"instance_page_state": {"version": 5},
|
|
"page": {"version": 1},
|
|
"shape": {"version": 3, "subTypeKey": "type", "subTypeVersions": {}},
|
|
"instance_presence": {"version": 5},
|
|
"pointer": {"version": 1}
|
|
},
|
|
"rootShapeIds": [],
|
|
"bindings": [],
|
|
"assets": []
|
|
},
|
|
"session": {
|
|
"version": 0,
|
|
"currentPageId": "page:page",
|
|
"pageStates": [{
|
|
"pageId": "page:page",
|
|
"camera": {"x": 0, "y": 0, "z": 1},
|
|
"selectedShapeIds": []
|
|
}]
|
|
}
|
|
}
|