Skip to content

Latest commit

 

History

History
163 lines (122 loc) · 7.22 KB

Developer.md

File metadata and controls

163 lines (122 loc) · 7.22 KB

AttendanceBot Developer Guide

A Telegram bot which helps Caregroup Leaders in Arrow Ministry tabulate their group attendance.

Getting Started

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.

Prerequisities

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

Deployment

You may use any Python engine to host your bot. I used Digital Ocean with a Linux distro.

  1. 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.

Understanding the code

We use Telepot, a Python API for Telegram, by Nick Lee (credit below). Telepot adds an extra layer of simplification for us.

Webhooks

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 cloud

All 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, [
        ...

DelegatorBot

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),
])

Receiving messages

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+('
    ... 

External methods

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.

Database

AttendanceBot uses a Mongo database in the cloud to keep track of everything. Database features will be explained in the future.

Sending replies

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.

Structure

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.

  1. 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 method approver_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)
  1. 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.


Contributors

License

This project is licensed under the MIT License - see the LICENSE file for details