Skip to content

Commit

Permalink
Merge pull request #4 from michalm138/dev
Browse files Browse the repository at this point in the history
Alerts and general improvements
  • Loading branch information
michalm138 committed Jun 11, 2023
2 parents 5cacbe3 + 16d3128 commit 9f02d32
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 78 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@ dmypy.json
.pyre/

.idea/
.vscode
57 changes: 44 additions & 13 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
# Slackybot usage
<!-- TOC -->
* [Slackybot usage](#slackybot-usage)
* [Initialization](#initialization)
* [Slack App token scopes](#slack-app-token-scopes)
* [Importing module](#importing-module)
* [Initialize the Slack object](#initialize-the-slack-object)
* [Simple message](#simple-message)
* [Send message](#send-message)
* [Send reply in the thread](#send-reply-in-the-thread)
* [List all sent messages](#list-all-sent-messages)
* [List all sent replies](#list-all-sent-replies)
* [List of all methods](#list-of-all-methods)
* [Update message or reply](#update-message-or-reply)
* [Delete message or reply](#delete-message-or-reply)
* [Alerts](#alerts)
* [Send alert](#send-alert)
* [List of all methods](#list-of-methods-of-all-objects)
<!-- TOC -->

# Slackybot usage
## Initialization
### Slack App token scopes
The Slack App should have following token scopes:
`channels:join` `channels:read` `chat:write` `chat:write.customize` `chat:write.public`
Expand All @@ -32,6 +38,7 @@ Initialize the Slack object.
**default_channel** - (string) You can specify the default channel - it may be overwritten later.


## Simple message
### Send message
```python
message = slack.send_message(channel='', text='')
Expand Down Expand Up @@ -83,18 +90,42 @@ reply.delete()
Deletes the message or reply.


## Alerts
### Send alert
![The alert sample](images/Screenshot%202023-06-09%20113833.png)
```python
slack.send_alert(channel='', title='', type='', values={}, mentions=())
```
Sends alert message to the channel. It returns the Message object.

**channel** - (string) The channel name. It overwrites the default one if passed in the initialization.
**title** - (string) The alert title.
**type** - (string) The alert type. Options are: `success`, `warning`, `fail`.
**values** - (dict) The alert content. E.g.:
```python
{
"Field one": "`OK`",
"Field two": 123456789,
"Field three": "Lorem ipsum..."
}
```
**mentions** - (tuple) People to be mentioned.

_Note: All Message object methods work as well_

---


# List of methods of all objects

| Object | Method | Returns |
|---------|-------------------------------------|----------------|
| Slack | `send_message(channel='', text='')` | Message object |
| | `get_messages()` | List |
| Message | `update(text='')` | - |
| | `send_reply(text='')` | Reply object |
| | `get_replies()` | List |
| | `delete()` | - |
| Reply | `update(text='')` | - |
| | `delete()` | - |
| Object | Method | Returns |
|---------|---------------------------------------------------------------------|----------------|
| Slack | `send_message(channel='', text='')` | Message object |
| | `send_alert(channel='', title='', type='', values={}, mentions=())` | Message object |
| | `get_messages()` | List |
| Message | `update(text='')` | - |
| | `send_reply(text='')` | Reply object |
| | `get_replies()` | List |
| | `delete()` | - |
| Reply | `update(text='')` | - |
| | `delete()` | - |
Binary file added docs/images/Screenshot 2023-06-09 113833.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = slackybot
version = 1.0.0
version = 1.2.0
author = michalm138
author_email = dev.michalm138@gmail.com
description = A Python package that helps to interact with the Slack App
Expand Down
7 changes: 7 additions & 0 deletions src/slackybot/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,10 @@ class MissingText(Exception):
def __init__(self, message="There is no text"):
self.message = message
super().__init__(self.message)


class WrongAlertType(Exception):

def __init__(self, message="Wrong the alert type. Possible options: success, fail, warning"):
self.message = message
super().__init__(self.message)
86 changes: 71 additions & 15 deletions src/slackybot/main.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
from .messaging import Message
from .utilities import request_handler, config, helpers
from .utilities.request_handler import Request
from .utilities.common import config
from . import exceptions
from time import time


class Slack:

def __init__(self, token=None, default_channel=''):
def __init__(self, token='', default_channel=''):
if not token:
raise exceptions.SlackInitializeError('Missing token')
self._token = token
self._messages = []
self._default_channel = default_channel
self._request = Request(self._token)

def send_message(self, channel='', text=''):
"""Sends simple text message.
Expand All @@ -22,19 +25,72 @@ def send_message(self, channel='', text=''):
Returns:
Object: <Message>
"""
if output := request_handler.post_request(
config.data['urls']['post_message'],
{'channel': channel if channel else self._default_channel, 'text': text},
self._token,
):
if output['ok']:
slack_message = Message(self._token, channel, text, output)
self._messages.append(slack_message)
return slack_message
else:
raise helpers.get_exception(output)
else:
raise exceptions.MessageNotSend

self._request.post(
url='post_message',
data={
'icon_url': config.data['default_icon'],
'channel': channel if channel else self._default_channel,
'text': text
},
exception=exceptions.MessageNotSend
)
slack_message = Message(self._token, channel, text, self._request.response)
self._messages.append(slack_message)
return slack_message

def send_alert(self, channel='', title='Alert!', type='', values: dict = {}, mentions: tuple = ()):
"""Sends the alert message
Args:
channel (str, optional): Specify the channel where the alert has to be sent.
title (str, optional): The alert title. Defaults to 'Alert!'.
type (str, optional): One of the following types: "success", "warning", "fail".
values (dict, optional): Fields in the alert message.
mentions (tuple, optional): Slack nicknames.
Returns:
Object: <Message>
"""
if type.lower() not in ['success', 'fail', 'warning']:
raise exceptions.WrongAlertType
self._request.post(
url='post_message',
data={
'channel': channel if channel else self._default_channel,
'icon_url': config.data['default_icon'],
'attachments': [
{
'mrkdwn_in': ['text'],
'color': config.data['alert']['colors'].get(type, '#737373'),
'title': f"{config.data['alert']['icons'].get(type, ':black_circle:')} {title}",
'fields': [
{
'title': '',
'value': '',
'short': False
},
{
'title': '',
'value': '\n'.join([f'*{key}:* {value}' for key, value in values.items()]),
'short': False
},
{
'title': ':mega: Mentions' if mentions else '',
'value': ', '.join([f'<@{mention}>' for mention in mentions]) if mentions else '',
'short': False
},
],
'footer': 'Alert',
'ts': time()
}
]
},
exception=exceptions.MessageNotSend
)
slack_message = Message(self._token, channel, '', self._request.response)
self._messages.append(slack_message)
return slack_message

def get_messages(self):
"""Lists all sent messages.
Expand Down
64 changes: 28 additions & 36 deletions src/slackybot/messaging.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .utilities import request_handler, config, helpers
from .utilities.request_handler import Request
from .utilities import config
from . import exceptions
import uuid

Expand All @@ -11,6 +12,7 @@ def __init__(self, token, channel, text, data):
self._ts = data['ts']
self._channel = data['channel']
self._deleted = False
self._request = Request(self._token)

self.channel = channel
self.text = text
Expand All @@ -30,17 +32,12 @@ def update(self, text=''):
Returns:
None
"""
if output := request_handler.post_request(
config.data['urls']['update_message'],
{'channel': self._channel, 'ts': self._ts, 'text': text},
self._token,
):
if output['ok']:
self.text = text
else:
raise helpers.get_exception(output)
else:
raise exceptions.MessageNotUpdated
self._request.post(
url='update_message',
data={'channel': self._channel, 'ts': self._ts, 'text': text},
exception=exceptions.MessageNotUpdated
)
self.text = text

def delete(self):
"""Deletes the message.
Expand All @@ -51,17 +48,12 @@ def delete(self):
if self._deleted:
raise exceptions.MessageAlreadyDeleted

if output := request_handler.post_request(
config.data['urls']['delete_message'],
{'channel': self._channel, 'ts': self._ts},
self._token,
):
if output['ok']:
self._deleted = True
else:
raise helpers.get_exception(output)
else:
raise exceptions.MessageNotDeleted
self._request.post(
url='delete_message',
data={'channel': self._channel, 'ts': self._ts},
exception=exceptions.MessageNotDeleted
)
self._deleted = True


class Message(SlackMessage):
Expand All @@ -80,19 +72,19 @@ def send_reply(self, text=''):
Object: <Reply>
"""
if output := request_handler.post_request(
config.data['urls']['post_message'],
{'channel': self.channel, 'thread_ts': self._ts, 'text': text},
self._token,
):
if output['ok']:
reply = Reply(self._token, self.channel, text, output)
self._replies.append(reply)
return reply
else:
raise helpers.get_exception(output)
else:
raise exceptions.MessageNotSend
self._request.post(
url='post_message',
data={
'icon_url': config.data['default_icon'],
'channel': self.channel,
'thread_ts': self._ts,
'text': text
},
exception=exceptions.MessageNotSend
)
reply = Reply(self._token, self.channel, text, self._request.response)
self._replies.append(reply)
return reply

def get_replies(self):
"""Lists all sent replies to the message thread.
Expand Down
File renamed without changes.
13 changes: 13 additions & 0 deletions src/slackybot/utilities/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,17 @@
'no_text': exceptions.MissingText,
'message_not_found': exceptions.MessageNotFound,
},
'alert': {
'colors': {
'success': 'good',
'warning': 'warning',
'fail': 'danger',
},
'icons': {
'success': ':white_check_mark:',
'fail': ':x:',
'warning': ':warning:',
},
},
'default_icon': 'http://lorempixel.com/48/48',
}
43 changes: 30 additions & 13 deletions src/slackybot/utilities/request_handler.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
from . import common, config
import requests
import json


def post_request(url, data, token):
"""
:param url: (string)
:param data: (dict)
:param token: (string) Token of the Slack bot
:return: (bool, dict) True and response JSON if the request is a success
"""
try:
headers = {'Authorization': f'Bearer {token}'}
response = requests.post(url, data, headers=headers)
return response.json()
except (requests.ConnectionError, json.JSONDecodeError, Exception):
return {}
class Request:

def __init__(self, token):
self.response = {}
self._token = None
self._headers = {'Authorization': f'Bearer {token}'}

def post(self, url, data={}, exception=None):
"""Sends the POST request
Args:
url (str): A key of the url in the config file.
data (dict, optional): The request JSON payload. Defaults to {}.
exception (exception): An exception - it is raised in case of request sending failure.
"""
try:
response = requests.post(
config.data['urls'][url],
json=data,
headers=self._headers,
).json()
if response['ok']:
self.response = response
else:
raise common.get_exception(response)
except KeyError as exp:
raise Exception(f'Given url does not exist: {exp}')
except (requests.ConnectionError, json.JSONDecodeError, requests.ConnectTimeout):
raise exception if exception else Exception('Unknown error while sending request. Exception not provided.')
Loading

0 comments on commit 9f02d32

Please sign in to comment.