A Telegram bot which helps Caregroup Leaders in Arrow Ministry tabulate their group attendance.
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
Install pip
apt install pip3
Install Python
apt install python3
Install Telepot framework
pip3 install telepot
Install MongoDB - instructions vary, refer to your server guide on how to.
Install pymongo
pip3 install pymongo
You may use any Python engine to host your bot. I used Digital Ocean with a Linux distro.
- Run the bot using
python3 main.py
2. Run the database using
mongod --dbpath directory/to/database
3. To access your database console at any time, use
mongo acglbot
This assumes you have used acglbot as the name of the database.
Highly recommend for to use screen to run main.py in the background. This enables you to switch terminals at anytime while preserving the functionality of the bot, and also prevent you from losing access to your bot in case you lose connection to the terminal.
We use Telepot, a Python API for Telegram, by Nick Lee (credit below). Telepot adds an extra layer of simplification for us.
Telegram provides webhooks for bots to latch onto their servers. It is different from classic polling in the sense that messages are 'pushed' to the bot from the server, on demand. So the bot will not have to waste resources querying Telegram servers 24/7 and users can get responses as and when they talk to it.
Telegram client --> Telegram server <-- Bot in cloudAll we need to do on our part is to set up the webhook, which Telepot's API handles for us neatly.
// main.py: TOKEN is a unique variable set in settings_secret.py and generated by the BotFather.
bot = telepot.DelegatorBot(TOKEN, [
...
AttendanceBot makes use of Telepot's DelegatorBot
to handle chat events. Each user is given a session with the bot, which expires after 120s of inactivity. This can be modified in this chunk at the bottom:
// main.py
bot = telepot.DelegatorBot(TOKEN, [
pave_event_space()(
per_chat_id(), create_open, ACGLBOT, timeout=120),
])
When a user talks to the bot, on_chat_message()
API method is activated. AttendanceBot uses a series of if-elif-else
nests to determine what the user is trying to get it to do. An example below:
main.py: User enters /start (...)
if command == '/start':
reply('...')
elif command.startswith('/start'):
regex_pattern = '\/start\s+([a-zA-Z ]+)\s+('
...
Remember that AttendanceBot exists primarily to assist in the collection of attendance. Different methods are being called from different parts of the codebase, which may not be in the same file (refer to structure. We import
them right at the top of main.py
for use.
AttendanceBot uses a Mongo database in the cloud to keep track of everything. Database features will be explained in the future.
AttendanceBot, being a bot, must issue replies to users. It can even broadcast messages, but that is beyond the scope of this readme. To reply, the reply()
method is defined as such:
def reply(reply):
logger.info('Replied \'%s\' to %s' % (reply, chat_id))
self.sender.sendMessage(reply)
As you can see, we are using self.sender.sendMessage()
('self' being the DelegatorBot
initialized in bot
, which really is from the Telepot API and beyond us to explain. All we need is to log the reply, and call sendMessage()
to get it to the user. Broadcasting, as a tidbit, simply uses a for
loop of sendMessage()
methods to all users.
AttendanceBot runs mainly from main.py
, hence we run the command python3 main.py
. Other files serve the following purposes:
File | Function |
---|---|
authorized.py |
Validates superadmins, admins. Also determines which cluster the CG belongs to, and their cluster representative. |
botlogger.py |
Contains the logger logic. |
broadcaster.py |
Assists in the broadcasting (mass send) of messages. |
easter.py |
Generates the correct reponse when users talk to the bot casually. easter_example.py was provided. Modify the response dictionaries according to your liking. |
headmaster.py |
Contains the question bank for attendance taking, and decides the order they are shown. |
helper.py |
Logic to handle /help commands written here. |
main.py |
Handles the reply logic. |
manager.py |
All code related to database CRUD (Create, Read, Update, Delete) is found here and only here. (SRP) |
settings_secret.py |
Contains your secret tokens. Modify settings_secret_example.py and roll. DO NOT PUBLISH THIS ON GIT. |
tools.py |
Helper tools for string replace, substitution, et cetera. |
voglogger.py |
A script which allows for saving of logs to files. Imported from Darren's VOGLBot and currently not used. |
AttendanceBot has the following functionality which makes it a little different from the typical Telegram bot.
- Only registered users who are approved may use the bot. Upon registration, a request is sent to the CGL's cluster rep for case-by-case approval. Implements the
request_add()
function where the target_id is determined in the methodapprover_id = authorized.address_book[cluster]
:
// main.py
def request_add(target_id, message, to_add_cg, to_add_id, to_add_name):
logger.info('Superadmin attention was requested from %s' % (chat_id))
reply_markup = ReplyKeyboardMarkup(keyboard=[
[KeyboardButton(text='/add %s %s %s' % (to_add_cg, to_add_name, to_add_id))],['Reject'],
],one_time_keyboard=True,)
bot.sendMessage(target_id, message, reply_markup=reply_markup)
- On board database to keep track of attendance per CG, on an event basis. This implies that there is no data persistence. (Attendance data is destroyed once the event expires, which is automatically set to 3 days)
To do so, an event is first created by the superadmin using command /event new NAME OF EVENT
. All CGLs receive a broadcast notifying them to get counting. The counting is in a step-by-step manner and relies on the following method:
// main.py
manager.updateAttendance(self._query_cg, question_order[self._progress], count)
Where self._query_cg
, question_order[self._progress]
, count
refer to the CGL's CG, the question (eg. How many youths came today?) and the user input respectively.
Anyone may query the attendance for the cluster at any point in time by typing in /event report
. In doing so, the method manager.printGrandTally()
queries the attendance database and reports back.
This project is licensed under the MIT License - see the LICENSE file for details