Skip to content

Commit 29e22c2

Browse files
marcoshowell
authored andcommitted
bots: Create Link Shortener Bot.
Create Link Shortener Bot using the goo.gl Link Shortening API. Link Shortener Bot can be mentioned in a conversation, and it will respond with shortened, goo.gl links for every URL in the message. For example, > @link_shortener_bot @johnsmith Check out this file: > https://github.com/zulip/python-zulip-api/blob/master/zulip_bots/ and Link Shortener Bot would respond > https://github.com/zulip/python-zulip-api/blob/master/zulip_bots/: > https://goo.gl/Mt5z3c In order to use Link Shortener Bot, an API key for goo.gl must be set in `link_shortener.conf` in the `link_shortener` folder.
1 parent e5685ad commit 29e22c2

File tree

7 files changed

+174
-0
lines changed

7 files changed

+174
-0
lines changed

zulip_bots/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
'html2text', # for bots/define
5353
'BeautifulSoup4', # for bots/googlesearch
5454
'lxml', # for bots/googlesearch
55+
'requests' # for bots/link_shortener
5556
],
5657
)
5758

zulip_bots/zulip_bots/bots/link_shortener/__init__.py

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Link Shortener Bot
2+
3+
Link Shortener Bot is a Zulip bot that will shorten URLs ("links") in a
4+
conversation. It uses the [goo.gl URL shortener API] to shorten its links.
5+
6+
Links can be anywhere in the message, for example,
7+
8+
> @**Link Shortener Bot** @**Joe Smith** See
9+
> https://github.com/zulip/python-zulip-api/tree/master/zulip_bots/zulip_bots/bots
10+
> for a list of all Zulip bots.
11+
12+
and LS Bot would respond
13+
14+
> https://github.com/zulip/python-zulip-api/tree/master/zulip_bots/zulip_bots/bots:
15+
> **https://goo.gl/NjLZZH**
16+
17+
[goo.gl URL shortener API]: https://goo.gl
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"request": {
3+
"api_url": "https://www.googleapis.com/urlshortener/v1/url",
4+
"method": "POST",
5+
"params": {
6+
"key": "qwertyuiop"
7+
},
8+
"json": {
9+
"longUrl": "https://www.github.com/zulip/zulip"
10+
}
11+
},
12+
"response": {
13+
"id": "https://goo.gl/6uoWKb"
14+
},
15+
"response-headers": {
16+
"status": 200,
17+
"content-type": "application/json; charset=utf-8"
18+
}
19+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[link_shortener]
2+
key = <your API key>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import re
2+
import requests
3+
4+
class LinkShortenerHandler(object):
5+
'''A Zulip bot that will shorten URLs ("links") in a conversation using the
6+
goo.gl URL shortener.
7+
'''
8+
9+
def usage(self):
10+
return (
11+
'Mention the link shortener bot in a conversation and then enter '
12+
'any URLs you want to shorten in the body of the message. \n\n'
13+
'`key` must be set in `link_shortener.conf`.')
14+
15+
def initialize(self, bot_handler):
16+
self.config_info = bot_handler.get_config_info('link_shortener')
17+
18+
def handle_message(self, message, bot_handler):
19+
REGEX_STR = (
20+
'('
21+
'(?:http|https):\/\/' # This allows for the HTTP or HTTPS
22+
# protocol.
23+
'[^"<>#%\{\}|\\^~[\]` ]+' # This allows for any character except
24+
# for certain non-URL-safe ones.
25+
')'
26+
)
27+
28+
content = message['content']
29+
30+
if content.strip() == 'help':
31+
bot_handler.send_reply(
32+
message,
33+
(
34+
'Mention the link shortener bot in a conversation and '
35+
'then enter any URLs you want to shorten in the body of '
36+
'the message.'
37+
)
38+
)
39+
return
40+
41+
link_matches = re.findall(REGEX_STR, content)
42+
43+
shortened_links = [self.shorten_link(link) for link in link_matches]
44+
link_pairs = [
45+
(link_match + ': ' + shortened_link)
46+
for link_match, shortened_link
47+
in zip(link_matches, shortened_links)
48+
if shortened_link != ''
49+
]
50+
final_response = '\n'.join(link_pairs)
51+
52+
if final_response == '':
53+
bot_handler.send_reply(
54+
message,
55+
'No links found. Send "help" to see usage instructions.'
56+
)
57+
return
58+
59+
bot_handler.send_reply(message, final_response)
60+
61+
def shorten_link(self, long_url):
62+
'''Shortens a link using goo.gl Link Shortener and returns it, or
63+
returns an empty string if something goes wrong.
64+
65+
Parameters:
66+
long_url (str): The original URL to shorten.
67+
'''
68+
69+
body = {'longUrl': long_url}
70+
params = {'key': self.config_info['key']}
71+
72+
request = requests.post(
73+
'https://www.googleapis.com/urlshortener/v1/url',
74+
json=body,
75+
params=params
76+
)
77+
78+
return request.json().get('id', '')
79+
80+
handler_class = LinkShortenerHandler
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python
2+
3+
from zulip_bots.test_lib import BotTestCase
4+
5+
class TestLinkShortenerBot(BotTestCase):
6+
bot_name = "link_shortener"
7+
8+
def test_bot(self):
9+
MESSAGE = 'Shorten https://www.github.com/zulip/zulip please.'
10+
RESPONSE = 'https://www.github.com/zulip/zulip: https://goo.gl/6uoWKb'
11+
12+
with self.mock_config_info({'key': 'qwertyuiop'}), \
13+
self.mock_http_conversation('test_normal'):
14+
self.initialize_bot()
15+
16+
self.assert_bot_response(
17+
message = {'content': MESSAGE},
18+
response = {'content': RESPONSE},
19+
expected_method='send_reply'
20+
)
21+
22+
def test_bot_empty(self):
23+
MESSAGE = 'Shorten nothing please.'
24+
RESPONSE = 'No links found. Send "help" to see usage instructions.'
25+
26+
# No `mock_http_conversation` is necessary because the bot will
27+
# recognize that no links are in the message and won't make any HTTP
28+
# requests.
29+
with self.mock_config_info({'key': 'qwertyuiop'}):
30+
self.initialize_bot()
31+
32+
self.assert_bot_response(
33+
message = {'content': MESSAGE},
34+
response = {'content': RESPONSE},
35+
expected_method='send_reply'
36+
)
37+
38+
def test_bot_help(self):
39+
MESSAGE = 'help'
40+
RESPONSE = (
41+
'Mention the link shortener bot in a conversation and then enter '
42+
'any URLs you want to shorten in the body of the message.'
43+
)
44+
45+
# No `mock_http_conversation` is necessary because the bot will
46+
# recognize that the message is 'help' and won't make any HTTP
47+
# requests.
48+
with self.mock_config_info({'key': 'qwertyuiop'}):
49+
self.initialize_bot()
50+
51+
self.assert_bot_response(
52+
message = {'content': MESSAGE},
53+
response = {'content': RESPONSE},
54+
expected_method='send_reply'
55+
)

0 commit comments

Comments
 (0)