release: dev → main (финальная сдача) #114

Merged
Eleboba merged 12 commits from dev into main 2026-10-05 13:43:38 +03:00
2 changed files with 34 additions and 1 deletions
Showing only changes of commit d662a69c7e - Show all commits
+17
View File
@@ -194,11 +194,28 @@ class TelegramChannel:
await self._dispatch(chat_id, person.token, Event(type="start", params={"code": code})) await self._dispatch(chat_id, person.token, Event(type="start", params={"code": code}))
return return
token = await self.directory.token_for(chat_id) token = await self.directory.token_for(chat_id)
if token is None and get_settings().demo_clock:
token = await self._demo_copy(chat_id)
if token is None: if token is None:
await self._say(chat_id, texts.not_connected) await self._say(chat_id, texts.not_connected)
return return
await self._dispatch(chat_id, token, Event(type="start")) await self._dispatch(chat_id, token, Event(type="start"))
async def _demo_copy(self, chat_id: int) -> str | None:
"""Demo stand (DEMO_CLOCK): `/start` without a code gets a private copy of veteran Andrey (synthetic),
starting from consent and the intake — the same entry as the ЕМИАС demo button of the web app."""
from app.api.patient_web import _fresh_demo_copy
try:
token = (await _fresh_demo_copy(start_in_chat=False)).token
except Exception:
log.exception("start: demo copy failed")
return None
if not await self.directory.bind(chat_id, token):
return None
log.info("start: demo copy bound tok=%s", _short(token))
return token
async def on_text(self, chat_id: int, text: str | None) -> None: async def on_text(self, chat_id: int, text: str | None) -> None:
texts = load_texts() texts = load_texts()
token = await self.directory.token_for(chat_id) token = await self.directory.token_for(chat_id)
+17 -1
View File
@@ -22,6 +22,7 @@ from app.channels.telegram import (
render_markup, render_markup,
split_text, split_text,
) )
from app.config import get_settings
from app.db import identity_repo, session from app.db import identity_repo, session
from app.db.bootstrap import init_db from app.db.bootstrap import init_db
from app.dialog.contracts import Button, Event, Reply from app.dialog.contracts import Button, Event, Reply
@@ -163,7 +164,10 @@ async def test_verified_token_without_identity_record(dbs: None, engine: Recordi
assert sender.texts == [load_texts().code_invalid] assert sender.texts == [load_texts().code_invalid]
async def test_unbound_chat_gets_not_connected(dbs: None, engine: RecordingEngine) -> None: async def test_unbound_chat_gets_not_connected(
dbs: None, engine: RecordingEngine, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(get_settings(), "demo_clock", False)
sender = FakeSender() sender = FakeSender()
channel = TelegramChannel(sender) channel = TelegramChannel(sender)
await channel.on_start(CHAT, None) await channel.on_start(CHAT, None)
@@ -251,6 +255,18 @@ async def test_outbox_pushes_to_bound_chat_and_falls_back(dbs: None, engine: Rec
assert [r.text for r in fallback.drain(TOKEN2)] == ["Как вы сегодня?"] assert [r.text for r in fallback.drain(TOKEN2)] == ["Как вы сегодня?"]
async def test_start_without_code_on_demo_stand_binds_a_demo_copy(
dbs: None, engine: RecordingEngine, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(get_settings(), "demo_clock", True)
sender = FakeSender()
channel = TelegramChannel(sender)
await channel.on_start(CHAT, None)
token = await channel.directory.token_for(CHAT)
assert token is not None and token.startswith("tok-andrey-")
assert [c[1].type for c in engine.calls] == ["start"]
async def test_start_is_noop_without_token(monkeypatch: pytest.MonkeyPatch) -> None: async def test_start_is_noop_without_token(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(telegram, "get_settings", lambda: type("S", (), {"tg_bot_token": ""})()) monkeypatch.setattr(telegram, "get_settings", lambda: type("S", (), {"tg_bot_token": ""})())
before = integrations.outbox before = integrations.outbox