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

Added "add_user" and "remove_user" commands #5

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 111 additions & 26 deletions webexteamsbot/webexteamsbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from webexteamsbot.models import Response
import sys
import json
import re
import asyncio


# __author__ = "imapex"
# __author_email__ = "[email protected]"
Expand All @@ -18,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
Expand All @@ -49,18 +53,20 @@ 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
"""

super(TeamsBot, self).__init__(teams_bot_name)

# 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, "
Expand Down Expand Up @@ -94,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": 0
},
"/help": {"help": "Get help.", "callback": self.send_help},
}

# Set default help message
Expand Down Expand Up @@ -313,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
Expand All @@ -341,13 +355,16 @@ 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):
# 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):
Expand All @@ -356,23 +373,37 @@ 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 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(
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):
"""
Expand Down Expand Up @@ -434,3 +465,57 @@ 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)

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)