Alerts: a Telegram channel, one chat or group each, connected by a one-time link

The channel sends through the Bot API with httpx only: HTML with escaped text,
cut to fit a message, silent for a warning, a short 429 waited out once, and
errors that say what to do about a blocked bot, a lost chat or a bad token and
never quote the request URL. The bot token is a stored secret: saving a
channel refuses a literal one, the card's "Store token" writes the secret and
a reference, and no endpoint returns it.

A chat id is never typed. Connect starts a ten minute code, and the chat that
sends `/start <code>` back through the bot is the one connected, so it is a
chat somebody opened a link for. The engine fetches updates only while a code
is waiting (no standing poll, no webhook, no inbound address) and ignores
everything else without a reply. Connect needs a saved form, and the form
takes the connected chat in without touching what was typed since.

The token is part of every Bot API URL, so the httpx logger gets the same
filter the request lines have, which now also masks an httpx.URL argument.
This commit is contained in:
2026-10-28 13:06:58 +01:00
parent bfaaa7cd03
commit 5d0ea480bf
14 changed files with 1462 additions and 11 deletions
+1
View File
@@ -220,6 +220,7 @@ reclaiming space sooner.
| `POST` | `/modules/apply` | replace the manifest with `{"requirements": "numpy>=2\n"}` |
| `GET`, `PUT` | `/alerts/config` | read or update alert configuration |
| `POST` | `/alerts/test/{channel}` | test a channel |
| `POST`, `GET`, `DELETE` | `/alerts/telegram/{channel}/link` | start, read or cancel connecting a chat to a telegram channel; the start returns the `t.me` links and never the bot token |
| `GET` | `/alerts/webpush/key` | the key a browser subscribes against; any account |
| `POST` | `/alerts/webpush/subscriptions`, `/alerts/webpush/unsubscribe` | add or remove the calling browser; any account |
+26
View File
@@ -63,10 +63,36 @@ subscribes its own browser to a **webpush** channel.
| **Webhook** | URL that receives a POST |
| **Dashboard** | declared message read by a Notification widget |
| **webpush** | browsers subscribed from the Alerts page |
| **Telegram** | one chat or group, connected from the Alerts page through a bot of your own |
Channel settings may use `{"$secret": "name"}` references. Browser push also
needs notification permission and a secure browser context.
### Telegram
Create a bot with @BotFather and copy its token. Add a **telegram** channel,
paste the token under **Bot token**, press **Store token**, then **Save**. The
token goes to the secrets store and the channel keeps only a reference, which
is the one form the API accepts.
Press **Connect**, open the link in Telegram on the device that should get the
alerts and press Start. **Add to a group** connects a group instead, and
everyone in it reads the alerts. The link works once and runs out after ten
minutes. A chat id is never typed in: the chat that sends the link's code back
is the one connected.
One channel is one chat. To send different events to different people, make
a channel for each and choose them in the rules. A warning arrives without a
sound. If the chat blocks or removes the bot, **Test** and the log say so;
press **Reconnect**.
The engine asks Telegram for updates only while a link is waiting, so it needs
no public address, and anything else sent to the bot is ignored without a
reply. Telegram lets one program fetch a bot's updates at a time, so give each
instance a bot of its own. Starting from a group sends `/start@bot code`;
whether a group in Telegram's default privacy mode delivers it has not been
tried against a live bot, so press **Test** after connecting one.
### Rules
A rule selects events and destination channels. Leaving all events unchecked