Files
loogle-scripts/services/loogle-mcp/app/db.py
T

119 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
"""SQLite schema for Loogle MCP Hub."""
import os
import sqlite3
import threading
DB_PATH = os.environ.get("MCP_DB", "/data/loogle_mcp.db")
_local = threading.local()
SCHEMA = """
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
is_admin INTEGER NOT NULL DEFAULT 0,
must_change_password INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS oauth_clients (
client_id TEXT PRIMARY KEY,
client_name TEXT NOT NULL,
redirect_uris TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS oauth_codes (
code TEXT PRIMARY KEY,
client_id TEXT NOT NULL,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
redirect_uri TEXT NOT NULL,
scope TEXT NOT NULL,
code_challenge TEXT,
code_challenge_method TEXT,
expires_at TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS refresh_tokens (
token TEXT PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
client_id TEXT NOT NULL,
scope TEXT NOT NULL,
expires_at TEXT NOT NULL,
revoked INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS revoked_jtis (
jti TEXT PRIMARY KEY,
revoked_at TEXT NOT NULL DEFAULT (datetime('now')),
expires_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
tool_name TEXT NOT NULL,
resource_id TEXT,
detail TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now','localtime'))
);
CREATE TABLE IF NOT EXISTS indexed_documents (
doc_id INTEGER PRIMARY KEY,
title TEXT,
owner TEXT,
visibility TEXT NOT NULL DEFAULT 'family',
indexed_at TEXT NOT NULL DEFAULT (datetime('now')),
chunk_count INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS indexed_gitea_files (
repo TEXT NOT NULL,
path TEXT NOT NULL,
sha TEXT,
owner TEXT NOT NULL,
visibility TEXT NOT NULL DEFAULT 'family',
chunk_count INTEGER NOT NULL DEFAULT 0,
indexed_at TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (repo, path)
);
CREATE INDEX IF NOT EXISTS idx_gitea_indexed_repo ON indexed_gitea_files(repo);
CREATE INDEX IF NOT EXISTS idx_gitea_indexed_at ON indexed_gitea_files(indexed_at DESC);
CREATE TABLE IF NOT EXISTS indexed_apps_records (
source TEXT NOT NULL,
record_id TEXT NOT NULL,
title TEXT,
owner TEXT NOT NULL DEFAULT 'family',
chunk_count INTEGER NOT NULL DEFAULT 0,
indexed_at TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (source, record_id)
);
CREATE INDEX IF NOT EXISTS idx_apps_indexed_source ON indexed_apps_records(source);
CREATE INDEX IF NOT EXISTS idx_apps_indexed_at ON indexed_apps_records(indexed_at DESC);
CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_log(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_oauth_codes_expires ON oauth_codes(expires_at);
"""
def get_conn() -> sqlite3.Connection:
conn = getattr(_local, "conn", None)
if conn is None:
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH, timeout=30)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("PRAGMA foreign_keys=ON")
_local.conn = conn
return conn
def init_db() -> None:
get_conn().executescript(SCHEMA)