Profiles/bots (profiles.py, main.py): - Surface real send errors; fix group send and member-count staleness (refresh on view) - Group/channel actions: join, leave, owner delete; consistent member counts - Contacts: always-visible Chat, plus Clear chat and Delete contact - Support bot: OpenAI-compatible LLM backend (Grok/Ollama/OpenAI) per-bot config - Deadmans bot: check-in window, trigger message, recipients, owner - Directory bot: add-to-group registration, super-user /approve /reject /list, search, publishes listing.json in the website schema (directory.py registry module) - Profile edit (name/bio/avatar) + avatars on list pages - Global status + /network page (operators, SMP/XFTP servers) and Settings network info UI (templates): - Chat rooms; collapsible left sidebar with notifications + network widget - Per-directory-bot website generated on creation (name substituted) - Matrix theme; copy/hyperlink addresses; site footer Ignore runtime bot state and generated directory sites. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
"""Profile registry — SQLite database for manager state."""
|
|
|
|
import sqlite3
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
DB_PATH = Path(__file__).parent / "data" / "manager.db"
|
|
|
|
|
|
def get_conn() -> sqlite3.Connection:
|
|
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
return conn
|
|
|
|
|
|
def init_db() -> None:
|
|
with get_conn() as conn:
|
|
conn.executescript("""
|
|
CREATE TABLE IF NOT EXISTS profiles (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
bot_type TEXT NOT NULL,
|
|
db_prefix TEXT NOT NULL UNIQUE,
|
|
config TEXT NOT NULL DEFAULT '{}',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
address TEXT
|
|
);
|
|
""")
|
|
|
|
|
|
def list_profiles() -> list[dict]:
|
|
with get_conn() as conn:
|
|
rows = conn.execute("SELECT * FROM profiles ORDER BY id").fetchall()
|
|
return [dict(r) for r in rows]
|
|
|
|
|
|
def get_profile(profile_id: int) -> dict | None:
|
|
with get_conn() as conn:
|
|
row = conn.execute("SELECT * FROM profiles WHERE id=?", (profile_id,)).fetchone()
|
|
return dict(row) if row else None
|
|
|
|
|
|
def create_profile(name: str, bot_type: str, config: dict) -> dict:
|
|
safe = name.lower().replace(" ", "_")
|
|
db_prefix = f"data/bots/{safe}"
|
|
Path(db_prefix).parent.mkdir(parents=True, exist_ok=True)
|
|
with get_conn() as conn:
|
|
conn.execute(
|
|
"INSERT INTO profiles (name, bot_type, db_prefix, config) VALUES (?,?,?,?)",
|
|
(name, bot_type, db_prefix, json.dumps(config)),
|
|
)
|
|
row = conn.execute("SELECT * FROM profiles WHERE name=?", (name,)).fetchone()
|
|
return dict(row)
|
|
|
|
|
|
def update_address(profile_id: int, address: str) -> None:
|
|
with get_conn() as conn:
|
|
conn.execute("UPDATE profiles SET address=? WHERE id=?", (address, profile_id))
|
|
|
|
|
|
def update_config(profile_id: int, config: dict) -> None:
|
|
with get_conn() as conn:
|
|
conn.execute(
|
|
"UPDATE profiles SET config=? WHERE id=?", (json.dumps(config), profile_id)
|
|
)
|
|
|
|
|
|
def delete_profile(profile_id: int) -> None:
|
|
with get_conn() as conn:
|
|
conn.execute("DELETE FROM profiles WHERE id=?", (profile_id,))
|