237 lines
7.1 KiB
Python
237 lines
7.1 KiB
Python
import aiosqlite
|
|
from config import DB_PATH, STORAGE_DIR
|
|
from paths import final_paths
|
|
|
|
CREATE_GUIDES = """
|
|
CREATE TABLE IF NOT EXISTS guides (
|
|
id TEXT PRIMARY KEY,
|
|
topic TEXT NOT NULL,
|
|
format TEXT NOT NULL,
|
|
instructions TEXT NOT NULL DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'queued',
|
|
progress TEXT,
|
|
error_msg TEXT,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
)
|
|
"""
|
|
|
|
CREATE_BAUSTEINE = """
|
|
CREATE TABLE IF NOT EXISTS bausteine (
|
|
id TEXT PRIMARY KEY,
|
|
topic TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
purpose TEXT NOT NULL DEFAULT '',
|
|
example TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
)
|
|
"""
|
|
|
|
CREATE_SUGGESTIONS = """
|
|
CREATE TABLE IF NOT EXISTS baustein_suggestions (
|
|
id TEXT PRIMARY KEY,
|
|
topic TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
purpose TEXT NOT NULL DEFAULT '',
|
|
example TEXT NOT NULL DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
created_at TEXT NOT NULL
|
|
)
|
|
"""
|
|
|
|
_db: aiosqlite.Connection | None = None
|
|
|
|
|
|
async def get_db() -> aiosqlite.Connection:
|
|
global _db
|
|
if _db is None:
|
|
_db = await aiosqlite.connect(DB_PATH)
|
|
_db.row_factory = None
|
|
return _db
|
|
|
|
|
|
async def init_db():
|
|
db = await get_db()
|
|
await db.execute(CREATE_GUIDES)
|
|
await db.execute(CREATE_BAUSTEINE)
|
|
await db.execute(CREATE_SUGGESTIONS)
|
|
cursor = await db.execute("PRAGMA table_info(guides)")
|
|
columns = {row[1] for row in await cursor.fetchall()}
|
|
if "instructions" not in columns:
|
|
await db.execute("ALTER TABLE guides ADD COLUMN instructions TEXT NOT NULL DEFAULT ''")
|
|
await db.execute(
|
|
"UPDATE guides SET status = 'error', progress = NULL, error_msg = 'Server-Neustart' "
|
|
"WHERE status IN ('queued', 'generating')"
|
|
)
|
|
await db.commit()
|
|
await _migrate_uuid_filenames(db)
|
|
|
|
|
|
async def _migrate_uuid_filenames(db: aiosqlite.Connection) -> None:
|
|
cursor = await db.execute("SELECT id, topic, format FROM guides WHERE status = 'done'")
|
|
rows = await cursor.fetchall()
|
|
for guide_id, topic, format_name in rows:
|
|
final_html, final_pdf = final_paths(topic, format_name)
|
|
old_html = STORAGE_DIR / "html" / f"{guide_id}.html"
|
|
old_pdf = STORAGE_DIR / "pdf" / f"{guide_id}.pdf"
|
|
if old_html.exists() and not final_html.exists():
|
|
old_html.rename(final_html)
|
|
if old_pdf.exists() and not final_pdf.exists():
|
|
old_pdf.rename(final_pdf)
|
|
|
|
|
|
async def close_db():
|
|
global _db
|
|
if _db is not None:
|
|
await _db.close()
|
|
_db = None
|
|
|
|
|
|
def _row_to_dict(row, cursor):
|
|
columns = [d[0] for d in cursor.description]
|
|
return dict(zip(columns, row))
|
|
|
|
|
|
async def create_guide(guide: dict) -> dict:
|
|
db = await get_db()
|
|
await db.execute(
|
|
"""INSERT INTO guides (id, topic, format, instructions, status, progress, created_at, updated_at)
|
|
VALUES (:id, :topic, :format, :instructions, :status, :progress, :created_at, :updated_at)""",
|
|
guide,
|
|
)
|
|
await db.commit()
|
|
return guide
|
|
|
|
|
|
async def get_guide(guide_id: str) -> dict | None:
|
|
db = await get_db()
|
|
cursor = await db.execute("SELECT * FROM guides WHERE id = ?", (guide_id,))
|
|
row = await cursor.fetchone()
|
|
if row is None:
|
|
return None
|
|
return _row_to_dict(row, cursor)
|
|
|
|
|
|
async def list_guides() -> list[dict]:
|
|
db = await get_db()
|
|
cursor = await db.execute("SELECT * FROM guides ORDER BY created_at DESC")
|
|
rows = await cursor.fetchall()
|
|
return [_row_to_dict(row, cursor) for row in rows]
|
|
|
|
|
|
async def update_guide(guide_id: str, **fields) -> None:
|
|
sets = ", ".join(f"{k} = :{k}" for k in fields)
|
|
fields["id"] = guide_id
|
|
db = await get_db()
|
|
await db.execute(f"UPDATE guides SET {sets} WHERE id = :id", fields)
|
|
await db.commit()
|
|
|
|
|
|
async def delete_guide(guide_id: str) -> bool:
|
|
db = await get_db()
|
|
cursor = await db.execute("DELETE FROM guides WHERE id = ?", (guide_id,))
|
|
await db.commit()
|
|
return cursor.rowcount > 0
|
|
|
|
|
|
# --- Bausteine ---
|
|
|
|
async def create_baustein(baustein: dict) -> dict:
|
|
db = await get_db()
|
|
await db.execute(
|
|
"""INSERT INTO bausteine (id, topic, title, description, purpose, example, created_at, updated_at)
|
|
VALUES (:id, :topic, :title, :description, :purpose, :example, :created_at, :updated_at)""",
|
|
baustein,
|
|
)
|
|
await db.commit()
|
|
return baustein
|
|
|
|
|
|
async def list_bausteine(topic: str) -> list[dict]:
|
|
db = await get_db()
|
|
cursor = await db.execute(
|
|
"SELECT * FROM bausteine WHERE topic = ? ORDER BY created_at ASC", (topic,)
|
|
)
|
|
rows = await cursor.fetchall()
|
|
return [_row_to_dict(row, cursor) for row in rows]
|
|
|
|
|
|
async def get_baustein(baustein_id: str) -> dict | None:
|
|
db = await get_db()
|
|
cursor = await db.execute("SELECT * FROM bausteine WHERE id = ?", (baustein_id,))
|
|
row = await cursor.fetchone()
|
|
if row is None:
|
|
return None
|
|
return _row_to_dict(row, cursor)
|
|
|
|
|
|
async def update_baustein(baustein_id: str, **fields) -> None:
|
|
sets = ", ".join(f"{k} = :{k}" for k in fields)
|
|
fields["id"] = baustein_id
|
|
db = await get_db()
|
|
await db.execute(f"UPDATE bausteine SET {sets} WHERE id = :id", fields)
|
|
await db.commit()
|
|
|
|
|
|
async def delete_baustein(baustein_id: str) -> bool:
|
|
db = await get_db()
|
|
cursor = await db.execute("DELETE FROM bausteine WHERE id = ?", (baustein_id,))
|
|
await db.commit()
|
|
return cursor.rowcount > 0
|
|
|
|
|
|
# --- Baustein Suggestions ---
|
|
|
|
async def create_suggestions(suggestions: list[dict]) -> None:
|
|
db = await get_db()
|
|
await db.executemany(
|
|
"""INSERT INTO baustein_suggestions (id, topic, title, description, purpose, example, status, created_at)
|
|
VALUES (:id, :topic, :title, :description, :purpose, :example, :status, :created_at)""",
|
|
suggestions,
|
|
)
|
|
await db.commit()
|
|
|
|
|
|
async def list_suggestions(topic: str) -> list[dict]:
|
|
db = await get_db()
|
|
cursor = await db.execute(
|
|
"SELECT * FROM baustein_suggestions WHERE topic = ? ORDER BY created_at ASC", (topic,)
|
|
)
|
|
rows = await cursor.fetchall()
|
|
return [_row_to_dict(row, cursor) for row in rows]
|
|
|
|
|
|
async def get_suggestion(suggestion_id: str) -> dict | None:
|
|
db = await get_db()
|
|
cursor = await db.execute("SELECT * FROM baustein_suggestions WHERE id = ?", (suggestion_id,))
|
|
row = await cursor.fetchone()
|
|
if row is None:
|
|
return None
|
|
return _row_to_dict(row, cursor)
|
|
|
|
|
|
async def update_suggestion(suggestion_id: str, **fields) -> None:
|
|
sets = ", ".join(f"{k} = :{k}" for k in fields)
|
|
fields["id"] = suggestion_id
|
|
db = await get_db()
|
|
await db.execute(f"UPDATE baustein_suggestions SET {sets} WHERE id = :id", fields)
|
|
await db.commit()
|
|
|
|
|
|
async def delete_suggestion(suggestion_id: str) -> bool:
|
|
db = await get_db()
|
|
cursor = await db.execute("DELETE FROM baustein_suggestions WHERE id = ?", (suggestion_id,))
|
|
await db.commit()
|
|
return cursor.rowcount > 0
|
|
|
|
|
|
async def delete_pending_suggestions(topic: str) -> None:
|
|
db = await get_db()
|
|
await db.execute(
|
|
"DELETE FROM baustein_suggestions WHERE topic = ? AND status = 'pending'", (topic,)
|
|
)
|
|
await db.commit()
|