kin: BATON-005-backend_dev

This commit is contained in:
Gros Frumos 2026-03-20 23:39:28 +02:00
parent 68a1c90541
commit cb95c9928f
7 changed files with 219 additions and 7 deletions

View file

@ -24,10 +24,12 @@ async def init_db() -> None:
async with _get_conn() as conn:
await conn.executescript("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
is_blocked INTEGER NOT NULL DEFAULT 0,
password_hash TEXT DEFAULT NULL,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS signals (
@ -58,6 +60,16 @@ async def init_db() -> None:
CREATE INDEX IF NOT EXISTS idx_batches_status
ON telegram_batches(status);
""")
# Migrations for existing databases (silently ignore if columns already exist)
for stmt in [
"ALTER TABLE users ADD COLUMN is_blocked INTEGER NOT NULL DEFAULT 0",
"ALTER TABLE users ADD COLUMN password_hash TEXT DEFAULT NULL",
]:
try:
await conn.execute(stmt)
await conn.commit()
except Exception:
pass # Column already exists
await conn.commit()
@ -104,6 +116,118 @@ async def get_user_name(uuid: str) -> Optional[str]:
return row["name"] if row else None
async def is_user_blocked(uuid: str) -> bool:
async with _get_conn() as conn:
async with conn.execute(
"SELECT is_blocked FROM users WHERE uuid = ?", (uuid,)
) as cur:
row = await cur.fetchone()
return bool(row["is_blocked"]) if row else False
async def admin_list_users() -> list[dict]:
async with _get_conn() as conn:
async with conn.execute(
"SELECT id, uuid, name, is_blocked, created_at FROM users ORDER BY id"
) as cur:
rows = await cur.fetchall()
return [
{
"id": row["id"],
"uuid": row["uuid"],
"name": row["name"],
"is_blocked": bool(row["is_blocked"]),
"created_at": row["created_at"],
}
for row in rows
]
async def admin_get_user_by_id(user_id: int) -> Optional[dict]:
async with _get_conn() as conn:
async with conn.execute(
"SELECT id, uuid, name, is_blocked, created_at FROM users WHERE id = ?",
(user_id,),
) as cur:
row = await cur.fetchone()
if row is None:
return None
return {
"id": row["id"],
"uuid": row["uuid"],
"name": row["name"],
"is_blocked": bool(row["is_blocked"]),
"created_at": row["created_at"],
}
async def admin_create_user(
uuid: str, name: str, password_hash: Optional[str] = None
) -> Optional[dict]:
"""Returns None if UUID already exists."""
async with _get_conn() as conn:
try:
async with conn.execute(
"INSERT INTO users (uuid, name, password_hash) VALUES (?, ?, ?)",
(uuid, name, password_hash),
) as cur:
new_id = cur.lastrowid
except Exception:
return None # UNIQUE constraint violation — UUID already exists
await conn.commit()
async with conn.execute(
"SELECT id, uuid, name, is_blocked, created_at FROM users WHERE id = ?",
(new_id,),
) as cur:
row = await cur.fetchone()
return {
"id": row["id"],
"uuid": row["uuid"],
"name": row["name"],
"is_blocked": bool(row["is_blocked"]),
"created_at": row["created_at"],
}
async def admin_set_password(user_id: int, password_hash: str) -> bool:
async with _get_conn() as conn:
async with conn.execute(
"UPDATE users SET password_hash = ? WHERE id = ?",
(password_hash, user_id),
) as cur:
changed = cur.rowcount > 0
await conn.commit()
return changed
async def admin_set_blocked(user_id: int, is_blocked: bool) -> bool:
async with _get_conn() as conn:
async with conn.execute(
"UPDATE users SET is_blocked = ? WHERE id = ?",
(1 if is_blocked else 0, user_id),
) as cur:
changed = cur.rowcount > 0
await conn.commit()
return changed
async def admin_delete_user(user_id: int) -> bool:
async with _get_conn() as conn:
# Delete signals first (no FK cascade in SQLite by default)
async with conn.execute(
"DELETE FROM signals WHERE user_uuid = (SELECT uuid FROM users WHERE id = ?)",
(user_id,),
):
pass
async with conn.execute(
"DELETE FROM users WHERE id = ?",
(user_id,),
) as cur:
changed = cur.rowcount > 0
await conn.commit()
return changed
async def save_telegram_batch(
message_text: str,
signals_count: int,