from slack import WebClient
from slack.web.classes.messages import Message
from slack.web.slack_response import SlackResponse
from slack.errors import SlackRequestError
import yaml
import glob
from typing import Dict, Union
import logging
from glados import GladosRequest, get_var, get_enc_var
[docs]class BotImporter:
def __init__(self, bots_dir: str):
logging.info(f"starting BotImporter with config dir: {bots_dir}")
self.bots = dict() # type: Dict[str, GladosBot]
self._bots_yaml = dict()
self._dir = bots_dir
[docs] def import_bots(self):
"""Import all bots in the bots config folder
Returns
-------
"""
files = glob.glob(f"{self._dir}/*.yaml")
logging.debug(f"bot config files found: {files}")
for f in files:
with open(f) as file:
self._bots_yaml.update(yaml.load(file, Loader=yaml.FullLoader))
for bot_name, bot_config in self._bots_yaml.items():
self.bots[bot_name] = GladosBot(name=bot_name, **bot_config)
[docs]class GladosBot:
""" GLaDOS Bot represents all the required data and functions for a Slack bot.
Notes
-----
All Slack Web API functions can be called from MyBot.client.*
Parameters
----------
name: str
The name of the bot (URL Safe)
token: str, Dict[str, str]
The bot token
signing_secret: str, Dict[str, str]
The bot signing secret.
Attributes
----------
name: str
The name of the bot (URL Safe)
token: str
The bot token
client: WebClient
A Slack client generated for that bot
signing_secret: str
The bots signing secret.
"""
def __init__(
self,
token: Union[str, Dict[str, str]],
name,
signing_secret: Union[str, Dict[str, str]] = None,
**kwargs,
):
# Get the values from the env vars if used.
token = self.check_for_env_vars(token)
signing_secret = self.check_for_env_vars(signing_secret)
self.name = name
self.token = token
self.client = WebClient(token=token)
self.signing_secret = signing_secret
[docs] def check_for_env_vars(self, value):
"""Check an input value to see if it is an env_var or enc_env_var and get the value.
Parameters
----------
value : input to check.
Returns
-------
Any:
Returns the value of the var from either the passed in value, or the env var value.
"""
if type(value) is dict and "env_var" in value:
var_name = value["env_var"]
try:
return get_var(var_name)
except KeyError:
logging.critical(f"missing env var: {value['env_var']}")
if type(value) is dict and "enc_env_var" in value:
var_name = value["enc_env_var"]
try:
return get_enc_var(var_name)
except KeyError:
logging.critical(f"missing enc env var: {value['enc_env_var']}")
return value
[docs] def validate_slack_signature(self, request: GladosRequest):
valid = self.client.validate_slack_signature(
signing_secret=self.signing_secret, **request.slack_verify.json
)
logging.info(f"valid payload signature from slack: {valid}")
if not valid:
raise SlackRequestError("Signature of request is not valid")
[docs] def send_message(self, channel: str, message: Message) -> SlackResponse:
"""Send a message as the bot
Parameters
----------
channel : str
channel to send the message to
message : Message
message object to send
Returns
-------
"""
return self.client.chat_postMessage(
channel=channel, as_user=True, **message.to_dict()
).data
[docs] def update_message(self, channel: str, ts: str, message: Message) -> SlackResponse:
"""Updates a message that was sent by the bot
Parameters
----------
channel :
ts :
message :
Returns
-------
"""
return self.client.chat_update(channel=channel, ts=ts, **message.to_dict()).data
[docs] def delete_message(self, channel: str, ts: str) -> SlackResponse:
"""Deletes a message that was sent by a bot
Parameters
----------
channel :
ts :
Returns
-------
"""
return self.client.chat_delete(channel=channel, ts=ts).data