diff --git a/legos/cryptocurrency.py b/legos/cryptocurrency.py index 849fa19..e61e524 100644 --- a/legos/cryptocurrency.py +++ b/legos/cryptocurrency.py @@ -26,8 +26,8 @@ def handle(self, message): try: query = message['text'].split()[1] - except: - self.reply(message, "Invalid query", opts) + except IndexError: + self.reply(message, "Invalid query. Not enough arguments.", opts) self.reply(message, self._lookup_symbol(query), opts) @@ -43,18 +43,23 @@ def _lookup_symbol(self, query): api_response = requests.get(request_url, params=params) if api_response.status_code == requests.codes.ok: api_response = json.loads(api_response.text) - if 'There is no data for the symbol' in api_response['Message']: + if 'Message' in api_response and \ + 'There is no data for the symbol' in api_response['Message']: matched_items = self._search_symbol(query) - params['fsym'] = matched_items[0]['symbol'] - api_response = requests.get(request_url, params=params) - if api_response.status_code == requests.codes.ok: - api_response = json.loads(api_response.text) - query = matched_items[0]['symbol'] - meta = 'Did you mean {}?'.format(matched_items[0]['name']) - return self._parse_api_response( - api_response, query, meta=meta) + if len(matched_items) > 0: + params['fsym'] = matched_items[0]['symbol'] + api_response = requests.get(request_url, params=params) + if api_response.status_code == requests.codes.ok: + api_response = json.loads(api_response.text) + query = matched_items[0]['symbol'] + meta = 'Did you mean {}?'.format( + matched_items[0]['name']) + return self._parse_api_response( + api_response, query, meta=meta) + else: + return 'We had trouble getting that ticker price.' else: - return 'We had trouble getting that ticker price.' + return 'Could not match "{}" to a symbol.'.format(query) else: return self._parse_api_response(api_response, query) else: @@ -71,7 +76,8 @@ def _search_symbol(self, query): matched_items = [] for coin in api_list['Data']: full_name = api_list['Data'][coin]['FullName'] - if query in full_name.lower(): + logger.debug('FULL NAME: ' + full_name) + if query.lower() in full_name.lower(): matched_items.append({"symbol": coin, "name": full_name}) return matched_items @@ -80,9 +86,10 @@ def _search_symbol(self, query): return 'There was an error fetching the list' def _parse_api_response(self, api_response, query, **kwargs): + return_val = '' if 'meta' in kwargs: - return_val = kwargs['meta'] + '\n' - return_val = return_val + query + ': | ' + return_val += kwargs['meta'] + '\n' + return_val += query + ': | ' for key, value in api_response.items(): return_val += '{} {} | '.format(value, key) if query == 'DOGE': @@ -93,6 +100,6 @@ def get_name(self): return 'crypto' def get_help(self): - return '''Lookup a crypto symbol's value. Usage: !crypto . - List of symbols here - https://min-api.cryptocompare.com/data/all/coinlist.''' + return ('Lookup a crypto symbol\'s value. Usage: !crypto .\n' + 'List of symbols here:\n' + 'https://min-api.cryptocompare.com/data/all/coinlist.') diff --git a/legos/hodl.py b/legos/hodl.py new file mode 100644 index 0000000..0a83f51 --- /dev/null +++ b/legos/hodl.py @@ -0,0 +1,185 @@ +from Legobot.Lego import Lego +import requests +import logging +import json +import configparser + +logger = logging.getLogger(__name__) + + +class Hodl(Lego): + def __init__(self, baseplate, lock): + super().__init__(baseplate, lock) + self.hodl = self._config_init() + + def listening_for(self, message): + if message['text'] is not None: + try: + command = message['text'].split()[0] + return command == '!hodl' + except Exception as e: + logger.error('''Stocks lego failed to check message text: + {}'''.format(e)) + return False + + def handle(self, message): + try: + target = message['metadata']['source_channel'] + opts = {'target': target} + except IndexError: + logger.error('''Could not identify message source in message: + {}'''.format(message)) + + message_list = message['text'].split() + try: + self.reply(message, self._parse_multi_commands(message_list), opts) + except Exception as e: + self.reply(message, 'An Error Ocurred: ' + e, opts) + + def _config_init(self): + hodl = configparser.ConfigParser() + hodl.read('hodl.ini') + if len(hodl) == 0 or 'hodl' not in hodl.sections(): + logger.warning('No hodl ini file or file contains no config. ' + 'Loading Defaults') + hodl['hodl'] = {} + hodl['hodl']['convert_from'] = 'BTC' + hodl['hodl']['convert_to'] = 'USD,BTC' + with open('hodl.ini', 'w') as configfile: + hodl.write(configfile) + return hodl + + def _parse_multi_commands(self, message_list): + if len(message_list) == 1: + return self._lookup_multi() + elif len(message_list) > 1: + case_dict = {} + case_dict['list'] = self._list_hodl_symbols + case_dict['add'] = self._add_symbols + case_dict['drop'] = self._drop_symbols + try: + return case_dict[message_list[1]](message_list) + except Exception as e: + return 'Argument error: ' + e + + def _list_hodl_symbols(self, message_list): + convert_from = self.hodl['hodl']['convert_from'] + convert_to = self.hodl['hodl']['convert_to'] + return_val = '' + return_val += 'Convert From: ' + convert_from + '\n' + return_val += 'Convert To: ' + convert_to + '\n' + return return_val + + def _add_symbols(self, message_list): + if len(message_list) < 3: + return ('Please supply additional arguments, e.g.:\n' + '!hodl add from BTC,LTC') + elif message_list[2] == 'from': + return self._add_from_symbols(message_list) + elif message_list[2] == 'to': + return self._add_to_symbols(message_list) + else: + return 'There was an issue processing your request.' + + def _add_from_symbols(self, message_list): + try: + add_convert_from = message_list[3].split(',') + old_convert_from = self.hodl['hodl']['convert_from'].split(',') + new_convert_from = list(set(old_convert_from + add_convert_from)) + self.hodl['hodl']['convert_from'] = ','.join(new_convert_from) + with open('hodl.ini', 'w') as configfile: + self.hodl.write(configfile) + return self._list_hodl_symbols(message_list) + except: + return ('Please supply additional arguments, e.g.:\n' + '!hodl add from BTC,LTC') + + def _add_to_symbols(self, message_list): + try: + add_convert_to = message_list[3].split(',') + old_convert_to = self.hodl['hodl']['convert_to'].split(',') + new_convert_to = list(set(old_convert_to + add_convert_to)) + self.hodl['hodl']['convert_to'] = ','.join(new_convert_to) + with open('hodl.ini', 'w') as configfile: + self.hodl.write(configfile) + return self._list_hodl_symbols(message_list) + except: + return ('Please supply additional arguments, e.g.:\n' + '!hodl add to BTC,LTC') + + def _drop_symbols(self, message_list): + if len(message_list) < 3: + return ('Please supply additional arguments, e.g.:\n' + '!hodl drop from BTC') + elif message_list[2] == 'from': + return self._drop_from_symbols(message_list) + elif message_list[2] == 'to': + return self._drop_to_symbols(message_list) + else: + return 'There was an issue processing your request.' + + def _drop_from_symbols(self, message_list): + try: + drop_convert_from = message_list[3].split(',') + old_convert_from = self.hodl['hodl']['convert_from'].split(',') + new_convert_from = set(old_convert_from).symmetric_difference( + set(drop_convert_from)) + self.hodl['hodl']['convert_from'] = ','.join(new_convert_from) + with open('hodl.ini', 'w') as configfile: + self.hodl.write(configfile) + return self._list_hodl_symbols(message_list) + except: + return ('Please supply additional arguments, e.g.:\n' + '!hodl drop from BTC,LTC') + + def _drop_to_symbols(self, message_list): + try: + drop_convert_to = message_list[3].split(',') + old_convert_to = self.hodl['hodl']['convert_to'].split(',') + new_convert_to = set(old_convert_to).symmetric_difference( + set(drop_convert_to)) + self.hodl['hodl']['convert_to'] = ','.join(new_convert_to) + with open('hodl.ini', 'w') as configfile: + self.hodl.write(configfile) + return self._list_hodl_symbols(message_list) + except: + return ('Please supply additional arguments, e.g.:\n' + '!hodl drop to BTC,LTC') + + def _lookup_multi(self): + multi_url = self._build_index_url() + get_multi = requests.get(multi_url) + if get_multi.status_code == requests.codes.ok: + api_response = json.loads(get_multi.text) + return self._parse_multi_price_response(api_response) + else: + return 'There was an error getting the data: ' + get_multi.text + + def _parse_multi_price_response(self, api_response): + return_val = '' + for key, value in api_response.items(): + return_val += key + ': | ' + for key, value in value.items(): + return_val += '{} {} | '.format(value, key) + return_val += '\n' + return return_val + + def _build_index_url(self): + baseurl = 'https://min-api.cryptocompare.com/data/pricemulti' + convert_from = self.hodl['hodl']['convert_from'] + convert_to = self.hodl['hodl']['convert_to'] + return baseurl + '?fsyms=' + convert_from + '&tsyms=' + convert_to + + def get_name(self): + return 'hodl' + + def get_help(self): + return ('Lookup multiple crypto symbol\'s values from saved list.\n' + 'List of symbols here: ' + 'https://min-api.cryptocompare.com/data/all/coinlist.\n' + 'Usage:\n' + '!hodl -- returns prices for multiple coins at once.\n' + '!hodl list -- returns the list of coins to convert from/to.\n' + '!hodl ' + ' -- adds or drop list of symbols to the convert to or convert' + ' from list.') diff --git a/legos/stocks.py b/legos/stocks.py index 57f5ff2..5cb345b 100644 --- a/legos/stocks.py +++ b/legos/stocks.py @@ -3,6 +3,7 @@ import json from Legobot.Lego import Lego from .cryptocurrency import Cryptocurrency # noqa: F401 +from .hodl import Hodl # noqa: F401 logger = logging.getLogger(__name__) diff --git a/requirements.txt b/requirements.txt index c88e02e..43da296 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ requests +configparser bandit==1.3.0 pytest==3.0.5 flake8==3.2.1