kin: BATON-005-backend_dev
This commit is contained in:
parent
68a1c90541
commit
cb95c9928f
7 changed files with 219 additions and 7 deletions
132
backend/db.py
132
backend/db.py
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue