From 48073e72100290e4caebbbfe541c6cf128a95050 Mon Sep 17 00:00:00 2001 From: sebastian Date: Fri, 13 Mar 2020 22:37:55 +0100 Subject: [PATCH 1/5] Added "add_user" and "remove_user" to dynamically add or remove user from the approved_user list. --- webexteamsbot/webexteamsbot.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/webexteamsbot/webexteamsbot.py b/webexteamsbot/webexteamsbot.py index 611c97d..4ed2b66 100644 --- a/webexteamsbot/webexteamsbot.py +++ b/webexteamsbot/webexteamsbot.py @@ -7,6 +7,7 @@ from webexteamsbot.models import Response import sys import json +import re # __author__ = "imapex" # __author_email__ = "CiscoTeamsBot@imapex.io" @@ -434,3 +435,22 @@ def send_echo(self, post_data): # Get sent message message = self.extract_message("/echo", post_data.text) return message + + def add_user(self, user): + """ + Command to add new user to approved_user list + :param user: + :return: + """ + if re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", user): + if user not in self.approved_users: + self.approved_users.append(user) + + def remove_user(self, user): + """ + Command to remove user from approved_user list + :param user: + :return: + """ + if user in self.approved_users: + self.approved_users.remove(user) From 3c3d0ea2631ea6f0476be4123e32070c264d4c6f Mon Sep 17 00:00:00 2001 From: Sebastian Halter Date: Tue, 17 Mar 2020 12:13:53 +0100 Subject: [PATCH 2/5] - Reformatting - Added ability to delete Message from the Bot after x seconds - Added function to delete Message by MessageID --- webexteamsbot/webexteamsbot.py | 114 +++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 27 deletions(-) diff --git a/webexteamsbot/webexteamsbot.py b/webexteamsbot/webexteamsbot.py index 4ed2b66..e3a63d4 100644 --- a/webexteamsbot/webexteamsbot.py +++ b/webexteamsbot/webexteamsbot.py @@ -8,6 +8,8 @@ import sys import json import re +import asyncio + # __author__ = "imapex" # __author_email__ = "CiscoTeamsBot@imapex.io" @@ -19,18 +21,19 @@ class TeamsBot(Flask): """An instance of a Webex Teams Bot""" def __init__( - self, - teams_bot_name, - teams_bot_token=None, - teams_api_url=None, - teams_bot_email=None, - teams_bot_url=None, - default_action="/help", - webhook_resource_event=None, - webhook_resource="messages", - webhook_event="created", - approved_users=[], - debug=False, + self, + teams_bot_name, + teams_bot_token=None, + teams_api_url=None, + teams_bot_email=None, + teams_bot_url=None, + default_action="/help", + webhook_resource_event=None, + webhook_resource="messages", + webhook_event="created", + approved_users=[], + debug=False + ): """ Initialize a new TeamsBot @@ -50,7 +53,9 @@ def __init__( to create webhooks for. [{"resource": "messages", "event": "created"}, {"resource": "attachmentActions", "event": "created"}] - :param approved_users: List of approved users (by email) to interact with bot. Default all users. + :param approved_users: + List of approved users (by email) to interact with bot. + Default all users. :param debug: boolean value for debut messages """ @@ -58,10 +63,10 @@ def __init__( # Verify required parameters provided if None in ( - teams_bot_name, - teams_bot_token, - teams_bot_email, - teams_bot_token, + teams_bot_name, + teams_bot_token, + teams_bot_email, + teams_bot_token, ): raise ValueError( "TeamsBot requires teams_bot_name, " @@ -95,8 +100,13 @@ def __init__( "/echo": { "help": "Reply back with the same message sent.", "callback": self.send_echo, + "after": 0 + }, + "/help": { + "help": "Get help.", + "callback": self.send_help, + "after": 10 }, - "/help": {"help": "Get help.", "callback": self.send_help}, } # Set default help message @@ -314,9 +324,12 @@ def process_incoming_message(self): sys.stderr.write("Message from: " + message.personEmail + "\n") # Check if user is approved - if len(self.approved_users) > 0 and message.personEmail not in self.approved_users: + if len(self.approved_users) > 0 and message.personEmail \ + not in map(str.lower, self.approved_users): # User NOT approved - sys.stderr.write("User: " + message.personEmail + " is not approved to interact with bot. Ignoring.\n") + sys.stderr.write("User: " + message.personEmail + + " is not approved to interact with bot. " + "Ignoring.\n") return "Unapproved user" # Find the command that was sent, if any @@ -342,13 +355,14 @@ def process_incoming_message(self): else: pass + sent_reply = "" # allow command handlers to craft their own Teams message if reply and isinstance(reply, Response): # If the Response lacks a roomId, set it to the incoming room if not reply.roomId: reply.roomId = room_id reply = reply.as_dict() - self.teams.messages.create(**reply) + sent_reply = self.teams.messages.create(**reply) reply = "ok" # Support returning a list of Responses elif reply and isinstance(reply, list): @@ -357,23 +371,34 @@ def process_incoming_message(self): if isinstance(response, Response): if not response.roomId: response.roomId = room_id - self.teams.messages.create(**response.as_dict()) - + sent_reply = \ + self.teams.messages.create(**response.as_dict()) reply = "ok" elif reply: - self.teams.messages.create(roomId=room_id, markdown=reply) + sent_reply = \ + self.teams.messages.create(roomId=room_id, markdown=reply) + + if self.commands[command]['after'] > 0: + self.async_deletion_start( + sent_reply.id, self.commands[command]['after'] + ) + return reply - def add_command(self, command, help_message, callback): + def add_command(self, command, help_message, callback, after=0): """ Add a new command to the bot :param command: The command string, example "/status" :param help_message: A Help string for this command :param callback: The function to run when this command is given + :param after: Determines the time till deletion in seconds + Defaults to 0. 0 = never delete the Message :return: """ self.commands[command.lower()] = {"help": help_message, - "callback": callback} + "callback": callback, + "after": after + } def remove_command(self, command): """ @@ -442,7 +467,8 @@ def add_user(self, user): :param user: :return: """ - if re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", user): + if re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", + user): if user not in self.approved_users: self.approved_users.append(user) @@ -454,3 +480,37 @@ def remove_user(self, user): """ if user in self.approved_users: self.approved_users.remove(user) + + def delete_message(self, message_id=None): + """ + Command to delete a Message by message_id + :param message_id: + :return: + """ + if message_id is not None and message_id is not "": + self.teams.messages.delete(message_id) + return + + def async_deletion_start(self, message_id, after): + """ + Command to start a asynchronous deletion + :param message_id: + :param after: + :return: + """ + loop = asyncio.new_event_loop() + loop.run_until_complete(self._wait_delete_message( + message_id, after, loop) + ) + + @asyncio.coroutine + def _wait_delete_message(self, message_id, after, loop): + """ + Command to call the asynchronous deletion for a message + after a specific amount of time + :param message_id: + :param after: + :return: + """ + yield from asyncio.sleep(after) + self.delete_message(message_id) From 0bb3211ba969b7df1f1495dd5852d4c3ac97fbe2 Mon Sep 17 00:00:00 2001 From: Sebastian Halter Date: Tue, 17 Mar 2020 12:25:54 +0100 Subject: [PATCH 3/5] Fixed an error --- webexteamsbot/webexteamsbot.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/webexteamsbot/webexteamsbot.py b/webexteamsbot/webexteamsbot.py index e3a63d4..bf73c33 100644 --- a/webexteamsbot/webexteamsbot.py +++ b/webexteamsbot/webexteamsbot.py @@ -378,10 +378,12 @@ def process_incoming_message(self): sent_reply = \ self.teams.messages.create(roomId=room_id, markdown=reply) - if self.commands[command]['after'] > 0: - self.async_deletion_start( - sent_reply.id, self.commands[command]['after'] - ) + if "command" in locals(): + if command in self.commands: + if self.commands[command]['after'] > 0: + self.async_deletion_start( + sent_reply.id, self.commands[command]['after'] + ) return reply From 0765ea097167c822484daaae0ea069ab49caa6ac Mon Sep 17 00:00:00 2001 From: Sebastian Halter Date: Tue, 17 Mar 2020 12:28:13 +0100 Subject: [PATCH 4/5] Forgot to replace a test variable --- webexteamsbot/webexteamsbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webexteamsbot/webexteamsbot.py b/webexteamsbot/webexteamsbot.py index bf73c33..12d1294 100644 --- a/webexteamsbot/webexteamsbot.py +++ b/webexteamsbot/webexteamsbot.py @@ -105,7 +105,7 @@ def __init__( "/help": { "help": "Get help.", "callback": self.send_help, - "after": 10 + "after": 0 }, } From 7659857cb7c0c959605c9ddd067640b1c14081b2 Mon Sep 17 00:00:00 2001 From: Sebastian Halter Date: Tue, 17 Mar 2020 14:16:47 +0100 Subject: [PATCH 5/5] Forgot to check if the sent_reply is a valid reply and not the default assignment --- webexteamsbot/webexteamsbot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/webexteamsbot/webexteamsbot.py b/webexteamsbot/webexteamsbot.py index 12d1294..bcf9a41 100644 --- a/webexteamsbot/webexteamsbot.py +++ b/webexteamsbot/webexteamsbot.py @@ -355,6 +355,8 @@ def process_incoming_message(self): else: pass + # variable to get the message_id form the response + # to delete it if necessary sent_reply = "" # allow command handlers to craft their own Teams message if reply and isinstance(reply, Response): @@ -378,7 +380,8 @@ def process_incoming_message(self): sent_reply = \ self.teams.messages.create(roomId=room_id, markdown=reply) - if "command" in locals(): + # if variable command exists and sent_reply is not a string + if "command" in locals() and not isinstance(sent_reply, str): if command in self.commands: if self.commands[command]['after'] > 0: self.async_deletion_start(