beeminder: Check auth_token in initialize
by idempotent request.
Change checking auth_token in `initialize` method by calling request to get user's information instead of calling POST request which modifies progress of user's goal.
This commit is contained in:
parent
229f62a483
commit
488dcb4219
|
@ -83,9 +83,13 @@ class BeeminderHandler(object):
|
||||||
def initialize(self, bot_handler: Any) -> None:
|
def initialize(self, bot_handler: Any) -> None:
|
||||||
self.config_info = bot_handler.get_config_info('beeminder')
|
self.config_info = bot_handler.get_config_info('beeminder')
|
||||||
# Check for valid auth_token
|
# Check for valid auth_token
|
||||||
result = get_beeminder_response('5', self.config_info)
|
auth_token = self.config_info['auth_token']
|
||||||
if result == "Error. Check your key!":
|
try:
|
||||||
|
r = requests.get("https://www.beeminder.com/api/v1/users/me.json", params={'auth_token': auth_token})
|
||||||
|
if r.status_code == 401:
|
||||||
bot_handler.quit('Invalid key!')
|
bot_handler.quit('Invalid key!')
|
||||||
|
except ConnectionError as e:
|
||||||
|
logging.exception(str(e))
|
||||||
|
|
||||||
def usage(self) -> str:
|
def usage(self) -> str:
|
||||||
return "This plugin allows users to add datapoints towards their Beeminder goals"
|
return "This plugin allows users to add datapoints towards their Beeminder goals"
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"api_url": "https://www.beeminder.com/api/v1/users/aaron/goals/goal/datapoints.json",
|
|
||||||
"method": "POST",
|
|
||||||
"json": {
|
|
||||||
"auth_token": "XXXXXX",
|
|
||||||
"value": "5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"help_message": "This is help message."
|
|
||||||
},
|
|
||||||
"response-headers": {
|
|
||||||
"status": 200,
|
|
||||||
"content-type": "application/json; charset=utf-8"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"api_url": "https://www.beeminder.com/api/v1/users/aaron/goals/goal/datapoints.json",
|
|
||||||
"method": "POST",
|
|
||||||
"json": {
|
|
||||||
"auth_token": "XXXXXX",
|
|
||||||
"value": "5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"help_message": "This is help message."
|
|
||||||
},
|
|
||||||
"response-headers": {
|
|
||||||
"status": 200,
|
|
||||||
"content-type": "application/json; charset=utf-8"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"api_url": "https://www.beeminder.com/api/v1/users/me.json",
|
||||||
|
"method": "GET",
|
||||||
|
"params": {
|
||||||
|
"auth_token": "someInvalidKey"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"errors": {
|
||||||
|
"auth_token": "bad_token",
|
||||||
|
"message": "No such auth_token found. (Did you mix up auth_token and access_token?)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response-headers": {
|
||||||
|
"status": 401,
|
||||||
|
"content-type": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"api_url": "https://www.beeminder.com/api/v1/users/aaron/goals/goal/datapoints.json",
|
|
||||||
"method": "POST",
|
|
||||||
"json": {
|
|
||||||
"auth_token": "XXXXXX",
|
|
||||||
"value": "5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"errors": {
|
|
||||||
"value": [
|
|
||||||
"syntax error"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response-headers": {
|
|
||||||
"status": 422,
|
|
||||||
"content-type": "application/json; charset=utf-8"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"api_url": "https://www.beeminder.com/api/v1/users/me.json",
|
||||||
|
"method": "GET",
|
||||||
|
"params": {
|
||||||
|
"auth_token": "XXXXXX"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"username": "testuser",
|
||||||
|
"timezone": "Asia/Kolkata",
|
||||||
|
"goals": [
|
||||||
|
"gainweight"
|
||||||
|
],
|
||||||
|
"updated_at": 1527962842,
|
||||||
|
"deadbeat": false,
|
||||||
|
"has_authorized_fitbit": false,
|
||||||
|
"default_leadtime": 0,
|
||||||
|
"default_alertstart": 82620,
|
||||||
|
"default_deadline": -3000,
|
||||||
|
"subscription": null,
|
||||||
|
"subs_downto": null,
|
||||||
|
"subs_freq": null,
|
||||||
|
"subs_lifetime": null,
|
||||||
|
"remaining_subs_credit": 0,
|
||||||
|
"id": "5a7c8509bfec03755800544a"
|
||||||
|
},
|
||||||
|
"response-headers": {
|
||||||
|
"status": 200,
|
||||||
|
"content-type": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,61 +22,87 @@ following the syntax shown below :smile:.\n \
|
||||||
|
|
||||||
def test_bot_responds_to_empty_message(self) -> None:
|
def test_bot_responds_to_empty_message(self) -> None:
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
self.mock_http_conversation('test_blank_input'):
|
self.mock_http_conversation('test_valid_auth_token'):
|
||||||
self.verify_reply('', self.help_message)
|
self.verify_reply('', self.help_message)
|
||||||
|
|
||||||
def test_help_message(self) -> None:
|
def test_help_message(self) -> None:
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
self.mock_http_conversation('test_help_message'):
|
self.mock_http_conversation('test_valid_auth_token'):
|
||||||
self.verify_reply('help', self.help_message)
|
self.verify_reply('help', self.help_message)
|
||||||
|
|
||||||
def test_message_with_daystamp_and_value(self) -> None:
|
def test_message_with_daystamp_and_value(self) -> None:
|
||||||
bot_response = '[Datapoint](https://www.beeminder.com/aaron/goal) created.'
|
bot_response = '[Datapoint](https://www.beeminder.com/aaron/goal) created.'
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_valid_auth_token'), \
|
||||||
self.mock_http_conversation('test_message_with_daystamp_and_value'):
|
self.mock_http_conversation('test_message_with_daystamp_and_value'):
|
||||||
self.verify_reply('20180602, 2', bot_response)
|
self.verify_reply('20180602, 2', bot_response)
|
||||||
|
|
||||||
def test_message_with_value_and_comment(self) -> None:
|
def test_message_with_value_and_comment(self) -> None:
|
||||||
bot_response = '[Datapoint](https://www.beeminder.com/aaron/goal) created.'
|
bot_response = '[Datapoint](https://www.beeminder.com/aaron/goal) created.'
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_valid_auth_token'), \
|
||||||
self.mock_http_conversation('test_message_with_value_and_comment'):
|
self.mock_http_conversation('test_message_with_value_and_comment'):
|
||||||
self.verify_reply('2, hi there!', bot_response)
|
self.verify_reply('2, hi there!', bot_response)
|
||||||
|
|
||||||
def test_message_with_daystamp_and_value_and_comment(self) -> None:
|
def test_message_with_daystamp_and_value_and_comment(self) -> None:
|
||||||
bot_response = '[Datapoint](https://www.beeminder.com/aaron/goal) created.'
|
bot_response = '[Datapoint](https://www.beeminder.com/aaron/goal) created.'
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_valid_auth_token'), \
|
||||||
self.mock_http_conversation('test_message_with_daystamp_and_value_and_comment'):
|
self.mock_http_conversation('test_message_with_daystamp_and_value_and_comment'):
|
||||||
self.verify_reply('20180602, 2, hi there!', bot_response)
|
self.verify_reply('20180602, 2, hi there!', bot_response)
|
||||||
|
|
||||||
def test_syntax_error(self) -> None:
|
def test_syntax_error(self) -> None:
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
self.mock_http_conversation('test_syntax_error'):
|
self.mock_http_conversation('test_valid_auth_token'):
|
||||||
bot_response = "Make sure you follow the syntax.\n You can take a look \
|
bot_response = "Make sure you follow the syntax.\n You can take a look \
|
||||||
at syntax by: @mention-botname help"
|
at syntax by: @mention-botname help"
|
||||||
self.verify_reply("20180303, 50, comment, redundant comment", bot_response)
|
self.verify_reply("20180303, 50, comment, redundant comment", bot_response)
|
||||||
|
|
||||||
def test_connection_error(self) -> None:
|
def test_connection_error_when_handle_message(self) -> None:
|
||||||
with self.mock_config_info(self.normal_config), \
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_valid_auth_token'), \
|
||||||
patch('requests.post', side_effect=ConnectionError()), \
|
patch('requests.post', side_effect=ConnectionError()), \
|
||||||
patch('logging.exception'):
|
patch('logging.exception'):
|
||||||
self.verify_reply('?$!', 'Uh-Oh, couldn\'t process the request \
|
self.verify_reply('?$!', 'Uh-Oh, couldn\'t process the request \
|
||||||
right now.\nPlease try again later')
|
right now.\nPlease try again later')
|
||||||
|
|
||||||
def test_error(self) -> None:
|
def test_invalid_when_handle_message(self) -> None:
|
||||||
bot_request = 'notNumber'
|
|
||||||
bot_response = "Error occured : 422"
|
|
||||||
with self.mock_config_info(self.normal_config), \
|
|
||||||
self.mock_http_conversation('test_error'):
|
|
||||||
self.verify_reply(bot_request, bot_response)
|
|
||||||
|
|
||||||
def test_invalid(self) -> None:
|
|
||||||
bot = get_bot_message_handler(self.bot_name)
|
bot = get_bot_message_handler(self.bot_name)
|
||||||
bot_handler = StubBotHandler()
|
bot_handler = StubBotHandler()
|
||||||
|
|
||||||
with self.mock_config_info({'auth_token': 'someInvalidKey',
|
with self.mock_config_info({'auth_token': 'someInvalidKey',
|
||||||
'username': 'aaron',
|
'username': 'aaron',
|
||||||
'goalname': 'goal',
|
'goalname': 'goal'}), \
|
||||||
"value": "5"}), \
|
patch('requests.get', side_effect=ConnectionError()), \
|
||||||
self.mock_http_conversation('test_invalid'), \
|
self.mock_http_conversation('test_invalid_when_handle_message'), \
|
||||||
|
patch('logging.exception'):
|
||||||
|
self.verify_reply('5', 'Error. Check your key!')
|
||||||
|
|
||||||
|
def test_error(self) -> None:
|
||||||
|
bot_request = 'notNumber'
|
||||||
|
bot_response = "Error occured : 422"
|
||||||
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
self.mock_http_conversation('test_valid_auth_token'), \
|
||||||
|
self.mock_http_conversation('test_error'):
|
||||||
|
self.verify_reply(bot_request, bot_response)
|
||||||
|
|
||||||
|
def test_invalid_when_initialize(self) -> None:
|
||||||
|
bot = get_bot_message_handler(self.bot_name)
|
||||||
|
bot_handler = StubBotHandler()
|
||||||
|
|
||||||
|
with self.mock_config_info({'auth_token': 'someInvalidKey',
|
||||||
|
'username': 'aaron',
|
||||||
|
'goalname': 'goal'}), \
|
||||||
|
self.mock_http_conversation('test_invalid_when_initialize'), \
|
||||||
self.assertRaises(bot_handler.BotQuitException):
|
self.assertRaises(bot_handler.BotQuitException):
|
||||||
bot.initialize(bot_handler)
|
bot.initialize(bot_handler)
|
||||||
|
|
||||||
|
def test_connection_error_during_initialize(self) -> None:
|
||||||
|
bot = get_bot_message_handler(self.bot_name)
|
||||||
|
bot_handler = StubBotHandler()
|
||||||
|
|
||||||
|
with self.mock_config_info(self.normal_config), \
|
||||||
|
patch('requests.get', side_effect=ConnectionError()), \
|
||||||
|
patch('logging.exception') as mock_logging:
|
||||||
|
bot.initialize(bot_handler)
|
||||||
|
self.assertTrue(mock_logging.called)
|
||||||
|
|
Loading…
Reference in a new issue