link_shortener: Migrate from goo.gl to bit.ly service.
Shorten URLs by using bit.ly service instead of goo.gl service. Fixes #367
This commit is contained in:
parent
dcd4c4a96e
commit
3db070b99e
|
@ -1,10 +1,9 @@
|
||||||
# Link Shortener Bot
|
# Link Shortener Bot
|
||||||
|
|
||||||
Link Shortener Bot is a Zulip bot that will shorten URLs ("links") in a
|
Link Shortener Bot is a Zulip bot that will shorten URLs ("links") in a
|
||||||
conversation. It uses the [goo.gl URL shortener API] to shorten its links.
|
conversation. It uses the [bitly URL shortener API] to shorten its links.
|
||||||
|
|
||||||
Use [this](https://developers.google.com/url-shortener/v1/getting_started) to get
|
Use [this](https://dev.bitly.com/get_started.html) to get your API Key.
|
||||||
your API Key.
|
|
||||||
|
|
||||||
Links can be anywhere in the message, for example,
|
Links can be anywhere in the message, for example,
|
||||||
|
|
||||||
|
@ -15,6 +14,6 @@ Links can be anywhere in the message, for example,
|
||||||
and LS Bot would respond
|
and LS Bot would respond
|
||||||
|
|
||||||
> https://github.com/zulip/python-zulip-api/tree/master/zulip_bots/zulip_bots/bots:
|
> https://github.com/zulip/python-zulip-api/tree/master/zulip_bots/zulip_bots/bots:
|
||||||
> **https://goo.gl/NjLZZH**
|
> **https://bit.ly/2FF3QHu**
|
||||||
|
|
||||||
[goo.gl URL shortener API]: https://goo.gl
|
[bitly URL shortener API]: https://bitly.com/
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"api_url": "https://api-ssl.bitly.com/v3/shorten",
|
||||||
|
"method": "GET",
|
||||||
|
"params": {
|
||||||
|
"access_token": "qwertyuiopx",
|
||||||
|
"longUrl": "www.youtube.com/watch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"status_code": 500,
|
||||||
|
"status_txt": "INVALID_ARG_ACCESS_TOKEN",
|
||||||
|
"data": []
|
||||||
|
},
|
||||||
|
"response-headers": {
|
||||||
|
"content-type": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"api_url": "https://www.googleapis.com/urlshortener/v1/url",
|
|
||||||
"method": "POST",
|
|
||||||
"params": {
|
|
||||||
"key": "qwertyuiopx"
|
|
||||||
},
|
|
||||||
"json": {
|
|
||||||
"longUrl": "www.youtube.com/watch"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"error":{
|
|
||||||
"errors":[
|
|
||||||
{
|
|
||||||
"reason":"keyInvalid"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"code": 400,
|
|
||||||
"message": "Bad Request"
|
|
||||||
},
|
|
||||||
"response-headers": {
|
|
||||||
"status": 400,
|
|
||||||
"content-type": "application/json; charset=utf-8"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,22 @@
|
||||||
{
|
{
|
||||||
"request": {
|
"request": {
|
||||||
"api_url": "https://www.googleapis.com/urlshortener/v1/url",
|
"api_url": "https://api-ssl.bitly.com/v3/shorten",
|
||||||
"method": "POST",
|
"method": "GET",
|
||||||
"params": {
|
"params": {
|
||||||
"key": "qwertyuiop"
|
"access_token": "qwertyuiop",
|
||||||
},
|
|
||||||
"json": {
|
|
||||||
"longUrl": "https://www.github.com/zulip/zulip"
|
"longUrl": "https://www.github.com/zulip/zulip"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"id": "https://goo.gl/6uoWKb"
|
"status_code": 200,
|
||||||
|
"status_txt": "OK",
|
||||||
|
"data": {
|
||||||
|
"url": "http://bit.ly/2Ht2hOI",
|
||||||
|
"hash": "2Ht2hOI",
|
||||||
|
"global_hash": "3j4ir4",
|
||||||
|
"long_url": "https://www.github.com/zulip/zulip/",
|
||||||
|
"new_hash": 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"response-headers": {
|
"response-headers": {
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
|
|
@ -20,18 +20,16 @@ class LinkShortenerHandler(object):
|
||||||
self.check_api_key(bot_handler)
|
self.check_api_key(bot_handler)
|
||||||
|
|
||||||
def check_api_key(self, bot_handler: Any) -> None:
|
def check_api_key(self, bot_handler: Any) -> None:
|
||||||
test_request = requests.post(
|
test_request_data = self.call_link_shorten_service('www.youtube.com/watch') # type: Any
|
||||||
'https://www.googleapis.com/urlshortener/v1/url',
|
|
||||||
json={'longUrl': 'www.youtube.com/watch'},
|
|
||||||
params={'key': self.config_info['key']}
|
|
||||||
) # type: Any
|
|
||||||
test_request_data = test_request.json()
|
|
||||||
try:
|
try:
|
||||||
if test_request_data['error']['errors'][0]['reason'] == 'keyInvalid':
|
if self.is_invalid_token_error(test_request_data):
|
||||||
bot_handler.quit('Invalid key. Follow the instructions in doc.md for setting API key.')
|
bot_handler.quit('Invalid key. Follow the instructions in doc.md for setting API key.')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def is_invalid_token_error(self, response_json: Any) -> bool:
|
||||||
|
return response_json['status_code'] == 500 and response_json['status_txt'] == 'INVALID_ARG_ACCESS_TOKEN'
|
||||||
|
|
||||||
def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
|
def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
|
||||||
REGEX_STR = (
|
REGEX_STR = (
|
||||||
'('
|
'('
|
||||||
|
@ -83,15 +81,24 @@ class LinkShortenerHandler(object):
|
||||||
long_url (str): The original URL to shorten.
|
long_url (str): The original URL to shorten.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
body = {'longUrl': long_url}
|
response_json = self.call_link_shorten_service(long_url)
|
||||||
params = {'key': self.config_info['key']}
|
if response_json['status_code'] == 200 and self.has_shorten_url(response_json):
|
||||||
|
shorten_url = self.get_shorten_url(response_json)
|
||||||
|
else:
|
||||||
|
shorten_url = ''
|
||||||
|
return shorten_url
|
||||||
|
|
||||||
request = requests.post(
|
def call_link_shorten_service(self, long_url: str) -> Any:
|
||||||
'https://www.googleapis.com/urlshortener/v1/url',
|
response = requests.get(
|
||||||
json=body,
|
'https://api-ssl.bitly.com/v3/shorten',
|
||||||
params=params
|
params={'access_token': self.config_info['key'], 'longUrl': long_url}
|
||||||
)
|
)
|
||||||
|
return response.json()
|
||||||
|
|
||||||
return request.json().get('id', '')
|
def has_shorten_url(self, response_json: Any) -> bool:
|
||||||
|
return 'data' in response_json and 'url' in response_json['data']
|
||||||
|
|
||||||
|
def get_shorten_url(self, response_json: Any) -> str:
|
||||||
|
return response_json['data']['url']
|
||||||
|
|
||||||
handler_class = LinkShortenerHandler
|
handler_class = LinkShortenerHandler
|
||||||
|
|
|
@ -12,19 +12,19 @@ class TestLinkShortenerBot(BotTestCase):
|
||||||
self.verify_reply(message, response)
|
self.verify_reply(message, response)
|
||||||
|
|
||||||
def test_bot_responds_to_empty_message(self) -> None:
|
def test_bot_responds_to_empty_message(self) -> None:
|
||||||
with patch('requests.post'):
|
with patch('requests.get'):
|
||||||
self._test('', 'No links found. Send "help" to see usage instructions.')
|
self._test('', 'No links found. Send "help" to see usage instructions.')
|
||||||
|
|
||||||
def test_normal(self) -> None:
|
def test_normal(self) -> None:
|
||||||
with self.mock_http_conversation('test_normal'):
|
with self.mock_http_conversation('test_normal'):
|
||||||
self._test('Shorten https://www.github.com/zulip/zulip please.',
|
self._test('Shorten https://www.github.com/zulip/zulip please.',
|
||||||
'https://www.github.com/zulip/zulip: https://goo.gl/6uoWKb')
|
'https://www.github.com/zulip/zulip: http://bit.ly/2Ht2hOI')
|
||||||
|
|
||||||
def test_no_links(self) -> None:
|
def test_no_links(self) -> None:
|
||||||
# No `mock_http_conversation` is necessary because the bot will
|
# No `mock_http_conversation` is necessary because the bot will
|
||||||
# recognize that no links are in the message and won't make any HTTP
|
# recognize that no links are in the message and won't make any HTTP
|
||||||
# requests.
|
# requests.
|
||||||
with patch('requests.post'):
|
with patch('requests.get'):
|
||||||
self._test('Shorten nothing please.',
|
self._test('Shorten nothing please.',
|
||||||
'No links found. Send "help" to see usage instructions.')
|
'No links found. Send "help" to see usage instructions.')
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class TestLinkShortenerBot(BotTestCase):
|
||||||
# No `mock_http_conversation` is necessary because the bot will
|
# No `mock_http_conversation` is necessary because the bot will
|
||||||
# recognize that the message is 'help' and won't make any HTTP
|
# recognize that the message is 'help' and won't make any HTTP
|
||||||
# requests.
|
# requests.
|
||||||
with patch('requests.post'):
|
with patch('requests.get'):
|
||||||
self._test('help',
|
self._test('help',
|
||||||
('Mention the link shortener bot in a conversation and then '
|
('Mention the link shortener bot in a conversation and then '
|
||||||
'enter any URLs you want to shorten in the body of the message.'))
|
'enter any URLs you want to shorten in the body of the message.'))
|
||||||
|
@ -40,6 +40,6 @@ class TestLinkShortenerBot(BotTestCase):
|
||||||
def test_exception_when_api_key_is_invalid(self)-> None:
|
def test_exception_when_api_key_is_invalid(self)-> None:
|
||||||
bot_test_instance = LinkShortenerHandler()
|
bot_test_instance = LinkShortenerHandler()
|
||||||
with self.mock_config_info({'key': 'qwertyuiopx'}):
|
with self.mock_config_info({'key': 'qwertyuiopx'}):
|
||||||
with self.mock_http_conversation('test_invalid_key'):
|
with self.mock_http_conversation('test_invalid_access_token'):
|
||||||
with self.assertRaises(StubBotHandler.BotQuitException):
|
with self.assertRaises(StubBotHandler.BotQuitException):
|
||||||
bot_test_instance.initialize(StubBotHandler())
|
bot_test_instance.initialize(StubBotHandler())
|
||||||
|
|
Loading…
Reference in a new issue