bots/flock: Add flock bot.
This commit is contained in:
parent
bb4c9c9bdb
commit
b6afa030c5
BIN
zulip_bots/zulip_bots/bots/flock/assests/1.png
Normal file
BIN
zulip_bots/zulip_bots/bots/flock/assests/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
27
zulip_bots/zulip_bots/bots/flock/doc.md
Normal file
27
zulip_bots/zulip_bots/bots/flock/doc.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Flock Bot
|
||||||
|
|
||||||
|
With [Flock](https://flock.com/) bot, you can send messages to any of your
|
||||||
|
flock contact without having to leave Zulip.
|
||||||
|
|
||||||
|
Sending messages to a user is quite easy, syntax is:
|
||||||
|
`@botname recipient_name: hello`
|
||||||
|
where `recipient_name` is name of recipient and `hello` is the sample message.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
1. Before running Flock bot, you'll need a `token`. In order to get `token`,
|
||||||
|
Go to [Flock apps](https://dev.flock.com/apps) and create an app.
|
||||||
|
After successful installation, you'll get an `token` in response from servers.
|
||||||
|
|
||||||
|
1. Once you have `token`, you should supply it in `flock.conf` file.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run this bot as described in
|
||||||
|
[here](https://zulipchat.com/api/running-bots#running-a-bot).
|
||||||
|
|
||||||
|
You can use this bot in one easy step:
|
||||||
|
|
||||||
|
`@botname recipient_firstName: message`
|
||||||
|
|
||||||
|
For help, do `@botname help`.
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"api_url": "https://api.flock.co/v1/chat.sendMessage",
|
||||||
|
"method": "GET",
|
||||||
|
"params": {
|
||||||
|
"token": "12345",
|
||||||
|
"text": "hi there",
|
||||||
|
"to": "u:invalid"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"error": "InvalidParameter",
|
||||||
|
"description": "A required parameter for the method call is missing or invalid",
|
||||||
|
"parameter": "to"
|
||||||
|
},
|
||||||
|
"response-headers": {
|
||||||
|
"content-type": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"api_url": "https://api.flock.co/v1/chat.sendMessage",
|
||||||
|
"method": "GET",
|
||||||
|
"params": {
|
||||||
|
"token": "12345",
|
||||||
|
"to": "u:userid",
|
||||||
|
"text": "hi there"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"uid": "15207048523"
|
||||||
|
},
|
||||||
|
"response-headers": {
|
||||||
|
"content-type": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"api_url": "https://api.flock.co/v1/roster.listContacts",
|
||||||
|
"method": "GET",
|
||||||
|
"params": {
|
||||||
|
"token": "12345"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"error": "No user found. Make sure you typed it correctly."
|
||||||
|
},
|
||||||
|
"response-headers": {
|
||||||
|
"content-type": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
2
zulip_bots/zulip_bots/bots/flock/flock.conf
Normal file
2
zulip_bots/zulip_bots/bots/flock/flock.conf
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[flock]
|
||||||
|
token=12345
|
98
zulip_bots/zulip_bots/bots/flock/flock.py
Normal file
98
zulip_bots/zulip_bots/bots/flock/flock.py
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
from typing import Any, Dict
|
||||||
|
from requests.exceptions import ConnectionError
|
||||||
|
|
||||||
|
USERS_LIST_URL = 'https://api.flock.co/v1/roster.listContacts'
|
||||||
|
SEND_MESSAGE_URL = 'https://api.flock.co/v1/chat.sendMessage'
|
||||||
|
|
||||||
|
help_message = '''
|
||||||
|
You can send messages to any Flock user associated with your account from Zulip.
|
||||||
|
*Syntax*: **@botname to: message** where `to` is **firstName** of recipient.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Matches the recipient name provided by user with list of users in his contacts.
|
||||||
|
# If matches, returns the matched User's ID
|
||||||
|
def find_recipient(res: str, to: str) -> str:
|
||||||
|
for obj in res:
|
||||||
|
if to == obj['firstName']:
|
||||||
|
return obj['id']
|
||||||
|
|
||||||
|
# Returns User's ID, if not found, returns error message.
|
||||||
|
def get_recipient_id(content: str, config: Dict[str, str]) -> str:
|
||||||
|
token = config['token']
|
||||||
|
content_pieces = content.split(':')
|
||||||
|
to = content_pieces[0].strip()
|
||||||
|
payload = {
|
||||||
|
'token': token
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = requests.get(USERS_LIST_URL, params=payload)
|
||||||
|
except ConnectionError as e:
|
||||||
|
logging.exception(str(e))
|
||||||
|
return "Uh-Oh, couldn't process the request \
|
||||||
|
right now.\nPlease try again later"
|
||||||
|
|
||||||
|
res = res.json()
|
||||||
|
to = find_recipient(res, to)
|
||||||
|
if to is None:
|
||||||
|
return "No user found. Make sure you typed it correctly."
|
||||||
|
else:
|
||||||
|
return to
|
||||||
|
|
||||||
|
# This handles the message sending work.
|
||||||
|
def get_flock_response(content: str, config: Dict[str, str]) -> str:
|
||||||
|
token = config['token']
|
||||||
|
content_pieces = content.split(':')
|
||||||
|
to = content_pieces[0].strip()
|
||||||
|
message = content_pieces[1].strip()
|
||||||
|
|
||||||
|
to = get_recipient_id(content, config)
|
||||||
|
if len(str(to)) > 30:
|
||||||
|
return to
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'to': to,
|
||||||
|
'text': message,
|
||||||
|
'token': token
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
r = requests.get(SEND_MESSAGE_URL, params=payload)
|
||||||
|
except ConnectionError as e:
|
||||||
|
logging.exception(str(e))
|
||||||
|
return "Uh-Oh, couldn't process the request \
|
||||||
|
right now.\nPlease try again later"
|
||||||
|
|
||||||
|
r = r.json()
|
||||||
|
if "uid" in r:
|
||||||
|
return "Message sent."
|
||||||
|
else:
|
||||||
|
return "Message sending failed :slightly_frowning_face:. Please try again."
|
||||||
|
|
||||||
|
def get_flock_bot_response(content: str, config: Dict[str, str]) -> None:
|
||||||
|
content = content.strip()
|
||||||
|
if content == '' or content == 'help':
|
||||||
|
return help_message
|
||||||
|
else:
|
||||||
|
result = get_flock_response(content, config)
|
||||||
|
return result
|
||||||
|
|
||||||
|
class FlockHandler(object):
|
||||||
|
'''
|
||||||
|
This is flock bot. Now you can send messages to any of your
|
||||||
|
flock user without having to leave Zulip.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
|
self.config_info = bot_handler.get_config_info('flock')
|
||||||
|
|
||||||
|
def usage(self) -> str:
|
||||||
|
return '''Hello from Flock Bot. You can send messages to any Flock user
|
||||||
|
right from Zulip.'''
|
||||||
|
|
||||||
|
def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
|
||||||
|
response = get_flock_bot_response(message['content'], self.config_info)
|
||||||
|
bot_handler.send_reply(message, response)
|
||||||
|
|
||||||
|
handler_class = FlockHandler
|
1
zulip_bots/zulip_bots/bots/flock/requirements.txt
Normal file
1
zulip_bots/zulip_bots/bots/flock/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
requests
|
62
zulip_bots/zulip_bots/bots/flock/test_flock.py
Normal file
62
zulip_bots/zulip_bots/bots/flock/test_flock.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
from unittest.mock import patch
|
||||||
|
from zulip_bots.test_lib import BotTestCase
|
||||||
|
from requests.exceptions import ConnectionError
|
||||||
|
|
||||||
|
class TestFlockBot(BotTestCase):
|
||||||
|
bot_name = "flock"
|
||||||
|
normal_config = {"token": "12345"}
|
||||||
|
|
||||||
|
message_config = {
|
||||||
|
"token": "12345",
|
||||||
|
"text": "Ricky: test message",
|
||||||
|
"to": "u:somekey"
|
||||||
|
}
|
||||||
|
|
||||||
|
help_message = '''
|
||||||
|
You can send messages to any Flock user associated with your account from Zulip.
|
||||||
|
*Syntax*: **@botname to: message** where `to` is **firstName** of recipient.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def test_bot_responds_to_empty_message(self) -> None:
|
||||||
|
self.verify_reply('', self.help_message)
|
||||||
|
|
||||||
|
def test_help_message(self) -> None:
|
||||||
|
self.verify_reply('', self.help_message)
|
||||||
|
|
||||||
|
def test_fetch_id_connection_error(self) -> None:
|
||||||
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
patch('requests.get', side_effect=ConnectionError()), \
|
||||||
|
patch('logging.exception'):
|
||||||
|
self.verify_reply('tyler: Hey tyler', "Uh-Oh, couldn\'t process the request \
|
||||||
|
right now.\nPlease try again later")
|
||||||
|
|
||||||
|
def test_response_connection_error(self) -> None:
|
||||||
|
with self.mock_config_info(self.message_config), \
|
||||||
|
patch('requests.get', side_effect=ConnectionError()), \
|
||||||
|
patch('logging.exception'):
|
||||||
|
self.verify_reply('Ricky: test message', "Uh-Oh, couldn\'t process the request \
|
||||||
|
right now.\nPlease try again later")
|
||||||
|
|
||||||
|
@patch('zulip_bots.bots.flock.flock.find_recipient')
|
||||||
|
def test_no_recipient_found(self, find_recipient: str) -> None:
|
||||||
|
bot_response = "No user found. Make sure you typed it correctly."
|
||||||
|
find_recipient.return_value = None
|
||||||
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_no_recipient_found'):
|
||||||
|
self.verify_reply('david: hello', bot_response)
|
||||||
|
|
||||||
|
@patch('zulip_bots.bots.flock.flock.get_recipient_id')
|
||||||
|
def test_message_send_success(self, get_recipient_id: str) -> None:
|
||||||
|
bot_response = "Message sent."
|
||||||
|
get_recipient_id.return_value = "u:userid"
|
||||||
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_message_send_success'):
|
||||||
|
self.verify_reply('Rishabh: hi there', bot_response)
|
||||||
|
|
||||||
|
@patch('zulip_bots.bots.flock.flock.get_recipient_id')
|
||||||
|
def test_message_send_failed(self, get_recipient_id: str) -> None:
|
||||||
|
bot_response = "Message sending failed :slightly_frowning_face:. Please try again."
|
||||||
|
get_recipient_id.return_value = "u:invalid"
|
||||||
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_message_send_failed'):
|
||||||
|
self.verify_reply('Rishabh: hi there', bot_response)
|
Loading…
Reference in a new issue