""" Database operations for CodiMD CLI. Direct database access for admin operations not exposed via API. """ import json from typing import List, Dict, Any, Optional from pathlib import Path class CodiMDDatabase: """Direct database access for CodiMD.""" @staticmethod def list_users_sqlite(db_path: str) -> List[Dict[str, Any]]: """List users from SQLite database.""" try: import sqlite3 except ImportError: raise ImportError("sqlite3 required for SQLite access") conn = sqlite3.connect(db_path) conn.row_factory = sqlite3.Row cursor = conn.cursor() cursor.execute(""" SELECT id, email, profile, createdAt, updatedAt FROM Users ORDER BY createdAt DESC """) users = [] for row in cursor.fetchall(): user = dict(row) # Parse profile JSON if it's a string if user.get('profile') and isinstance(user['profile'], str): try: user['profile'] = json.loads(user['profile']) except: pass users.append(user) conn.close() return users @staticmethod def list_users_postgresql(host: str, database: str, user: str, password: str, port: int = 5432) -> List[Dict[str, Any]]: """List users from PostgreSQL database.""" try: import psycopg2 except ImportError: raise ImportError("psycopg2 required for PostgreSQL access") conn = psycopg2.connect( host=host, database=database, user=user, password=password, port=port ) cursor = conn.cursor() cursor.execute(""" SELECT id, email, profile, "createdAt", "updatedAt" FROM "Users" ORDER BY "createdAt" DESC """) users = [] for row in cursor.fetchall(): user = { 'id': row[0], 'email': row[1], 'profile': row[2], 'createdAt': row[3], 'updatedAt': row[4] } # Parse profile JSON if it's a string if user.get('profile') and isinstance(user['profile'], str): try: user['profile'] = json.loads(user['profile']) except: pass users.append(user) conn.close() return users @staticmethod def list_users_mysql(host: str, database: str, user: str, password: str, port: int = 3306) -> List[Dict[str, Any]]: """List users from MySQL/MariaDB database.""" try: import mysql.connector except ImportError: raise ImportError("mysql-connector-python required for MySQL access") conn = mysql.connector.connect( host=host, database=database, user=user, password=password, port=port ) cursor = conn.cursor(dictionary=True) cursor.execute(""" SELECT id, email, profile, createdAt, updatedAt FROM Users ORDER BY createdAt DESC """) users = cursor.fetchall() # Parse profile JSON for user in users: if user.get('profile') and isinstance(user['profile'], str): try: user['profile'] = json.loads(user['profile']) except: pass conn.close() return users @staticmethod def list_user_notes_sqlite(db_path: str, user_id: str) -> List[Dict[str, Any]]: """List notes for a specific user from SQLite database.""" try: import sqlite3 except ImportError: raise ImportError("sqlite3 required for SQLite access") conn = sqlite3.connect(db_path) conn.row_factory = sqlite3.Row cursor = conn.cursor() cursor.execute(""" SELECT id, shortid, alias, title, permission, "lastchangeAt", "createdAt", viewcount FROM Notes WHERE "ownerId" = ? ORDER BY "lastchangeAt" DESC """, (user_id,)) notes = [dict(row) for row in cursor.fetchall()] conn.close() return notes