butterrobot/butterrobot/platforms/slack.py

106 lines
3.2 KiB
Python
Raw Normal View History

2020-04-22 21:58:06 +00:00
from datetime import datetime
import structlog
from butterrobot.platforms.base import Platform, PlatformMethods
from butterrobot.config import SLACK_TOKEN, SLACK_BOT_OAUTH_ACCESS_TOKEN
from butterrobot.objects import Message, Channel
2020-04-22 21:58:06 +00:00
from butterrobot.lib.slack import SlackAPI
logger = structlog.get_logger(__name__)
class SlackMethods(PlatformMethods):
@classmethod
2020-10-28 10:19:30 +00:00
def send_message(self, message: Message):
2020-04-22 21:58:06 +00:00
logger.debug(
"Outgoing message", message=message.__dict__, platform=SlackPlatform.ID
)
try:
2020-10-28 10:19:30 +00:00
SlackAPI.send_message(
2020-07-03 15:34:49 +00:00
channel=message.chat, message=message.text, thread=message.reply_to
2020-04-22 21:58:06 +00:00
)
except SlackAPI.SlackClientError as error:
logger.error(
"Send message error",
platform=SlackPlatform.ID,
error=error,
message=message.__dict__,
)
class SlackPlatform(Platform):
ID = "slack"
methods = SlackMethods
@classmethod
2020-10-28 10:19:30 +00:00
def init(cls, app):
2020-04-22 21:58:06 +00:00
if not (SLACK_TOKEN and SLACK_BOT_OAUTH_ACCESS_TOKEN):
logger.error("Missing token. platform not enabled.", platform=cls.ID)
return
@classmethod
def parse_channel_name_from_raw(cls, channel_raw):
return channel_raw["name"]
@classmethod
def parse_channel_from_message(cls, message):
# Call different APIs for a channel or DM
if message["event"]["channel_type"] == "im":
chat_raw = SlackAPI.get_user_info(message["event"]["user"])
else:
chat_raw = SlackAPI.get_conversations_info(message["event"]["channel"])
return Channel(
platform=cls.ID,
platform_channel_id=message["event"]["channel"],
channel_raw=chat_raw,
)
2020-04-22 21:58:06 +00:00
@classmethod
2020-10-28 10:19:30 +00:00
def parse_incoming_message(cls, request):
data = request["json"]
2020-04-22 21:58:06 +00:00
# Auth
if data.get("token") != SLACK_TOKEN:
raise cls.PlatformAuthError("Authentication error")
# Confirms challenge request to configure webhook
if "challenge" in data:
raise cls.PlatformAuthResponse(data={"challenge": data["challenge"]})
# Discard messages by webhooks and apps
2020-04-22 21:58:06 +00:00
if "bot_id" in data["event"]:
logger.debug("Discarding message", data=data)
2020-04-22 21:58:06 +00:00
return
logger.debug("Parsing message", platform=cls.ID, data=data)
if data["event"]["type"] not in ("message", "message.groups"):
2020-04-22 21:58:06 +00:00
return
# Surprisingly, this *can* happen.
if "text" not in data["event"]:
return
message = Message(
2020-04-22 21:58:06 +00:00
id=data["event"].get("thread_ts", data["event"]["ts"]),
author=data["event"].get("user"),
2020-08-11 11:37:17 +00:00
from_bot="bot_id" in data["event"],
2020-04-22 21:58:06 +00:00
date=datetime.fromtimestamp(int(float(data["event"]["event_ts"]))),
text=data["event"]["text"],
2020-07-03 15:34:49 +00:00
chat=data["event"]["channel"],
channel=cls.parse_channel_from_message(data),
2020-04-22 21:58:06 +00:00
raw=data,
)
logger.info(
"New message",
platform=message.channel.platform,
channel=cls.parse_channel_name_from_raw(message.channel.channel_raw),
)
return message