Initial commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,220 @@
|
||||
import os
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from typing import List, Dict, Any, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from modules.logger_tool import initialise_logger
|
||||
from modules.database.tools import neo4j_driver_tools as driver_tools
|
||||
|
||||
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/get-calendar-structure")
|
||||
async def get_calendar_structure(db_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get the complete calendar structure including years, months, weeks, and days.
|
||||
"""
|
||||
try:
|
||||
# Get all calendar nodes in a single query
|
||||
query = """
|
||||
// Match all calendar-related nodes
|
||||
MATCH (y:CalendarYear)
|
||||
OPTIONAL MATCH (y)-[:YEAR_INCLUDES_MONTH]->(m:CalendarMonth)
|
||||
OPTIONAL MATCH (m)-[:MONTH_INCLUDES_DAY]->(d:CalendarDay)
|
||||
OPTIONAL MATCH (w:CalendarWeek)-[:WEEK_INCLUDES_DAY]->(d)
|
||||
WITH y, m, w, d
|
||||
ORDER BY y.date, m.date, w.date, d.date
|
||||
|
||||
// Collect all nodes with dates converted to strings
|
||||
RETURN {
|
||||
years: collect(DISTINCT {
|
||||
id: y.unique_id,
|
||||
path: y.path,
|
||||
date: toString(y.date),
|
||||
__primarylabel__: 'CalendarYear'
|
||||
}),
|
||||
months: collect(DISTINCT {
|
||||
id: m.unique_id,
|
||||
path: m.path,
|
||||
date: toString(m.date),
|
||||
__primarylabel__: 'CalendarMonth'
|
||||
}),
|
||||
weeks: collect(DISTINCT {
|
||||
id: w.unique_id,
|
||||
path: w.path,
|
||||
date: toString(w.date),
|
||||
__primarylabel__: 'CalendarWeek'
|
||||
}),
|
||||
days: collect(DISTINCT {
|
||||
id: d.unique_id,
|
||||
path: d.path,
|
||||
date: toString(d.date),
|
||||
week_id: w.unique_id,
|
||||
month_id: m.unique_id,
|
||||
__primarylabel__: 'CalendarDay'
|
||||
})
|
||||
} as structure
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query)
|
||||
record = result.single()
|
||||
if not record:
|
||||
raise HTTPException(status_code=404, detail="Calendar structure not found")
|
||||
|
||||
structure = record["structure"]
|
||||
|
||||
# Find current day using string comparison
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
current_day = next(
|
||||
(day["id"] for day in structure["days"]
|
||||
if day["date"] == today),
|
||||
structure["days"][0]["id"] if structure["days"] else None
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"structure": {
|
||||
"years": structure["years"],
|
||||
"months": structure["months"],
|
||||
"weeks": structure["weeks"],
|
||||
"days": structure["days"],
|
||||
"currentDay": current_day
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting calendar structure: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-calendar-days")
|
||||
async def get_calendar_days(db_name: str, start_date: str, end_date: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all calendar days in a date range.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (d:CalendarDay)
|
||||
WHERE date(d.date) >= date($start_date) AND date(d.date) <= date($end_date)
|
||||
OPTIONAL MATCH (w:CalendarWeek)-[:WEEK_INCLUDES_DAY]->(d)
|
||||
OPTIONAL MATCH (m:CalendarMonth)-[:MONTH_INCLUDES_DAY]->(d)
|
||||
RETURN {
|
||||
id: d.unique_id,
|
||||
path: d.path,
|
||||
date: d.date,
|
||||
week_id: w.unique_id,
|
||||
month_id: m.unique_id,
|
||||
__primarylabel__: 'CalendarDay'
|
||||
} as day
|
||||
ORDER BY d.date
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query, start_date=start_date, end_date=end_date)
|
||||
days = [record["day"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"days": days
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting calendar days: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-calendar-weeks")
|
||||
async def get_calendar_weeks(db_name: str, start_date: str, end_date: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all calendar weeks in a date range.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (w:CalendarWeek)-[:WEEK_INCLUDES_DAY]->(d:CalendarDay)
|
||||
WHERE date(w.date) >= date($start_date) AND date(w.date) <= date($end_date)
|
||||
WITH w, collect(d) as days
|
||||
RETURN {
|
||||
id: w.unique_id,
|
||||
path: w.path,
|
||||
date: w.date,
|
||||
day_ids: [day in days | day.unique_id],
|
||||
__primarylabel__: 'CalendarWeek'
|
||||
} as week
|
||||
ORDER BY w.date
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query, start_date=start_date, end_date=end_date)
|
||||
weeks = [record["week"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"weeks": weeks
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting calendar weeks: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-calendar-months")
|
||||
async def get_calendar_months(db_name: str, start_date: str, end_date: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all calendar months in a date range.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (m:CalendarMonth)-[:MONTH_INCLUDES_DAY]->(d:CalendarDay)
|
||||
WHERE date(m.date) >= date($start_date) AND date(m.date) <= date($end_date)
|
||||
WITH m, collect(d) as days
|
||||
RETURN {
|
||||
id: m.unique_id,
|
||||
path: m.path,
|
||||
date: m.date,
|
||||
day_ids: [day in days | day.unique_id],
|
||||
__primarylabel__: 'CalendarMonth'
|
||||
} as month
|
||||
ORDER BY m.date
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query, start_date=start_date, end_date=end_date)
|
||||
months = [record["month"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"months": months
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting calendar months: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-calendar-years")
|
||||
async def get_calendar_years(db_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all calendar years.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (y:CalendarYear)-[:YEAR_INCLUDES_MONTH]->(m:CalendarMonth)
|
||||
WITH y, collect(m) as months
|
||||
RETURN {
|
||||
id: y.unique_id,
|
||||
path: y.path,
|
||||
date: y.date,
|
||||
month_ids: [month in months | month.unique_id],
|
||||
__primarylabel__: 'CalendarYear'
|
||||
} as year
|
||||
ORDER BY y.date
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query)
|
||||
years = [record["year"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"years": years
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting calendar years: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
@@ -0,0 +1,257 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from typing import Dict, Any
|
||||
from modules.database.tools import neo4j_driver_tools as driver_tools
|
||||
from modules.logger_tool import initialise_logger
|
||||
from neo4j.time import DateTime, Date
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
|
||||
router = APIRouter()
|
||||
|
||||
def convert_neo4j_values(value: Any) -> Any:
|
||||
"""Convert Neo4j types to JSON-serializable types."""
|
||||
if isinstance(value, DateTime):
|
||||
return value.isoformat() # Convert to ISO format string
|
||||
elif isinstance(value, Date):
|
||||
return value.isoformat() # Convert Date to ISO format string
|
||||
elif isinstance(value, dict):
|
||||
return {k: convert_neo4j_values(v) for k, v in value.items()}
|
||||
elif isinstance(value, list):
|
||||
return [convert_neo4j_values(v) for v in value]
|
||||
return value
|
||||
|
||||
def get_default_node_week(db_name: str) -> Dict[str, Any]:
|
||||
"""Get the current week node."""
|
||||
# Get today's date
|
||||
today = datetime.now()
|
||||
|
||||
# Find the calendar week node that contains today's date
|
||||
query = """
|
||||
MATCH (w:CalendarWeek)
|
||||
WHERE date(w.start_date) <= date($today) AND date($today) <= date(w.start_date) + duration('P7D')
|
||||
RETURN w
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query, today=today.strftime('%Y-%m-%d'))
|
||||
week_node = result.single()
|
||||
|
||||
if not week_node:
|
||||
raise HTTPException(status_code=404, detail="No default node found for context: week")
|
||||
|
||||
node = week_node["w"]
|
||||
node_data = dict(node)
|
||||
converted_data = convert_neo4j_values(node_data)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"node": {
|
||||
"id": node["unique_id"],
|
||||
"path": node["path"],
|
||||
"type": "CalendarWeek",
|
||||
"label": node.get("title", "Calendar Week"),
|
||||
"data": converted_data
|
||||
}
|
||||
}
|
||||
|
||||
def get_default_node_month(db_name: str) -> Dict[str, Any]:
|
||||
"""Get the current month node."""
|
||||
# Get today's date
|
||||
today = datetime.now()
|
||||
|
||||
# Find the calendar month node for the current month
|
||||
query = """
|
||||
MATCH (m:CalendarMonth)
|
||||
WHERE m.year = $year AND m.month = $month
|
||||
RETURN m
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query, year=str(today.year), month=str(today.month))
|
||||
month_node = result.single()
|
||||
|
||||
if not month_node:
|
||||
raise HTTPException(status_code=404, detail="No default node found for context: month")
|
||||
|
||||
node = month_node["m"]
|
||||
node_data = dict(node)
|
||||
converted_data = convert_neo4j_values(node_data)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"node": {
|
||||
"id": node["unique_id"],
|
||||
"path": node["path"],
|
||||
"type": "CalendarMonth",
|
||||
"label": node.get("title", "Calendar Month"),
|
||||
"data": converted_data
|
||||
}
|
||||
}
|
||||
|
||||
@router.get("/get-default-node/{context}")
|
||||
async def get_default_node(context: str, db_name: str, base_context: str | None = None) -> Dict[str, Any]:
|
||||
"""Get the default node for a given context."""
|
||||
try:
|
||||
# Handle special cases for week and month
|
||||
if context == 'week':
|
||||
return get_default_node_week(db_name)
|
||||
elif context == 'month':
|
||||
return get_default_node_month(db_name)
|
||||
|
||||
# Map contexts to their default node queries
|
||||
context_queries = {
|
||||
# Base Contexts
|
||||
'profile': """
|
||||
MATCH (n:User)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'worker': """
|
||||
MATCH (n)
|
||||
WHERE n:SchoolAdmin OR n:Teacher OR n:Student OR n:Developer OR n:SuperAdmin
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'calendar': """
|
||||
MATCH (n:Calendar)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'teaching': """
|
||||
MATCH (n:Teacher)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'school': """
|
||||
MATCH (n:School)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'department': """
|
||||
MATCH (n:Department)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'class': """
|
||||
MATCH (n:Class)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - Overview queries for each base context
|
||||
'overview': """
|
||||
MATCH (n)
|
||||
WHERE CASE $base_context
|
||||
WHEN 'profile' THEN n:User
|
||||
WHEN 'calendar' THEN n:Calendar
|
||||
WHEN 'teaching' THEN n:Teacher
|
||||
WHEN 'school' THEN n:School
|
||||
WHEN 'department' THEN n:Department
|
||||
WHEN 'class' THEN n:Class
|
||||
ELSE false
|
||||
END
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - User
|
||||
'settings': """
|
||||
MATCH (n:User)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'history': """
|
||||
MATCH (n:User)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'journal': """
|
||||
MATCH (n:Journal)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'planner': """
|
||||
MATCH (n:Planner)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - Calendar
|
||||
'day': """
|
||||
MATCH (n:CalendarDay)
|
||||
WHERE date(n.date) = date()
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'year': """
|
||||
MATCH (n:CalendarYear)
|
||||
WHERE n.year = toString(date().year)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - Teaching
|
||||
'timetable': """
|
||||
MATCH (n:UserTeacherTimetable)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'classes': """
|
||||
MATCH (n:Class)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'lessons': """
|
||||
MATCH (n:TimetableLesson)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - School
|
||||
'departments': """
|
||||
MATCH (n:Department)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'staff': """
|
||||
MATCH (n:Teacher)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - Department
|
||||
'teachers': """
|
||||
MATCH (n:Teacher)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
'subjects': """
|
||||
MATCH (n:Subject)
|
||||
RETURN n LIMIT 1
|
||||
""",
|
||||
|
||||
# Extended Contexts - Class
|
||||
'students': """
|
||||
MATCH (n:Student)
|
||||
RETURN n LIMIT 1
|
||||
"""
|
||||
}
|
||||
|
||||
if context not in context_queries:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid context: {context}")
|
||||
|
||||
query = context_queries[context]
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
# For overview context, we need to pass the database name as a parameter
|
||||
params = {'db_name': db_name, 'base_context': base_context} if context == 'overview' else {}
|
||||
result = session.run(query, params)
|
||||
record = result.single()
|
||||
|
||||
if not record:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"No default node found for context: {context}"
|
||||
)
|
||||
|
||||
node = record["n"]
|
||||
node_data = dict(node)
|
||||
|
||||
# Convert Neo4j types to JSON-serializable types
|
||||
converted_data = convert_neo4j_values(node_data)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"node": {
|
||||
"id": node["unique_id"],
|
||||
"path": node["path"],
|
||||
"type": list(node.labels)[0],
|
||||
"label": node.get("title", ""),
|
||||
"data": converted_data
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting default node: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
@@ -0,0 +1,101 @@
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
load_dotenv(find_dotenv())
|
||||
import os
|
||||
import modules.logger_tool as logger
|
||||
log_name = 'api_routers_calendar_get_events'
|
||||
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'
|
||||
)
|
||||
import modules.database.tools.neo4j_driver_tools as driver
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import colorsys
|
||||
import random
|
||||
|
||||
# Predefined vibrant color palette
|
||||
BASE_COLORS = [
|
||||
"#FF4136", "#FF851B", "#FFDC00", "#2ECC40", "#0074D9", "#B10DC9",
|
||||
"#F012BE", "#FF6F61", "#7FDBFF", "#01FF70", "#001f3f", "#85144b",
|
||||
"#39CCCC", "#3D9970", "#e74c3c", "#e67e22", "#f1c40f", "#2ecc71",
|
||||
"#1abc9c", "#3498db", "#9b59b6", "#34495e", "#16a085", "#27ae60",
|
||||
"#2980b9", "#8e44ad", "#2c3e50", "#d35400", "#c0392b", "#bdc3c7",
|
||||
"#7f8c8d", "#00a86b", "#8B4513", "#4B0082", "#800000", "#1E90FF"
|
||||
]
|
||||
|
||||
def generate_vibrant_color():
|
||||
h = random.random()
|
||||
s = 0.5 + random.random() * 0.5 # 0.5 to 1.0
|
||||
v = 0.5 + random.random() * 0.5 # 0.5 to 1.0
|
||||
r, g, b = [int(x * 255) for x in colorsys.hsv_to_rgb(h, s, v)]
|
||||
return f"#{r:02x}{g:02x}{b:02x}"
|
||||
|
||||
# Extend the color palette
|
||||
EXTENDED_COLOR_PALETTE = BASE_COLORS + [generate_vibrant_color() for _ in range(100)]
|
||||
|
||||
def get_subject_class_color(subject_class):
|
||||
# Use a hash function to generate a unique number for each subject class
|
||||
hash_value = hash(subject_class)
|
||||
|
||||
# Use the hash to select a color from the extended palette
|
||||
color_index = hash_value % len(EXTENDED_COLOR_PALETTE)
|
||||
color = EXTENDED_COLOR_PALETTE[color_index]
|
||||
|
||||
return color
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/get_teacher_timetable_events")
|
||||
async def get_teacher_timetable_events(
|
||||
unique_id: str,
|
||||
worker_db_name: str
|
||||
):
|
||||
logging.info(f"Getting timetable events for teacher {unique_id} from database {worker_db_name}")
|
||||
neo_driver = driver.get_driver(db_name=worker_db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=worker_db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (t:Teacher {unique_id: $unique_id})-[:TEACHER_HAS_TIMETABLE]->(tt:TeacherTimetable)
|
||||
-[:TIMETABLE_HAS_CLASS]->(sc:SubjectClass)-[:CLASS_HAS_LESSON]->(tl:TimetableLesson)
|
||||
RETURN tl.unique_id as id,
|
||||
tl.period_code as period_code,
|
||||
COALESCE(sc.subject_class_code, 'Untitled Class') as subject_class,
|
||||
tl.date as date,
|
||||
tl.start_time as start_time,
|
||||
tl.end_time as end_time,
|
||||
tl.path as path
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
|
||||
events = []
|
||||
for record in result:
|
||||
start = f"{record['date']}T{record['start_time']}"
|
||||
end = f"{record['date']}T{record['end_time']}"
|
||||
title = f"{record['subject_class']}"
|
||||
events.append({
|
||||
"id": record["id"],
|
||||
"title": title,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"groupId": f"subject-class-{record['subject_class']}",
|
||||
"extendedProps": {
|
||||
"subjectClass": record['subject_class'],
|
||||
"color": get_subject_class_color(record['subject_class']),
|
||||
"periodCode": record['period_code'],
|
||||
"path": record['path']
|
||||
}
|
||||
})
|
||||
logging.info(f"Found {len(events)} events for teacher {unique_id}")
|
||||
return {"status": "success", "events": events}
|
||||
except Exception as e:
|
||||
logging.error(f"Error fetching events: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
@@ -0,0 +1,563 @@
|
||||
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_get_nodes'
|
||||
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'
|
||||
)
|
||||
import modules.database.tools.neo4j_driver_tools as driver
|
||||
import modules.database.tools.neo4j_session_tools as session
|
||||
from modules.database.schemas.nodes.calendars import CalendarNode
|
||||
from modules.database.schemas.nodes.schools.timetable import SchoolTimetableNode, AcademicYearNode, AcademicTermNode, AcademicWeekNode, AcademicDayNode, AcademicPeriodNode, RegistrationPeriodNode
|
||||
from modules.database.schemas.nodes.users import UserNode
|
||||
from modules.database.schemas.nodes.workers.workers import TeacherNode, StudentNode, DeveloperNode, SchoolAdminNode
|
||||
from modules.database.schemas.nodes.schools.schools import SchoolNode, DepartmentNode, SubjectClassNode, RoomNode
|
||||
from modules.database.schemas.nodes.workers.timetable import TeacherTimetableNode, TimetableLessonNode, PlannedLessonNode, UserTeacherTimetableNode
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/get-node")
|
||||
async def get_node(unique_id: str = Query(...), db_name: str = Query(...)):
|
||||
logging.info(f"Getting node for {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n {unique_id: $unique_id})
|
||||
RETURN n
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
|
||||
if record:
|
||||
node = record['n']
|
||||
node_labels = list(node.labels)
|
||||
node_data = dict(node)
|
||||
|
||||
try:
|
||||
# Convert node based on its type
|
||||
node_type = node_labels[0] if node_labels else "Unknown"
|
||||
if node_type in globals():
|
||||
node_class = globals()[f"{node_type}Node"]
|
||||
node_object = node_class(**node_data)
|
||||
node_dict = node_object.to_dict()
|
||||
else:
|
||||
node_dict = node_data
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"node": {
|
||||
"node_type": node_type,
|
||||
"node_data": node_dict
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
return {
|
||||
"status": "error",
|
||||
"message": "Error processing node data",
|
||||
"details": str(e)
|
||||
}
|
||||
else:
|
||||
return {"status": "not_found", "message": "Node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving node: {str(e)}")
|
||||
return {"status": "error", "message": "Internal server error"}
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-user-node")
|
||||
async def get_user_node(user_id: str = Query(...)):
|
||||
db_name = f"cc.users.{user_id}"
|
||||
logging.info(f"Getting user node for user {user_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
nodes = session.find_nodes_by_label_and_properties(neo_session, "User", {"user_id": user_id})
|
||||
if nodes:
|
||||
user_node = nodes[0]
|
||||
data = UserNode(**user_node)
|
||||
user_node_data = data.to_dict()
|
||||
return {"status": "success", "user_node": user_node_data, "user_node_raw": nodes}
|
||||
else:
|
||||
return {"status": "not_found", "message": "User node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving user node: {str(e)}")
|
||||
return {"status": "error", "message": "Internal server error"}
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-connected-nodes")
|
||||
async def get_connected_nodes(unique_id: str = Query(...), db_name: str = Query(...)):
|
||||
logging.info(f"Getting connected nodes for {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n {unique_id: $unique_id})
|
||||
OPTIONAL MATCH (n)-[]-(connected)
|
||||
RETURN n, collect(connected) as connected_nodes
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
if record:
|
||||
main_node = record['n']
|
||||
connected_nodes = record['connected_nodes']
|
||||
|
||||
main_node_labels = list(main_node.labels)
|
||||
main_node_type = main_node_labels[0] if main_node_labels else "Unknown"
|
||||
main_node_data = dict(main_node)
|
||||
|
||||
try:
|
||||
main_node_class = globals()[f"{main_node_type}Node"]
|
||||
main_node_object = main_node_class(**main_node_data)
|
||||
main_node_dict = main_node_object.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting main node to dict: {str(e)}")
|
||||
main_node_dict = main_node_data
|
||||
|
||||
connected_nodes_list = []
|
||||
|
||||
for node in connected_nodes:
|
||||
node_labels = list(node.labels)
|
||||
node_type = node_labels[0] if node_labels else "Unknown"
|
||||
node_data = dict(node)
|
||||
try:
|
||||
node_class = globals()[f"{node_type}Node"]
|
||||
node_object = node_class(**node_data)
|
||||
connected_node_dict = node_object.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting connected node to dict: {str(e)}")
|
||||
connected_node_dict = node_data
|
||||
|
||||
connected_node_info = {
|
||||
"node_type": node_type,
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
|
||||
logging.debug(f"connected_nodes_list: {connected_nodes_list}")
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"main_node": {
|
||||
"node_type": main_node_type,
|
||||
"node_data": main_node_dict
|
||||
},
|
||||
"connected_nodes": connected_nodes_list
|
||||
}
|
||||
else:
|
||||
return {"status": "not_found", "message": "Node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving connected nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-user-connected-nodes")
|
||||
async def get_user_connected_nodes(unique_id: str = Query(...)):
|
||||
logging.info(f"Getting user adjacent nodes for node {unique_id}")
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai") # TODO: This function needs to be able to take a db_name as a parameter
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
raise HTTPException(status_code=500, detail="Failed to connect to the database")
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
user_node_and_connected_nodes = session.get_node_by_unique_id_and_adjacent_nodes(neo_session, unique_id)
|
||||
user_node = user_node_and_connected_nodes['node']
|
||||
connected_nodes = user_node_and_connected_nodes['connected_nodes']
|
||||
try:
|
||||
data = UserNode(**user_node)
|
||||
user_node_dict = data.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting user node to dict: {str(e)}")
|
||||
connected_nodes_list = []
|
||||
for connected_node in connected_nodes:
|
||||
node_data = connected_node['node']
|
||||
node_labels = list(node_data.labels)
|
||||
logging.debug(f"node_labels: {node_labels}")
|
||||
for label in node_labels:
|
||||
logging.debug(f"label: {label}")
|
||||
try:
|
||||
if 'Developer' == label:
|
||||
logging.debug(f"Developer node found")
|
||||
node_object = DeveloperNode(**node_data)
|
||||
elif 'SchoolAdmin' == label:
|
||||
logging.debug(f"SchoolAdmin node found")
|
||||
node_object = SchoolAdminNode(**node_data)
|
||||
elif 'Teacher' == label:
|
||||
logging.debug(f"Teacher node found")
|
||||
node_object = TeacherNode(**node_data)
|
||||
elif 'Student' == label:
|
||||
logging.debug(f"Student node found")
|
||||
node_object = StudentNode(**node_data)
|
||||
elif 'Calendar' == label:
|
||||
logging.debug(f"Calendar node found")
|
||||
node_object = CalendarNode(**node_data)
|
||||
elif 'TeacherTimetable' == label:
|
||||
logging.debug(f"TeacherTimetable node found")
|
||||
node_object = TeacherTimetableNode(**node_data)
|
||||
elif 'UserTeacherTimetable' == label:
|
||||
logging.debug(f"UserTeacherTimetable node found")
|
||||
node_object = UserTeacherTimetableNode(**node_data)
|
||||
elif 'School' == label:
|
||||
logging.debug(f"School node found")
|
||||
node_object = SchoolNode(**node_data)
|
||||
elif 'Department' == label:
|
||||
logging.debug(f"Department node found")
|
||||
node_object = DepartmentNode(**node_data)
|
||||
elif 'Student' == label:
|
||||
logging.debug(f"Student node found")
|
||||
node_object = StudentNode(**node_data)
|
||||
elif 'Class' == label:
|
||||
logging.debug(f"Class node found")
|
||||
node_object = SubjectClassNode(**node_data)
|
||||
elif 'Room' == label:
|
||||
logging.debug(f"Room node found")
|
||||
node_object = RoomNode(**node_data)
|
||||
else:
|
||||
logging.error(f"Unknown node label: {node_labels}")
|
||||
continue
|
||||
connected_node_dict = node_object.to_dict()
|
||||
logging.debug(f"connected_node_dict: {connected_node_dict}")
|
||||
connected_node_info = {
|
||||
"node_type": label,
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
return {"status": "success", "user_node": user_node_dict, "user_connected_nodes": connected_nodes_list}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving adjacent nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-worker-connected-nodes")
|
||||
async def get_worker_connected_nodes(unique_id: str = Query(...)):
|
||||
logging.info(f"Getting worker adjacent nodes for node {unique_id}")
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai") # TODO: This function needs to be able to take a db_name as a parameter
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
raise HTTPException(status_code=500, detail="Failed to connect to the database")
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
node_and_connected_nodes = session.get_node_by_unique_id_and_adjacent_nodes(neo_session, unique_id)
|
||||
worker_node = node_and_connected_nodes['node']
|
||||
connected_nodes = node_and_connected_nodes['connected_nodes']
|
||||
try:
|
||||
data = TeacherNode(**worker_node)
|
||||
worker_node_dict = data.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting user node to dict: {str(e)}")
|
||||
connected_nodes_list = []
|
||||
for connected_node in connected_nodes:
|
||||
node_data = connected_node['node']
|
||||
node_labels = list(node_data.labels)
|
||||
logging.debug(f"node_labels: {node_labels}")
|
||||
for label in node_labels:
|
||||
logging.debug(f"label: {label}")
|
||||
try:
|
||||
if 'Calendar' == label:
|
||||
logging.debug(f"Calendar node found")
|
||||
node_object = CalendarNode(**node_data)
|
||||
elif 'TeacherTimetable' == label:
|
||||
logging.debug(f"TeacherTimetable node found")
|
||||
node_object = TeacherTimetableNode(**node_data)
|
||||
elif 'UserTeacherTimetable' == label:
|
||||
logging.debug(f"UserTeacherTimetable node found")
|
||||
node_object = UserTeacherTimetableNode(**node_data)
|
||||
elif 'School' == label:
|
||||
logging.debug(f"School node found")
|
||||
node_object = SchoolNode(**node_data)
|
||||
elif 'Department' == label:
|
||||
logging.debug(f"Department node found")
|
||||
node_object = DepartmentNode(**node_data)
|
||||
elif 'Student' == label:
|
||||
logging.debug(f"Student node found")
|
||||
node_object = StudentNode(**node_data)
|
||||
elif 'Class' == label:
|
||||
logging.debug(f"Class node found")
|
||||
node_object = SubjectClassNode(**node_data)
|
||||
elif 'Room' == label:
|
||||
logging.debug(f"Room node found")
|
||||
node_object = RoomNode(**node_data)
|
||||
else:
|
||||
logging.error(f"Unknown node label: {node_labels}")
|
||||
continue
|
||||
connected_node_dict = node_object.to_dict()
|
||||
logging.debug(f"connected_node_dict: {connected_node_dict}")
|
||||
connected_node_info = {
|
||||
"node_type": label,
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
return {"status": "success", "user_node": worker_node_dict, "worker_connected_nodes": connected_nodes_list}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving worker adjacent nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-calendar-connected-nodes")
|
||||
async def get_calendar_connected_nodes(unique_id: str = Query(...)):
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai")
|
||||
logging.info(f"Getting connected nodes for calendar {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n)
|
||||
WHERE n.unique_id = $unique_id AND (n:Calendar OR n:CalendarYear OR n:CalendarMonth OR n:CalendarWeek OR n:CalendarDay OR n:CalendarTimeChunk)
|
||||
OPTIONAL MATCH (n)-[]-(connected)
|
||||
RETURN n, collect(connected) as connected_nodes
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
if record:
|
||||
calendar_node = record['n']
|
||||
connected_nodes = record['connected_nodes']
|
||||
|
||||
node_type = list(calendar_node.labels)[0]
|
||||
calendar_dict = globals()[f"{node_type}Node"](**calendar_node).to_dict()
|
||||
connected_nodes_list = []
|
||||
|
||||
for node in connected_nodes:
|
||||
node_labels = list(node.labels)
|
||||
node_data = dict(node)
|
||||
try:
|
||||
node_class = globals()[f"{node_labels[0]}Node"]
|
||||
node_object = node_class(**node_data)
|
||||
connected_node_dict = node_object.to_dict()
|
||||
connected_node_info = {
|
||||
"node_type": node_labels[0],
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
|
||||
return {"status": "success", "calendar_node": calendar_dict, "connected_nodes": connected_nodes_list}
|
||||
else:
|
||||
return {"status": "not_found", "message": "Calendar node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving connected nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-teacher-timetable-connected-nodes")
|
||||
async def get_teacher_timetable_connected_nodes(unique_id: str = Query(...)):
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai")
|
||||
logging.info(f"Getting connected nodes for teacher timetable {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n:TeacherTimetable {unique_id: $unique_id})
|
||||
OPTIONAL MATCH (n)-[]-(connected)
|
||||
RETURN n, collect(connected) as connected_nodes
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
if record:
|
||||
teacher_timetable_node = record['n']
|
||||
connected_nodes = record['connected_nodes']
|
||||
|
||||
teacher_timetable_dict = TeacherTimetableNode(**teacher_timetable_node).to_dict()
|
||||
connected_nodes_list = []
|
||||
|
||||
for node in connected_nodes:
|
||||
node_labels = list(node.labels)
|
||||
node_data = dict(node)
|
||||
try:
|
||||
if 'TimetableLesson' in node_labels:
|
||||
node_object = TimetableLessonNode(**node_data)
|
||||
elif 'PlannedLesson' in node_labels:
|
||||
node_object = PlannedLessonNode(**node_data)
|
||||
else:
|
||||
logging.error(f"Unknown node label: {node_labels}")
|
||||
continue
|
||||
connected_node_dict = node_object.to_dict()
|
||||
connected_node_info = {
|
||||
"node_type": node_labels[0],
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
|
||||
return {"status": "success", "teacher_timetable_node": teacher_timetable_dict, "connected_nodes": connected_nodes_list}
|
||||
else:
|
||||
return {"status": "not_found", "message": "Teacher timetable node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving connected nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-school-timetable-connected-nodes")
|
||||
async def get_school_timetable_connected_nodes(unique_id: str = Query(...)):
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai")
|
||||
logging.info(f"Getting connected nodes for school timetable {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n:SchoolTimetable {unique_id: $unique_id})
|
||||
OPTIONAL MATCH (n)-[]-(connected)
|
||||
RETURN n, collect(connected) as connected_nodes
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
if record:
|
||||
school_timetable_node = record['n']
|
||||
connected_nodes = record['connected_nodes']
|
||||
|
||||
school_timetable_dict = SchoolTimetableNode(**school_timetable_node).to_dict()
|
||||
connected_nodes_list = []
|
||||
|
||||
for node in connected_nodes:
|
||||
node_labels = list(node.labels)
|
||||
node_data = dict(node)
|
||||
try:
|
||||
if 'AcademicYear' in node_labels:
|
||||
node_object = AcademicYearNode(**node_data)
|
||||
elif 'AcademicTerm' in node_labels:
|
||||
node_object = AcademicTermNode(**node_data)
|
||||
elif 'AcademicWeek' in node_labels:
|
||||
node_object = AcademicWeekNode(**node_data)
|
||||
elif 'AcademicDay' in node_labels:
|
||||
node_object = AcademicDayNode(**node_data)
|
||||
elif 'AcademicPeriod' in node_labels:
|
||||
node_object = AcademicPeriodNode(**node_data)
|
||||
elif 'RegistrationPeriod' in node_labels:
|
||||
node_object = RegistrationPeriodNode(**node_data)
|
||||
else:
|
||||
logging.error(f"Unknown node label: {node_labels}")
|
||||
continue
|
||||
connected_node_dict = node_object.to_dict()
|
||||
connected_node_info = {
|
||||
"node_type": node_labels[0],
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
|
||||
return {"status": "success", "school_timetable_node": school_timetable_dict, "connected_nodes": connected_nodes_list}
|
||||
else:
|
||||
return {"status": "not_found", "message": "School timetable node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving connected nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-curriculum-connected-nodes")
|
||||
async def get_curriculum_connected_nodes(unique_id: str = Query(...)):
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai")
|
||||
logging.info(f"Getting connected nodes for curriculum {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n)
|
||||
WHERE n.unique_id = $unique_id AND (n:PastoralStructure OR n:YearGroup OR n:CurriculumStructure OR n:KeyStage OR n:KeyStageSyllabus OR n:YearGroupSyllabus OR n:Subject OR n:Topic OR n:TopicLesson OR n:LearningStatement OR n:ScienceLab)
|
||||
OPTIONAL MATCH (n)-[]-(connected)
|
||||
RETURN n, collect(connected) as connected_nodes
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
if record:
|
||||
curriculum_node = record['n']
|
||||
connected_nodes = record['connected_nodes']
|
||||
|
||||
node_type = list(curriculum_node.labels)[0]
|
||||
curriculum_dict = globals()[f"{node_type}Node"](**curriculum_node).to_dict()
|
||||
connected_nodes_list = []
|
||||
|
||||
for node in connected_nodes:
|
||||
node_labels = list(node.labels)
|
||||
node_data = dict(node)
|
||||
try:
|
||||
node_class = globals()[f"{node_labels[0]}Node"]
|
||||
node_object = node_class(**node_data)
|
||||
connected_node_dict = node_object.to_dict()
|
||||
connected_node_info = {
|
||||
"node_type": node_labels[0],
|
||||
"node_data": connected_node_dict
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
|
||||
return {"status": "success", "curriculum_node": curriculum_dict, "connected_nodes": connected_nodes_list}
|
||||
else:
|
||||
return {"status": "not_found", "message": "Curriculum node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving connected nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
@router.get("/get-school-node")
|
||||
async def get_school_node(school_uuid: str = Query(...)):
|
||||
logging.info(f"Getting school node for school {school_uuid}...")
|
||||
db_name = f"cc.institutes.{school_uuid}"
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
nodes = session.find_nodes_by_label_and_properties(neo_session, "School", {"school_uuid": school_uuid})
|
||||
if nodes:
|
||||
school_node = nodes[0]
|
||||
data = SchoolNode(
|
||||
unique_id=school_node["unique_id"],
|
||||
school_uuid=school_node["school_uuid"],
|
||||
school_name=school_node["school_name"],
|
||||
school_website=school_node["school_website"],
|
||||
path=school_node["path"]
|
||||
)
|
||||
school_node_data = data.to_dict()
|
||||
return {"status": "success", "school_node": school_node_data, "school_node_raw": nodes}
|
||||
else:
|
||||
return {"status": "not_found", "message": "School node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving school node: {str(e)}")
|
||||
return {"status": "error", "message": "Internal server error"}
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
@@ -0,0 +1,174 @@
|
||||
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_get_nodes'
|
||||
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'
|
||||
)
|
||||
import modules.database.tools.neo4j_driver_tools as driver
|
||||
import modules.database.tools.neo4j_session_tools as session
|
||||
from modules.database.schemas.nodes.calendars import CalendarNode, CalendarYearNode, CalendarMonthNode, CalendarWeekNode, CalendarDayNode, CalendarTimeChunkNode
|
||||
from modules.database.schemas.nodes.users import UserNode
|
||||
from modules.database.schemas.nodes.workers.workers import TeacherNode, StudentNode, DeveloperNode, SchoolAdminNode
|
||||
from modules.database.schemas.nodes.structures.schools import PastoralStructureNode, CurriculumStructureNode
|
||||
from modules.database.schemas.nodes.schools.pastoral import YearGroupNode, YearGroupSyllabusNode
|
||||
from modules.database.schemas.nodes.schools.curriculum import SubjectNode, TopicNode, TopicLessonNode, LearningStatementNode, ScienceLabNode
|
||||
from modules.database.schemas.nodes.schools.timetable import SchoolTimetableNode, AcademicYearNode, AcademicTermNode, AcademicWeekNode, AcademicDayNode, OffTimetableDayNode, StaffDayNode, AcademicPeriodNode, RegistrationPeriodNode, OffTimetablePeriodNode, AcademicTermBreakNode, BreakPeriodNode, HolidayDayNode, HolidayWeekNode
|
||||
from modules.database.schemas.nodes.workers.timetable import TeacherTimetableNode, TimetableLessonNode, PlannedLessonNode, UserTeacherTimetableNode, StudentTimetableNode, SchoolAdminTimetableNode, DeveloperTimetableNode, SuperAdminTimetableNode
|
||||
from modules.database.schemas.nodes.schools.schools import SchoolNode, DepartmentNode, SubjectClassNode, RoomNode
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/get-all-nodes-and-edges")
|
||||
async def get_all_nodes_and_edges():
|
||||
db_name = os.getenv("NEO4J_DB_NAME", "cc.institutes.kevlarai")
|
||||
logging.info(f"Getting all nodes and edges from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n)-[r]->(m)
|
||||
RETURN n, r, m
|
||||
"""
|
||||
result = neo_session.run(query)
|
||||
nodes = {}
|
||||
relationships = []
|
||||
|
||||
for record in result:
|
||||
source = record['n']
|
||||
target = record['m']
|
||||
relationship = record['r']
|
||||
|
||||
for node in [source, target]:
|
||||
if node.id not in nodes:
|
||||
node_labels = list(node.labels)
|
||||
node_type = node_labels[0] if node_labels else "Unknown"
|
||||
node_data = dict(node)
|
||||
try:
|
||||
node_class = globals()[f"{node_type}Node"]
|
||||
node_object = node_class(**node_data)
|
||||
node_dict = node_object.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting node to dict: {str(e)}")
|
||||
node_dict = node_data
|
||||
|
||||
nodes[node.id] = {
|
||||
"node_type": node_type,
|
||||
"node_data": node_dict
|
||||
}
|
||||
|
||||
relationship_info = {
|
||||
"start_node": source.id,
|
||||
"end_node": target.id,
|
||||
"relationship_type": relationship.type,
|
||||
"relationship_properties": dict(relationship)
|
||||
}
|
||||
relationships.append(relationship_info)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"nodes": list(nodes.values()),
|
||||
"relationships": relationships
|
||||
}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving all nodes and edges: {str(e)}")
|
||||
return {"status": "error", "message": "Internal server error"}
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
|
||||
|
||||
@router.get("/get-connected-nodes-and-edges")
|
||||
async def get_connected_nodes_and_edges(unique_id: str = Query(...), db_name: str = Query(...)):
|
||||
logging.info(f"Getting connected nodes and edges for {unique_id} from database {db_name}")
|
||||
neo_driver = driver.get_driver(db_name=db_name)
|
||||
if neo_driver is None:
|
||||
return {"status": "error", "message": "Failed to connect to the database"}
|
||||
|
||||
try:
|
||||
with neo_driver.session(database=db_name) as neo_session:
|
||||
query = """
|
||||
MATCH (n {unique_id: $unique_id})
|
||||
OPTIONAL MATCH (n)-[r]-(connected)
|
||||
RETURN n, collect(connected) as connected_nodes, collect(r) as relationships
|
||||
"""
|
||||
result = neo_session.run(query, unique_id=unique_id)
|
||||
record = result.single()
|
||||
if record:
|
||||
main_node = record['n']
|
||||
connected_nodes = record['connected_nodes']
|
||||
relationships = record['relationships']
|
||||
|
||||
main_node_labels = list(main_node.labels)
|
||||
main_node_type = main_node_labels[0] if main_node_labels else "Unknown"
|
||||
main_node_data = dict(main_node)
|
||||
|
||||
try:
|
||||
main_node_class = globals()[f"{main_node_type}Node"]
|
||||
main_node_object = main_node_class(**main_node_data)
|
||||
main_node_dict = main_node_object.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting main node to dict: {str(e)}")
|
||||
main_node_dict = main_node_data
|
||||
|
||||
connected_nodes_list = []
|
||||
relationship_list = []
|
||||
|
||||
for node, relationship in zip(connected_nodes, relationships):
|
||||
node_labels = list(node.labels)
|
||||
node_type = node_labels[0] if node_labels else "Unknown"
|
||||
node_data = dict(node)
|
||||
try:
|
||||
node_class = globals()[f"{node_type}Node"]
|
||||
node_object = node_class(**node_data)
|
||||
connected_node_dict = node_object.to_dict()
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting connected node to dict: {str(e)}")
|
||||
connected_node_dict = node_data
|
||||
|
||||
connected_node_info = {
|
||||
"node_type": node_type,
|
||||
"node_data": connected_node_dict,
|
||||
"relationship_type": relationship.type, # Get relationship type
|
||||
"relationship_properties": dict(relationship) # Relationship properties, if any
|
||||
}
|
||||
connected_nodes_list.append(connected_node_info)
|
||||
|
||||
relationship_info = {
|
||||
"start_node": dict(relationship.start_node),
|
||||
"end_node": dict(relationship.end_node),
|
||||
"relationship_type": relationship.type,
|
||||
"relationship_properties": dict(relationship)
|
||||
}
|
||||
relationship_list.append(relationship_info)
|
||||
|
||||
logging.info(f"Main node: {main_node_dict}")
|
||||
logging.info(f"Connected nodes: {connected_nodes_list}")
|
||||
logging.info(f"Relationships: {relationship_list}")
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"main_node": {
|
||||
"node_type": main_node_type,
|
||||
"node_data": main_node_dict
|
||||
},
|
||||
"connected_nodes": connected_nodes_list,
|
||||
"relationships": relationship_list
|
||||
}
|
||||
else:
|
||||
return {"status": "not_found", "message": "Node not found"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error retrieving connected nodes: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
finally:
|
||||
driver.close_driver(neo_driver)
|
||||
@@ -0,0 +1,3 @@
|
||||
import os
|
||||
from modules.logger_tool import initialise_logger
|
||||
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
|
||||
@@ -0,0 +1,196 @@
|
||||
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}")
|
||||
|
||||
# Handle path based on environment
|
||||
if os.getenv("DEV_MODE") == "true":
|
||||
# In dev mode, use the full system path from the node
|
||||
if not user_node.path:
|
||||
raise HTTPException(status_code=400, detail="Node path not found")
|
||||
logging.debug(f"Using DEV_MODE path: {user_node.path}")
|
||||
base_path = os.path.normpath(user_node.path)
|
||||
else:
|
||||
# In prod mode, construct path using formatted email
|
||||
logging.warning(f"Using db_name as base path not ready in prod: {db_name}")
|
||||
base_path = formatted_email
|
||||
|
||||
# Construct final path including tldraw file
|
||||
logging.debug(f"Base path: {base_path}")
|
||||
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:
|
||||
logging.debug(f"File does not exist: {file_location}")
|
||||
raise HTTPException(status_code=404, detail="File 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")
|
||||
|
||||
# Handle path based on environment
|
||||
if os.getenv("ENVIRONMENT") == "dev":
|
||||
# In dev mode, use the full system path from the node
|
||||
if not user_node.path:
|
||||
raise HTTPException(status_code=400, detail="Node path not found")
|
||||
base_path = os.path.normpath(user_node.path)
|
||||
else:
|
||||
# In prod mode, construct path using formatted email
|
||||
base_path = formatted_email
|
||||
|
||||
# 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
|
||||
os.makedirs(os.path.dirname(file_location), exist_ok=True)
|
||||
|
||||
# Write the file
|
||||
with open(file_location, "w") as file:
|
||||
json.dump(data, file)
|
||||
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}")
|
||||
|
||||
fs = ClassroomCopilotFilesystem(db_name=db_name, init_run_type="user")
|
||||
|
||||
logging.debug(f"Filesystem root path: {fs.root_path}")
|
||||
|
||||
# Handle path based on environment
|
||||
if os.getenv("DEV_MODE") == "true":
|
||||
# In dev mode, use the full system path from the node
|
||||
if not path:
|
||||
raise HTTPException(status_code=400, detail="Path not provided")
|
||||
logging.debug(f"Using DEV_MODEpath: {path}")
|
||||
base_path = os.path.normpath(path)
|
||||
else:
|
||||
# In prod mode, construct path
|
||||
logging.warning(f"Using db_name as base path not ready in prod: {db_name}")
|
||||
base_path = db_name
|
||||
|
||||
# Construct final path including tldraw file
|
||||
logging.debug(f"Base path: {base_path}")
|
||||
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:
|
||||
logging.debug(f"File does not exist: {file_location}")
|
||||
raise HTTPException(status_code=404, detail="File 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}")
|
||||
|
||||
# Handle path based on environment
|
||||
if os.getenv("DEV_MODE") == "true":
|
||||
# In dev mode, use the full system path from the node
|
||||
if not path:
|
||||
raise HTTPException(status_code=400, detail="Path not provided")
|
||||
logging.debug(f"Using DEV_MODEpath: {path}")
|
||||
base_path = os.path.normpath(path)
|
||||
else:
|
||||
# In prod mode, construct path
|
||||
logging.warning(f"Using db_name as base path not ready in prod: {db_name}")
|
||||
base_path = db_name
|
||||
|
||||
# Construct final path including tldraw file
|
||||
logging.debug(f"Base path: {base_path}")
|
||||
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 set file at: {file_location}")
|
||||
|
||||
try:
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(file_location), exist_ok=True)
|
||||
|
||||
# Write the file
|
||||
with open(file_location, "w") as file:
|
||||
json.dump(data, file)
|
||||
return {"status": "success"}
|
||||
except Exception as e:
|
||||
logging.error(f"Error writing file: {e}")
|
||||
raise HTTPException(status_code=500, detail="Error writing file")
|
||||
@@ -0,0 +1,190 @@
|
||||
import os
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from typing import List, Dict, Any, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from modules.logger_tool import initialise_logger
|
||||
from modules.database.tools import neo4j_driver_tools as driver_tools
|
||||
|
||||
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/get-worker-structure")
|
||||
async def get_worker_structure(db_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get the complete worker structure including timetables, classes, lessons, journals, and planners.
|
||||
"""
|
||||
try:
|
||||
# Get all worker-related nodes in a single query
|
||||
query = """
|
||||
// Match all worker-related nodes
|
||||
MATCH (t:Teacher)
|
||||
OPTIONAL MATCH (t)-[:TEACHER_HAS_TIMETABLE]->(tt:UserTeacherTimetable)
|
||||
OPTIONAL MATCH (t)-[:TEACHER_HAS_CLASS]->(c:Class)
|
||||
OPTIONAL MATCH (t)-[:TEACHER_HAS_LESSON]->(l:TimetableLesson)
|
||||
OPTIONAL MATCH (t)-[:TEACHER_HAS_JOURNAL]->(j:Journal)
|
||||
OPTIONAL MATCH (t)-[:TEACHER_HAS_PLANNER]->(p:Planner)
|
||||
WITH t, tt, c, l, j, p
|
||||
ORDER BY tt.start_date, c.created, l.created, j.created, p.created
|
||||
|
||||
// Collect all nodes
|
||||
RETURN {
|
||||
timetables: collect(DISTINCT {
|
||||
id: tt.unique_id,
|
||||
path: tt.path,
|
||||
title: tt.title,
|
||||
type: tt.__primarylabel__,
|
||||
startTime: toString(tt.start_date),
|
||||
endTime: toString(tt.end_date)
|
||||
}),
|
||||
classes: collect(DISTINCT {
|
||||
id: c.unique_id,
|
||||
path: c.path,
|
||||
title: c.title,
|
||||
type: c.__primarylabel__
|
||||
}),
|
||||
lessons: collect(DISTINCT {
|
||||
id: l.unique_id,
|
||||
path: l.path,
|
||||
title: l.title,
|
||||
type: l.__primarylabel__
|
||||
}),
|
||||
journals: collect(DISTINCT {
|
||||
id: j.unique_id,
|
||||
path: j.path,
|
||||
title: j.title,
|
||||
type: j.__primarylabel__
|
||||
}),
|
||||
planners: collect(DISTINCT {
|
||||
id: p.unique_id,
|
||||
path: p.path,
|
||||
title: p.title,
|
||||
type: p.__primarylabel__
|
||||
})
|
||||
} as structure
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query)
|
||||
record = result.single()
|
||||
if not record:
|
||||
raise HTTPException(status_code=404, detail="Worker structure not found")
|
||||
|
||||
structure = record["structure"]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"data": {
|
||||
"timetables": {
|
||||
"default": structure["timetables"]
|
||||
},
|
||||
"classes": {
|
||||
"default": structure["classes"]
|
||||
},
|
||||
"lessons": {
|
||||
"default": structure["lessons"]
|
||||
},
|
||||
"journals": {
|
||||
"default": structure["journals"]
|
||||
},
|
||||
"planners": {
|
||||
"default": structure["planners"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting worker structure: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-timetables")
|
||||
async def get_timetables(db_name: str, start_date: str, end_date: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all timetables in a date range.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (tt:UserTeacherTimetable)
|
||||
WHERE date(tt.start_date) >= date($start_date) AND date(tt.end_date) <= date($end_date)
|
||||
RETURN {
|
||||
id: tt.unique_id,
|
||||
path: tt.path,
|
||||
title: tt.title,
|
||||
type: tt.__primarylabel__,
|
||||
startTime: toString(tt.start_date),
|
||||
endTime: toString(tt.end_date)
|
||||
} as timetable
|
||||
ORDER BY tt.start_date
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query, start_date=start_date, end_date=end_date)
|
||||
timetables = [record["timetable"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"timetables": timetables
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting timetables: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-journals")
|
||||
async def get_journals(db_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all journals.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (j:Journal)
|
||||
RETURN {
|
||||
id: j.unique_id,
|
||||
path: j.path,
|
||||
title: j.title,
|
||||
type: j.__primarylabel__
|
||||
} as journal
|
||||
ORDER BY j.created
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query)
|
||||
journals = [record["journal"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"journals": journals
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting journals: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/get-planners")
|
||||
async def get_planners(db_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get all planners.
|
||||
"""
|
||||
try:
|
||||
query = """
|
||||
MATCH (p:Planner)
|
||||
RETURN {
|
||||
id: p.unique_id,
|
||||
path: p.path,
|
||||
title: p.title,
|
||||
type: p.__primarylabel__
|
||||
} as planner
|
||||
ORDER BY p.created
|
||||
"""
|
||||
|
||||
with driver_tools.get_session(database=db_name) as session:
|
||||
result = session.run(query)
|
||||
planners = [record["planner"] for record in result]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"planners": planners
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting planners: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user