def _remove_subscriber(id): ''' Performs the write operation for removing a subscriber. TODO: add error handling for when user is not in the list of subscribers @param id: stringified unique user id as provided by telegram ''' subscribers = commons.get_data("subscribers") commons.log(LOG_TAG, "removing subscriber: " + subscribers[id] + "[" + id + "]") del subscribers[id] commons.set_data("subscribers", subscribers)
def _new_subscriber(id, name): ''' Performs the write operation for adding a subscriber. @param id: stringified unique user id as provided by telegram @param name: string to identify the user; can be first name, username or group chat name ''' subscribers = commons.get_data("subscribers") subscribers[id] = name commons.set_data("subscribers", subscribers) commons.log(LOG_TAG, "new subscriber: " + name + "[" + id + "]")
async def on_chat_message(self, message): ''' Async method to delegate command calls to their respective methods. Ignores messages that do not start with '/'. Sends non-admins a blocking 'maintenance mode' message when maintenance mode is on. @param message: dictionary containing information about the message received from user; see https://core.telegram.org/bots/api#message for more information ''' if("text" not in message): return command, _, payload = message['text'][1:].partition(" ") command = command.split("@")[0] chat = await self.administrator.getChat() self._log("chat: " + message['text'], chat) is_admin = chat['id'] in commons.get_data("admins") maintenance_mode = commons.get_data("status") == "maintenance" if maintenance_mode and not is_admin: await self.sender.sendMessage(MAINTENANCE_MODE_MESSAGE) elif message['text'].startswith("/"): try: command_call = getattr(self, "_" + command) await command_call(is_admin, payload) # increment command stats count stats = commons.get_data("stats") stats[command] = (0 if command not in stats else int(stats[command])) + 1 commons.set_data("stats", stats) except Exception as e: print(e) await self.sender.sendMessage(INVALID_COMMAND_MESSAGE)
async def _broadcast(self, is_admin, payload): ''' Async method to handle /broadcast calls from administrators. Sends a broadcasted message to all subscribers. @param is_admin: boolean to determine if user is admin @param payload: required string that follows the user's command ''' if payload and is_admin: for subscriber_id in commons.get_data("subscribers").keys(): await self.bot.sendMessage(int(subscriber_id), payload) else: raise ValueError("unauthorised")
async def on_tweet(data): ''' Function to be called when a new tweet is sent. @param data: a dictionary containing information about the tweet; see https://dev.twitter.com/overview/api/tweets for more information ''' # increment tweet stat count stats = commons.get_data("stats") stats["tweets"] = (0 if "tweets" not in stats else int(stats["tweets"])) + 1 commons.set_data("stats", stats) # send tweet to all subscribers tweet_message = "<b>" + data['user']['screen_name'] + "</b>: " + data[ 'text'] subscribers = commons.get_data("subscribers") commons.log(LOG_TAG, "sending tweet to " + str(len(subscribers)) + " subscribers") for subscriber_id in subscribers.keys(): await bot_delegator.sendMessage(int(subscriber_id), tweet_message, parse_mode='HTML')
async def _start(self, is_admin, payload = None): ''' Async method to handle /start calls. Sends the current status of the bot if user is an admin, otherwise, sends the normal welcome message unless the admin passes the payload 'force' @param is_admin: boolean to determine if user is admin @param payload: optional string that follows the user's command ''' if is_admin and payload != "force": await self.sender.sendMessage("Hi Admin!\nCurrent Status: " + commons.get_data("status")) else: await self.sender.sendMessage(START_MESSAGE, parse_mode = 'HTML', disable_web_page_preview = True) await self._subscribe(is_admin)
async def _subscribers(self, is_admin, payload = None): ''' Async method to handle /subscribers calls from administrators. Returns list of subscribers by their either their first name, username or group chat name. @param is_admin: boolean to determine if user is admin @param payload: optional string that follows the user's command ''' if is_admin: subscribers = commons.get_data("subscribers") message = "NTU_CampusBot Subscribers:\n" + ("=" * 25) + "\n\n" message += "\n".join(subscribers.values()) await self.sender.sendMessage(message) else: raise ValueError("unauthorised")
async def _stats(self, is_admin, payload = None): ''' Async method to handle /stats calls from administrators. Sends a statistical count of the number of times commands were called and the number of times tweets were sent. @param is_admin: boolean to determine if user is admin @param payload: optional string that follows the user's command ''' if is_admin: statistics = commons.get_data("stats") message = "NTU_CampusBot Statistics:\n" + ("=" * 25) + "\n\n" message += "\n".join([key + ": " + str(statistics[key]) for key in statistics.keys()]) await self.sender.sendMessage(message) else: raise ValueError("unauthorised")
async def _unsubscribe(self, is_admin, payload = None): ''' Async method to handle /unsubscribe calls. Removes user from list of subscribers. Returns a success message if user successfully unregisters and an error message if user fails to unsubscribe, that is, when user is not even subscribed. @param is_admin: boolean to determine if user is admin @param payload: optional string that follows the user's command ''' chat = await self.administrator.getChat() chat_id = str(chat['id']) if chat_id in commons.get_data("subscribers"): _remove_subscriber(chat_id) await self.sender.sendMessage(SUCCESSFULLY_UNSUBSCRIBED) else: await self.sender.sendMessage(NOT_SUBSCRIBED_MESSAGE)
async def _subscribe(self, is_admin, payload = None): ''' Async method to handle /subscribe calls. Adds user to list of subscribers. Returns a success message if user successfully registers and an error message if user fails to subscribe, that is, when user is already subscribed. @param is_admin: boolean to determine if user is admin @param payload: optional string that follows the user's command ''' chat = await self.administrator.getChat() chat_id = str(chat['id']) if chat_id not in commons.get_data("subscribers"): sender = chat['title' if 'title' in chat else ('username' if 'username' in chat else 'first_name')] _new_subscriber(chat_id, sender) await self.sender.sendMessage(SUCCESSFULLY_SUBSCRIBED) else: await self.sender.sendMessage(ALREADY_SUBSCRIBED_MESSAGE)
async def _maintenance(self, is_admin, payload = None): ''' Async method to handle /maintenance calls from administrators. Toggles maintenance mode on/off. Toggling it on disables standard users from using the bot. Passing 'on'/'off' as payload specifies the mode to be switched into. @param is_admin: boolean to determine if user is admin @param payload: optional string that follows the user's command ''' if is_admin and ((payload.lower() in ["on", "off"]) if payload else True): flip_current = "maintenance" if commons.get_data("status") == "running" else "running" new_status = "maintenance" if payload == "on" else ("off" if payload == "off" else flip_current) commons.set_data("status", new_status) message = "Maintenance Mode: " + ("on" if new_status == "maintenance" else "off") await self.sender.sendMessage(message) else: raise ValueError("unauthorised")