Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Telegram Bot for notifying new questions #1198

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

edomora97
Copy link
Contributor

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.

image

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`).
Comment on lines +207 to +212
if bool(self.telegram_bot_token) ^ bool(self.telegram_bot_chat_id):
raise ConfigError("Both telegram_bot_token and telegram_bot_chat_id "
"should be set or left null")
if self.telegram_bot_chat_id:
if type(self.telegram_bot_chat_id) != int:
raise ConfigError("telegram_bot_chat_id should be an integer")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks are probably better moved together with the other Telegram code to improve locality. This should be easier with the below suggestion.

@andreyv
Copy link
Member

andreyv commented Dec 13, 2021

Thanks for the feature!

I feel it might not be the best solution to put Telegram message sending directly in ContestWebServer:

  1. This is not directly related to ContestWebServer (or CMS core) functionality.
  2. The notification is not retried if it fails.
  3. 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.

@edomora97
Copy link
Contributor Author

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?

@magula
Copy link
Contributor

magula commented Dec 13, 2021

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.

@andreyv
Copy link
Member

andreyv commented Dec 13, 2021

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.

@stefano-maggiolo
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants