import sqlite3 import json import os import uuid from datetime import datetime # Database path for GTM projects DB_PATH = os.environ.get("GTM_DB_PATH", "/app/gtm_projects.db") def get_db_connection(): """Establishes a connection to the SQLite database.""" conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn def init_gtm_db(): """Initializes the database and creates the gtm_projects table if it doesn't exist.""" try: conn = get_db_connection() # A flexible schema to store project-related data in a single JSON column conn.execute(''' CREATE TABLE IF NOT EXISTS gtm_projects ( id TEXT PRIMARY KEY, name TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, data JSON NOT NULL ) ''') conn.commit() finally: if conn: conn.close() def create_project(name): """Creates a new project with a given name and returns the new project's ID.""" conn = get_db_connection() try: project_id = str(uuid.uuid4()) initial_data = {"id": project_id, "name": name, "phases": {}} conn.execute( 'INSERT INTO gtm_projects (id, name, data) VALUES (?, ?, ?)', (project_id, name, json.dumps(initial_data)) ) conn.commit() return {"id": project_id, "name": name} finally: if conn: conn.close() def update_project_name(project_id, new_name): """Updates the name of an existing project.""" conn = get_db_connection() try: conn.execute( 'UPDATE gtm_projects SET name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', (new_name, project_id) ) conn.commit() return {"id": project_id, "name": new_name, "status": "updated"} finally: if conn: conn.close() def save_gtm_result(project_id, phase, result): """Saves or updates the result of a specific phase for a given project.""" conn = get_db_connection() try: # First, load the existing data cursor = conn.cursor() cursor.execute('SELECT data FROM gtm_projects WHERE id = ?', (project_id,)) row = cursor.fetchone() if not row: return {"error": "Project not found"} project_data = json.loads(row['data']) # Update the specific phase result if 'phases' not in project_data: project_data['phases'] = {} project_data['phases'][phase] = result # Save the updated data back to the DB cursor.execute( '''UPDATE gtm_projects SET data = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?''', (json.dumps(project_data), project_id) ) conn.commit() return {"id": project_id, "status": f"Phase '{phase}' saved successfully."} finally: if conn: conn.close() def get_project_data(project_id): """Retrieves all data for a specific project.""" conn = get_db_connection() try: cursor = conn.cursor() cursor.execute('SELECT data FROM gtm_projects WHERE id = ?', (project_id,)) row = cursor.fetchone() return json.loads(row['data']) if row else None finally: if conn: conn.close() def get_all_projects(): """Lists all projects with key details extracted from the JSON data.""" conn = get_db_connection() try: query = """ SELECT id, name, updated_at, json_extract(data, '$.phases.phase1_result.specs.metadata.model_name') AS productName, json_extract(data, '$.phases.phase1_result.specs.metadata.category') AS productCategory, json_extract(data, '$.phases.phase1_result.specs.metadata.description') AS productDescription, json_extract(data, '$.phases.phase1_result.specs.metadata.manufacturer_url') AS sourceUrl FROM gtm_projects ORDER BY updated_at DESC """ projects = conn.execute(query).fetchall() # Convert row objects to dictionaries, handling potential None values project_list = [] for row in projects: project_dict = dict(row) if project_dict.get('productName') is None: project_dict['productName'] = project_dict['name'] # Fallback to project name if project_dict.get('productCategory') is None: project_dict['productCategory'] = "Uncategorized" # Default category if project_dict.get('productDescription') is None: project_dict['productDescription'] = "No description available." # Default description if project_dict.get('sourceUrl') is None: project_dict['sourceUrl'] = "No source URL found." # Default URL project_list.append(project_dict) return project_list finally: if conn: conn.close() def delete_project(project_id): """Deletes a project by its ID.""" conn = get_db_connection() try: conn.execute('DELETE FROM gtm_projects WHERE id = ?', (project_id,)) conn.commit() return {"status": "deleted", "id": project_id} finally: if conn: conn.close() if __name__ == "__main__": # Simple CLI for testing and potential Node.js bridge # Usage: python gtm_db_manager.py [init|create|save|load|list|delete] [args...] import sys if len(sys.argv) < 2: print(json.dumps({"error": "Mode is required."})) sys.exit(1) mode = sys.argv[1] if mode == "init": init_gtm_db() print(json.dumps({"status": "GTM database initialized"})) elif mode == "create": project_name = sys.argv[2] if len(sys.argv) > 2 else "Untitled GTM Project" print(json.dumps(create_project(project_name))) elif mode == "save": project_id = sys.argv[2] phase = sys.argv[3] result_json = sys.argv[4] print(json.dumps(save_gtm_result(project_id, phase, json.loads(result_json)))) elif mode == "load": project_id = sys.argv[2] project = get_project_data(project_id) print(json.dumps(project if project else {"error": "Project not found"})) elif mode == "list": print(json.dumps(get_all_projects())) elif mode == "delete": project_id = sys.argv[2] print(json.dumps(delete_project(project_id))) else: print(json.dumps({"error": f"Unknown mode: {mode}"}))