feat(api,userbot,frontend): add accounts from the web ui and isolate per-account settings
This commit is contained in:
@@ -110,10 +110,24 @@ async def get_policy(pool: asyncpg.Pool, policy_id: int) -> PolicyRecord | None:
|
||||
return PolicyRecord(**dict(row)) if row else None
|
||||
|
||||
|
||||
async def find_policy(
|
||||
pool: asyncpg.Pool, account_id: int, scope_type: ScopeType, scope_id: int | None
|
||||
) -> PolicyRecord | None:
|
||||
row = await pool.fetchrow(
|
||||
"SELECT * FROM capture_policy WHERE account_id = $1 AND scope_type = $2 "
|
||||
"AND scope_id IS NOT DISTINCT FROM $3",
|
||||
account_id,
|
||||
scope_type.value,
|
||||
scope_id,
|
||||
)
|
||||
return PolicyRecord(**dict(row)) if row else None
|
||||
|
||||
|
||||
async def list_policies(pool: asyncpg.Pool, account_id: int) -> list[PolicyRecord]:
|
||||
rows = await pool.fetch(
|
||||
"SELECT * FROM capture_policy WHERE account_id = $1 OR account_id IS NULL "
|
||||
"ORDER BY scope_type, scope_id",
|
||||
"SELECT DISTINCT ON (scope_type, scope_id) * FROM capture_policy "
|
||||
"WHERE account_id = $1 OR account_id IS NULL "
|
||||
"ORDER BY scope_type, scope_id, account_id NULLS LAST",
|
||||
account_id,
|
||||
)
|
||||
return [PolicyRecord(**dict(row)) for row in rows]
|
||||
@@ -131,6 +145,22 @@ async def update_policy(
|
||||
return PolicyRecord(**dict(row)) if row else None
|
||||
|
||||
|
||||
async def override_policy(
|
||||
pool: asyncpg.Pool, policy_id: int, account_id: int, toggles: CaptureToggles
|
||||
) -> PolicyRecord | None:
|
||||
record = await get_policy(pool, policy_id)
|
||||
if record is None:
|
||||
return None
|
||||
if record.account_id == account_id:
|
||||
return await update_policy(pool, policy_id, toggles)
|
||||
existing = await find_policy(pool, account_id, record.scope_type, record.scope_id)
|
||||
if existing is not None:
|
||||
return await update_policy(pool, existing.id, toggles)
|
||||
return await create_policy(
|
||||
pool, account_id, record.scope_type, record.scope_id, toggles
|
||||
)
|
||||
|
||||
|
||||
async def delete_policy(pool: asyncpg.Pool, policy_id: int) -> bool:
|
||||
result = await pool.execute("DELETE FROM capture_policy WHERE id = $1", policy_id)
|
||||
return result.endswith("1")
|
||||
@@ -138,7 +168,8 @@ async def delete_policy(pool: asyncpg.Pool, policy_id: int) -> bool:
|
||||
|
||||
async def load_policy_set(pool: asyncpg.Pool, account_id: int) -> PolicySet:
|
||||
rows = await pool.fetch(
|
||||
"SELECT * FROM capture_policy WHERE account_id = $1 OR account_id IS NULL",
|
||||
"SELECT * FROM capture_policy WHERE account_id = $1 OR account_id IS NULL "
|
||||
"ORDER BY account_id NULLS FIRST",
|
||||
account_id,
|
||||
)
|
||||
policies = PolicySet()
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
import json
|
||||
|
||||
import asyncpg
|
||||
from pyrogram.types import User
|
||||
|
||||
from utils.read.models import AccountView
|
||||
|
||||
ACCOUNTS_CHANGED_CHANNEL = "accounts_changed"
|
||||
|
||||
_ACCOUNT_COLS = "account_id, label, phone, tg_user_id, is_active"
|
||||
|
||||
_UPSERT_ACCOUNT = """
|
||||
INSERT INTO accounts
|
||||
(tg_user_id, label, phone, session_name, is_active, raw, updated_at)
|
||||
VALUES ($1, $2, $3, $4, TRUE, $5::jsonb, now())
|
||||
ON CONFLICT (tg_user_id) DO UPDATE SET
|
||||
label = EXCLUDED.label,
|
||||
phone = EXCLUDED.phone,
|
||||
session_name = EXCLUDED.session_name,
|
||||
is_active = TRUE,
|
||||
raw = EXCLUDED.raw,
|
||||
updated_at = now()
|
||||
RETURNING account_id
|
||||
"""
|
||||
|
||||
|
||||
async def self_user_id(pool: asyncpg.Pool, account_id: int) -> int | None:
|
||||
return await pool.fetchval(
|
||||
@@ -11,7 +32,47 @@ async def self_user_id(pool: asyncpg.Pool, account_id: int) -> int | None:
|
||||
|
||||
async def list_accounts(pool: asyncpg.Pool) -> list[AccountView]:
|
||||
rows = await pool.fetch(
|
||||
"SELECT account_id, label, phone, tg_user_id, is_active FROM accounts "
|
||||
"ORDER BY account_id"
|
||||
f"SELECT {_ACCOUNT_COLS} FROM accounts ORDER BY account_id" # noqa: S608
|
||||
)
|
||||
return [AccountView(**dict(row)) for row in rows]
|
||||
|
||||
|
||||
async def get_account(pool: asyncpg.Pool, account_id: int) -> AccountView | None:
|
||||
row = await pool.fetchrow(
|
||||
f"SELECT {_ACCOUNT_COLS} FROM accounts WHERE account_id = $1", # noqa: S608
|
||||
account_id,
|
||||
)
|
||||
return AccountView(**dict(row)) if row else None
|
||||
|
||||
|
||||
async def sync_account(pool: asyncpg.Pool, me: User, session_name: str) -> int:
|
||||
raw = json.dumps(
|
||||
{
|
||||
"id": me.id,
|
||||
"first_name": me.first_name,
|
||||
"last_name": me.last_name,
|
||||
"username": me.username,
|
||||
"phone_number": me.phone_number,
|
||||
}
|
||||
)
|
||||
label = " ".join(filter(None, [me.first_name, me.last_name])) or me.username
|
||||
return await pool.fetchval(
|
||||
_UPSERT_ACCOUNT, me.id, label, me.phone_number, session_name, raw
|
||||
)
|
||||
|
||||
|
||||
async def deactivate_account(pool: asyncpg.Pool, account_id: int) -> str | None:
|
||||
return await pool.fetchval(
|
||||
"UPDATE accounts SET is_active = FALSE, updated_at = now() "
|
||||
"WHERE account_id = $1 RETURNING session_name",
|
||||
account_id,
|
||||
)
|
||||
|
||||
|
||||
async def inactive_session_names(pool: asyncpg.Pool) -> set[str]:
|
||||
rows = await pool.fetch("SELECT session_name FROM accounts WHERE NOT is_active")
|
||||
return {row["session_name"] for row in rows}
|
||||
|
||||
|
||||
async def notify_accounts_changed(pool: asyncpg.Pool) -> None:
|
||||
await pool.execute("SELECT pg_notify($1, '')", ACCOUNTS_CHANGED_CHANNEL)
|
||||
|
||||
Reference in New Issue
Block a user