Initial commit
This commit is contained in:
207
server/telegram/triggers.py
Normal file
207
server/telegram/triggers.py
Normal file
@@ -0,0 +1,207 @@
|
||||
"""
|
||||
telegram/triggers.py — CRUD for telegram_triggers and telegram_whitelist tables (async).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from ..database import _rowcount, get_pool
|
||||
|
||||
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
|
||||
# ── Trigger rules ─────────────────────────────────────────────────────────────
|
||||
|
||||
async def list_triggers(user_id: str | None = "GLOBAL") -> list[dict]:
|
||||
"""
|
||||
- user_id="GLOBAL" (default): global triggers (user_id IS NULL)
|
||||
- user_id=None: ALL triggers
|
||||
- user_id="<uuid>": that user's triggers only
|
||||
"""
|
||||
pool = await get_pool()
|
||||
if user_id == "GLOBAL":
|
||||
rows = await pool.fetch(
|
||||
"SELECT t.*, a.name AS agent_name "
|
||||
"FROM telegram_triggers t LEFT JOIN agents a ON a.id = t.agent_id "
|
||||
"WHERE t.user_id IS NULL ORDER BY t.created_at"
|
||||
)
|
||||
elif user_id is None:
|
||||
rows = await pool.fetch(
|
||||
"SELECT t.*, a.name AS agent_name "
|
||||
"FROM telegram_triggers t LEFT JOIN agents a ON a.id = t.agent_id "
|
||||
"ORDER BY t.created_at"
|
||||
)
|
||||
else:
|
||||
rows = await pool.fetch(
|
||||
"SELECT t.*, a.name AS agent_name "
|
||||
"FROM telegram_triggers t LEFT JOIN agents a ON a.id = t.agent_id "
|
||||
"WHERE t.user_id = $1 ORDER BY t.created_at",
|
||||
user_id,
|
||||
)
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
async def create_trigger(
|
||||
trigger_word: str,
|
||||
agent_id: str,
|
||||
description: str = "",
|
||||
enabled: bool = True,
|
||||
user_id: str | None = None,
|
||||
) -> dict:
|
||||
now = _now()
|
||||
trigger_id = str(uuid.uuid4())
|
||||
pool = await get_pool()
|
||||
await pool.execute(
|
||||
"""
|
||||
INSERT INTO telegram_triggers
|
||||
(id, trigger_word, agent_id, description, enabled, user_id, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
""",
|
||||
trigger_id, trigger_word, agent_id, description, enabled, user_id, now, now,
|
||||
)
|
||||
return {
|
||||
"id": trigger_id,
|
||||
"trigger_word": trigger_word,
|
||||
"agent_id": agent_id,
|
||||
"description": description,
|
||||
"enabled": enabled,
|
||||
"user_id": user_id,
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
|
||||
async def update_trigger(id: str, **fields) -> bool:
|
||||
fields["updated_at"] = _now()
|
||||
|
||||
set_parts = []
|
||||
values: list[Any] = []
|
||||
for i, (k, v) in enumerate(fields.items(), start=1):
|
||||
set_parts.append(f"{k} = ${i}")
|
||||
values.append(v)
|
||||
|
||||
id_param = len(fields) + 1
|
||||
values.append(id)
|
||||
|
||||
pool = await get_pool()
|
||||
status = await pool.execute(
|
||||
f"UPDATE telegram_triggers SET {', '.join(set_parts)} WHERE id = ${id_param}",
|
||||
*values,
|
||||
)
|
||||
return _rowcount(status) > 0
|
||||
|
||||
|
||||
async def delete_trigger(id: str) -> bool:
|
||||
pool = await get_pool()
|
||||
status = await pool.execute("DELETE FROM telegram_triggers WHERE id = $1", id)
|
||||
return _rowcount(status) > 0
|
||||
|
||||
|
||||
async def toggle_trigger(id: str) -> None:
|
||||
pool = await get_pool()
|
||||
await pool.execute(
|
||||
"UPDATE telegram_triggers SET enabled = NOT enabled, updated_at = $1 WHERE id = $2",
|
||||
_now(), id,
|
||||
)
|
||||
|
||||
|
||||
async def get_enabled_triggers(user_id: str | None = "GLOBAL") -> list[dict]:
|
||||
"""Return enabled triggers scoped to user_id."""
|
||||
pool = await get_pool()
|
||||
if user_id == "GLOBAL":
|
||||
rows = await pool.fetch(
|
||||
"SELECT * FROM telegram_triggers WHERE enabled = TRUE AND user_id IS NULL"
|
||||
)
|
||||
elif user_id is None:
|
||||
rows = await pool.fetch("SELECT * FROM telegram_triggers WHERE enabled = TRUE")
|
||||
else:
|
||||
rows = await pool.fetch(
|
||||
"SELECT * FROM telegram_triggers WHERE enabled = TRUE AND user_id = $1",
|
||||
user_id,
|
||||
)
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
# ── Chat ID whitelist ─────────────────────────────────────────────────────────
|
||||
|
||||
async def list_whitelist(user_id: str | None = "GLOBAL") -> list[dict]:
|
||||
"""
|
||||
- user_id="GLOBAL" (default): global whitelist (user_id IS NULL)
|
||||
- user_id=None: ALL whitelist entries
|
||||
- user_id="<uuid>": that user's entries
|
||||
"""
|
||||
pool = await get_pool()
|
||||
if user_id == "GLOBAL":
|
||||
rows = await pool.fetch(
|
||||
"SELECT * FROM telegram_whitelist WHERE user_id IS NULL ORDER BY created_at"
|
||||
)
|
||||
elif user_id is None:
|
||||
rows = await pool.fetch("SELECT * FROM telegram_whitelist ORDER BY created_at")
|
||||
else:
|
||||
rows = await pool.fetch(
|
||||
"SELECT * FROM telegram_whitelist WHERE user_id = $1 ORDER BY created_at",
|
||||
user_id,
|
||||
)
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
async def add_to_whitelist(
|
||||
chat_id: str,
|
||||
label: str = "",
|
||||
user_id: str | None = None,
|
||||
) -> dict:
|
||||
now = _now()
|
||||
chat_id = str(chat_id)
|
||||
pool = await get_pool()
|
||||
await pool.execute(
|
||||
"""
|
||||
INSERT INTO telegram_whitelist (chat_id, label, user_id, created_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (chat_id, user_id) NULLS NOT DISTINCT DO UPDATE SET label = EXCLUDED.label
|
||||
""",
|
||||
chat_id, label, user_id, now,
|
||||
)
|
||||
return {"chat_id": chat_id, "label": label, "user_id": user_id, "created_at": now}
|
||||
|
||||
|
||||
async def remove_from_whitelist(chat_id: str, user_id: str | None = "GLOBAL") -> bool:
|
||||
"""Remove whitelist entry. user_id="GLOBAL" deletes only global entry (user_id IS NULL)."""
|
||||
pool = await get_pool()
|
||||
if user_id == "GLOBAL":
|
||||
status = await pool.execute(
|
||||
"DELETE FROM telegram_whitelist WHERE chat_id = $1 AND user_id IS NULL", str(chat_id)
|
||||
)
|
||||
elif user_id is None:
|
||||
status = await pool.execute(
|
||||
"DELETE FROM telegram_whitelist WHERE chat_id = $1", str(chat_id)
|
||||
)
|
||||
else:
|
||||
status = await pool.execute(
|
||||
"DELETE FROM telegram_whitelist WHERE chat_id = $1 AND user_id = $2",
|
||||
str(chat_id), user_id,
|
||||
)
|
||||
return _rowcount(status) > 0
|
||||
|
||||
|
||||
async def is_allowed(chat_id: str | int, user_id: str | None = "GLOBAL") -> bool:
|
||||
"""Check if chat_id is whitelisted. Scoped to user_id (or global if "GLOBAL")."""
|
||||
pool = await get_pool()
|
||||
if user_id == "GLOBAL":
|
||||
row = await pool.fetchrow(
|
||||
"SELECT 1 FROM telegram_whitelist WHERE chat_id = $1 AND user_id IS NULL",
|
||||
str(chat_id),
|
||||
)
|
||||
elif user_id is None:
|
||||
row = await pool.fetchrow(
|
||||
"SELECT 1 FROM telegram_whitelist WHERE chat_id = $1", str(chat_id)
|
||||
)
|
||||
else:
|
||||
row = await pool.fetchrow(
|
||||
"SELECT 1 FROM telegram_whitelist WHERE chat_id = $1 AND user_id = $2",
|
||||
str(chat_id), user_id,
|
||||
)
|
||||
return row is not None
|
||||
Reference in New Issue
Block a user