t-261013113629: маршрутизация ответов TG в чат-источник — chat_type/chat_title в MessageReceived, дефолтный чат уведомлений = личка Alex (chat_id>0 фолбэк для старых записей); тест 11 PASS (группа→группа, личка→личка, смешанный батч, дефолт)
This commit is contained in:
parent
5a889e42a4
commit
5b1d30a0ff
2 changed files with 131 additions and 1 deletions
|
|
@ -264,6 +264,11 @@ def receive_message(update: dict):
|
||||||
data = {
|
data = {
|
||||||
"update_id": update["update_id"],
|
"update_id": update["update_id"],
|
||||||
"chat_id": chat.get("id"),
|
"chat_id": chat.get("id"),
|
||||||
|
# t-261013113629: тип чата (private/group/supergroup/channel) и название —
|
||||||
|
# маршрутизация ответов в чат-источник (группа vs личка) и дефолтный
|
||||||
|
# чат уведомлений (личка Alex, а не последняя активная группа)
|
||||||
|
"chat_type": chat.get("type"),
|
||||||
|
"chat_title": chat.get("title"),
|
||||||
# tg message_id нужен для setMessageReaction (реакция «seen», e-261002202857):
|
# tg message_id нужен для setMessageReaction (реакция «seen», e-261002202857):
|
||||||
# update_id ≠ message_id (глобальный стрим vs чат), фолбэк — старый hash
|
# update_id ≠ message_id (глобальный стрим vs чат), фолбэк — старый hash
|
||||||
"message_id": msg.get("message_id"),
|
"message_id": msg.get("message_id"),
|
||||||
|
|
@ -547,7 +552,20 @@ def _default_chat_id():
|
||||||
and not m.get("ignored")]
|
and not m.get("ignored")]
|
||||||
if not inbox:
|
if not inbox:
|
||||||
return None # некому: чат ещё не известен
|
return None # некому: чат ещё не известен
|
||||||
return sorted(inbox, key=lambda m: m.get("ts") or "")[-1]["chat_id"]
|
# t-261013113629: уведомления/файлы — в ЛИЧКУ Alex, а не в последний
|
||||||
|
# активный чат (иначе ответ в группе делает её дефолтом, и файлы/дайджесты
|
||||||
|
# уходят всем участникам группы). Личный чат = private по chat_type;
|
||||||
|
# старые записи без chat_type — chat_id > 0 (у групп он отрицательный).
|
||||||
|
def _is_private(m):
|
||||||
|
if m.get("chat_type"):
|
||||||
|
return m.get("chat_type") == "private"
|
||||||
|
try: # старые записи без chat_type: у групп chat_id < 0
|
||||||
|
return int(m.get("chat_id")) > 0
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return False
|
||||||
|
privates = [m for m in inbox if _is_private(m)]
|
||||||
|
pool = privates or inbox
|
||||||
|
return sorted(pool, key=lambda m: m.get("ts") or "")[-1]["chat_id"]
|
||||||
|
|
||||||
|
|
||||||
def _post_multipart(method: str, fields: dict, file_path: str,
|
def _post_multipart(method: str, fields: dict, file_path: str,
|
||||||
|
|
|
||||||
112
tests/test_reply_routing.py
Normal file
112
tests/test_reply_routing.py
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""t-261013113629: маршрутизация ответов TG — ответ уходит в чат-источник.
|
||||||
|
|
||||||
|
Проверяет: ответ на сообщение из ГРУППЫ уходит в группу, из ЛИЧКИ — в личку;
|
||||||
|
send_batch_reply разбивает смешанный батч по чатам (не смешивает разговоры);
|
||||||
|
notify_chat/_default_chat_id выбирает личку Alex, даже если последнее
|
||||||
|
активное сообщение — из группы (старые записи без chat_type → chat_id<0).
|
||||||
|
|
||||||
|
Запуск: ./venv/bin/python tests/test_reply_routing.py
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_DST = "/tmp/simbiot-test-reply-routing.db"
|
||||||
|
for p in (_DST, _DST + "-wal", _DST + "-shm"):
|
||||||
|
if os.path.exists(p):
|
||||||
|
os.unlink(p)
|
||||||
|
os.environ["SIMBIOT_DB"] = _DST
|
||||||
|
sys.path.insert(0, "/root/simbiot-harness")
|
||||||
|
|
||||||
|
from harness import es, tg_inbox
|
||||||
|
|
||||||
|
fails = []
|
||||||
|
|
||||||
|
|
||||||
|
def check(name, cond, extra=""):
|
||||||
|
print(("PASS" if cond else "FAIL") + " " + name + (" | " + extra if not cond else ""))
|
||||||
|
if not cond:
|
||||||
|
fails.append(name)
|
||||||
|
|
||||||
|
|
||||||
|
def _recv(update_id, text, chat_id, chat_type, chat_title=None, date=1780000000):
|
||||||
|
chat = {"id": chat_id, "type": chat_type}
|
||||||
|
if chat_title:
|
||||||
|
chat["title"] = chat_title
|
||||||
|
tg_inbox.receive_message({"update_id": update_id, "message": {
|
||||||
|
"message_id": update_id % 100000, "date": date, "chat": chat,
|
||||||
|
"from": {"id": 1, "username": "alex", "first_name": "Alex"}, "text": text}})
|
||||||
|
|
||||||
|
|
||||||
|
es.init_db()
|
||||||
|
|
||||||
|
PRIVATE_ID = 424242 # личка Alex (>0)
|
||||||
|
GROUP_ID = -100999 # группа (<0)
|
||||||
|
|
||||||
|
# ── 1. send_reply: ответ в чат-источник (группа → группа, личка → личка) ──
|
||||||
|
_recv(900, "вопрос в личке", PRIVATE_ID, "private", date=1780000000)
|
||||||
|
_recv(901, "вопрос в группе", GROUP_ID, "supergroup", "Кооп 42", date=1780000001)
|
||||||
|
|
||||||
|
sends, actions = [], []
|
||||||
|
tg_inbox.send_message = lambda chat_id, text, reply_to=None, timeout=35: (
|
||||||
|
sends.append((chat_id, text)) or {"ok": True})
|
||||||
|
tg_inbox._api = lambda method, params, timeout=35: (
|
||||||
|
actions.append((method, params.get("chat_id"))) or {"ok": True})
|
||||||
|
|
||||||
|
tg_inbox.send_reply("m-900", "ответ в личку")
|
||||||
|
check("send_reply: личка → личка", sends and sends[-1][0] == PRIVATE_ID, str(sends))
|
||||||
|
tg_inbox.send_reply("m-901", "ответ в группу")
|
||||||
|
check("send_reply: группа → группа", sends and sends[-1][0] == GROUP_ID, str(sends))
|
||||||
|
model = es.run_projections()
|
||||||
|
check("send_reply: оба закрыты (replied)",
|
||||||
|
model["inbox"]["m-900"]["replied"] and model["inbox"]["m-901"]["replied"])
|
||||||
|
check("send_reply: chat_type сохранён",
|
||||||
|
model["inbox"]["m-901"]["chat_type"] == "supergroup"
|
||||||
|
and model["inbox"]["m-901"]["chat_title"] == "Кооп 42")
|
||||||
|
# реплай ушёл именно в чат-источник — проверено по sends выше; здесь — что
|
||||||
|
# ReplySent-событие тоже адресовано группе (to_chat)
|
||||||
|
_last = [e for e in es.get_events()
|
||||||
|
if e.get("event_type") == "ReplySent" and e.get("aggregate_id") == "m-901"]
|
||||||
|
check("send_reply: ReplySent-событие адресовано группе",
|
||||||
|
bool(_last) and str(GROUP_ID) in _last[-1]["data"], str(_last[-1:]))
|
||||||
|
|
||||||
|
# ── 2. send_batch_reply: смешанный батч НЕ смешивает чаты ──
|
||||||
|
_recv(910, "группа: первое", GROUP_ID, "group", "Кооп 42", date=1780000010)
|
||||||
|
_recv(911, "группа: второе", GROUP_ID, "group", "Кооп 42", date=1780000011)
|
||||||
|
_recv(912, "личка: первое", PRIVATE_ID, "private", date=1780000012)
|
||||||
|
|
||||||
|
sends.clear()
|
||||||
|
head = tg_inbox.send_batch_reply(["m-910", "m-911", "m-912"], "Сводный ответ")
|
||||||
|
sent_chats = sorted(c for c, _ in sends)
|
||||||
|
check("send_batch_reply: ДВЕ отправки (по числу чатов)", len(sends) == 2, str(sends))
|
||||||
|
check("send_batch_reply: ответ в группу ушёл в группу",
|
||||||
|
sends and any(c == GROUP_ID for c, _ in sends), str(sends))
|
||||||
|
check("send_batch_reply: ответ в личку ушёл в личку",
|
||||||
|
sends and any(c == PRIVATE_ID for c, _ in sends), str(sends))
|
||||||
|
model = es.run_projections()
|
||||||
|
check("send_batch_reply: все 3 закрыты",
|
||||||
|
all(model["inbox"][f"m-91{i}"]["replied"] for i in (0, 1, 2)))
|
||||||
|
|
||||||
|
# ── 3. _default_chat_id: дефолт — личка, не последняя группа ──
|
||||||
|
# последнее сообщение по ts — из группы (m-912 личка раньше m-911? нет:
|
||||||
|
# m-912 новее). Добавим ещё более новую группу, чтобы проверить приоритет.
|
||||||
|
_recv(920, "самое свежее — из группы", GROUP_ID, "group", "Кооп 42", date=1780000020)
|
||||||
|
default = tg_inbox._default_chat_id()
|
||||||
|
check("_default_chat_id: личка Alex, а не свежая группа",
|
||||||
|
default == PRIVATE_ID, str(default))
|
||||||
|
|
||||||
|
# старые записи без chat_type: группа = chat_id < 0
|
||||||
|
es.append_event("inbox", "m-930", "MessageReceived", {
|
||||||
|
"update_id": 930, "chat_id": PRIVATE_ID, "text": "старая личка без типа",
|
||||||
|
"kind": "text", "ts": "2026-10-13T10:00:00+00:00"})
|
||||||
|
es.append_event("inbox", "m-931", "MessageReceived", {
|
||||||
|
"update_id": 931, "chat_id": GROUP_ID, "text": "старая группа без типа",
|
||||||
|
"kind": "text", "ts": "2026-10-13T10:01:00+00:00"})
|
||||||
|
default = tg_inbox._default_chat_id()
|
||||||
|
check("_default_chat_id: без chat_type — тоже личка (chat_id>0)",
|
||||||
|
default == PRIVATE_ID, str(default))
|
||||||
|
|
||||||
|
# только группы — фолбэк на группу (лучше, чем None)
|
||||||
|
print()
|
||||||
|
print("FAILS:", fails if fails else "нет")
|
||||||
|
sys.exit(1 if fails else 0)
|
||||||
Loading…
Reference in a new issue