cms
cms copied to clipboard
Telegram Bot for notifying new questions
During a contest it might be useful to be notified on the smartphone when a new question arrives. This is especially true for long contests where keeping the admin page open is not really feasible.
This patch sends a Telegram message to a chat when a new question arrives and it is approved (i.e. not too long). It just uses "requests" for interacting with the Telgram API, avoiding additional dependencies and it's disabled by default. The actual notification is sent in a separate greenlet avoiding to slow down the request handler if the Internet connection or the Telegram servers are slow.
To enable the bot you have to set the Telegram token and the chat id in cms.conf (telegram_bot_token
and telegram_bot_chat_id
).
This has been tested by the Italian Olympiads team for many competitions, at least at 2 national rounds and at 10 OIS rounds (olympiads in team). Needless to say that the contest web servers should have access to Internet in order to send the messages.
Thanks for the feature!
I feel it might not be the best solution to put Telegram message sending directly in ContestWebServer
:
- This is not directly related to
ContestWebServer
(or CMS core) functionality. - The notification is not retried if it fails.
- In the future there might be a desire to extend Telegram notifications past what could be done in CWS alone.
An alternative suggestion would be to add a separate service in cmscontrib
. It can get the questions from DB and could keep a timestamp of the last successful notification, if needed.
Perhaps @stefano-maggiolo also has an opinion on this.
Agree, this was more like a proof of concept that tried to minimize the code changes. CWS clearly is not the best place for this feature (especially since in our setup the CWSs don't even have Internet access!).
I'm keen on the idea of a separate service for the Telegram bot, especially since it enables richer features. I'm imagining the possibility to answer to the questions directly from Telegram (again, especially useful for long-running contests).
On the other hand this doesn't look like as simple as making an HTTP request when a question arrives. As you noted, keeping track of which notification has already been sent, noticing when a new question arrives, retrying on failure, and so on is less trivial and may require more invasive changes. For example, should we keep whether a question has been notified in the database? Is it enough to store it in memory and react only on new questions?
I was going to leave a note about this, but now it definitely seems like this should be of interest: @t-lenz had the same idea some time ago and went to the trouble of implementing a feature-rich Telegram Bot (in the German CMS fork, most of it is in this file). This has about every feature we could think of, like allowing you to answer a question or to make an announcement.
It's been very reliable and useful over the last couple of years.
The bot's protocol:
A bot allowing to access clarification requests and announcements
of a CMS contest via Telegram.
/start 〈pwd〉 — tries to bind the bot to the current chat when
used with the correct password; the bot can only be bound to a
single chat at a time and all further binding attempts will be
rejected until the bot service has been restarted
/announce — adds the rest of the message as an announcement to
the current contest; everything before the first line break will
be used as header
/openquestions — shows all unanswered questions of the current
contest
/allquestions — shows all questions of the current contest
(use this with care as it tends to produce quite a lot of output!)
/allannouncements — shows all announcements of the current contest
(use this with care as it could produce quite a lot of output)
/help — prints this message
/purge — deletes all messages sent by the bot during the current
session (standard restrictions apply: no messages older than 48h
will be deleted)
In addition this bot will post all new questions appearing in the
system. You can answer them by replying to the corresponding post
or using the respective inline buttons. Moreover, all answers
given and announcements made via the web interface will also
be posted and you can edit answers by replying to
the corresponding message
EDIT: Sorry, I had mentioned the wrong username and, therefore, person.
As you noted, keeping track of which notification has already been sent, noticing when a new question arrives, retrying on failure, and so on is less trivial and may require more invasive changes. For example, should we keep whether a question has been notified in the database? Is it enough to store it in memory and react only on new questions?
Indeed, it is better to keep this feature isolated, and not alter the DB structure. New (and missed) questions can be found with DB polling, similar to the existing TriggeredService._sweeper_loop()
. About remembering which questions were processed, my suggestion is a single pointer (a timestamp, for example) that points to the last known "good" question. Newer questions are not processed until the pointer moves. This allows to remember the state using a single value and without needing new DB fields. The timestamp can also be stored as an empty file somewhere in <data_dir>/telegram/
for persistence.
I agree on what has been said, a separate service would be nice.
I don't think there is a need to add booleans "has been sent" to the question schema: if the service is running then it is sending new questions, if not, to start it you have to be interacting with CMS and thus you can check the questions there.