From 76941a92aec805e59124741f2992435cc7fe75bf Mon Sep 17 00:00:00 2001 From: Timothy Machnacki Date: Fri, 22 Apr 2022 15:53:25 -0400 Subject: [PATCH] Add a bot to fetch crytpo information. Fetches current market price for a provided cryptocurrency in USD. It can also return the market price for a cryptocurrency given a specified date. Usage: @-mention Tested against unit tests and on local development environment. TODO: Test in production server. --- zulip_bots/zulip_bots/bots/crypto/__init__.py | 0 zulip_bots/zulip_bots/bots/crypto/crypto.py | 87 +++++++++++++++++++ zulip_bots/zulip_bots/bots/crypto/doc.md | 18 ++++ .../bots/crypto/fixtures/test_404.json | 11 +++ .../crypto/fixtures/test_normal_date.json | 22 +++++ .../crypto/fixtures/test_normal_no_date.json | 19 ++++ .../zulip_bots/bots/crypto/test_crypto.py | 57 ++++++++++++ 7 files changed, 214 insertions(+) create mode 100644 zulip_bots/zulip_bots/bots/crypto/__init__.py create mode 100644 zulip_bots/zulip_bots/bots/crypto/crypto.py create mode 100644 zulip_bots/zulip_bots/bots/crypto/doc.md create mode 100644 zulip_bots/zulip_bots/bots/crypto/fixtures/test_404.json create mode 100644 zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_date.json create mode 100644 zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_no_date.json create mode 100644 zulip_bots/zulip_bots/bots/crypto/test_crypto.py diff --git a/zulip_bots/zulip_bots/bots/crypto/__init__.py b/zulip_bots/zulip_bots/bots/crypto/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zulip_bots/zulip_bots/bots/crypto/crypto.py b/zulip_bots/zulip_bots/bots/crypto/crypto.py new file mode 100644 index 0000000000..cfb24a50c8 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/crypto/crypto.py @@ -0,0 +1,87 @@ +# bot to fetch crypto information from coinbase API. +# No API key authentication is required for pricing +# and time information. + +from datetime import datetime +from typing import Any, Dict + +import requests +from requests.exceptions import ConnectionError, HTTPError + +from zulip_bots.lib import BotHandler + + +class CryptoHandler: + """ + This bot will get the current spot "market" exchange rate for a given + cryptocurrency in USD. + """ + def usage(self): + return """ + This bot allows users to get spot prices for requested cryptocurrencies in USD. + Users should @-mention the bot with the following format: + @-mention + i.e., "@-mention BTC 2022-04-16" or just "@-mention BTC" + """ + + def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler): + original_content = message["content"] + args = original_content.split() + if len(args) == 0 or len(args) > 2: + bot_handler.send_reply(message, self.usage()) + return + + date_param = None + if len(args) == 2: + date_param = {"date": args[1]} + + # check format of date input + if date_param: + format = "%Y-%m-%d" + + try: + datetime.strptime(date_param["date"], format) + except ValueError: + reply = "Dates should be in the form YYYY-MM-DD." + bot_handler.send_reply(message, reply) + return + + currency_param = args[0] + + try: + if date_param: + response = requests.get( + "https://api.coinbase.com/v2/prices/{}-USD/spot".format(currency_param), + params=date_param + ) + else: + response = requests.get( + "https://api.coinbase.com/v2/prices/{}-USD/spot".format(currency_param) + ) + + # raise exception for bad status codes + response.raise_for_status() + except (HTTPError, ConnectionError): + reply = ( + "Sorry, I wasn't able to find anything on {}. " + "Check your spelling and try again." + ).format(currency_param) + + bot_handler.send_reply(message, reply) + return + + market_price = response.json()["data"]["amount"] + + if date_param: + reply = ( + "The market price for {} on {} was ${}" + ).format(currency_param, date_param["date"], market_price) + else: + reply = ( + "The current market price for {} is ${}" + ).format(currency_param, market_price) + + bot_handler.send_reply(message, reply) + + +handler_class = CryptoHandler diff --git a/zulip_bots/zulip_bots/bots/crypto/doc.md b/zulip_bots/zulip_bots/bots/crypto/doc.md new file mode 100644 index 0000000000..77e2073250 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/crypto/doc.md @@ -0,0 +1,18 @@ +# crypto bot + +The crypto bot is a Zulip bot that can fetch the +current market price for a specified cryptocurrency in USD. +The crypto bot can also retrieve a market price for +a cryptocurrency from a given date in the form YYYY-MM-DD. + +To get the current market price: +``` +@crypto BTC +> The current market price for BTC is $40696.73 +``` + +To get the price on a given date: +``` +@crypto BTC 2022-04-16 +> The market price for BTC on 2022-04-16 was $40554.6 +``` \ No newline at end of file diff --git a/zulip_bots/zulip_bots/bots/crypto/fixtures/test_404.json b/zulip_bots/zulip_bots/bots/crypto/fixtures/test_404.json new file mode 100644 index 0000000000..3d6ecd5b1d --- /dev/null +++ b/zulip_bots/zulip_bots/bots/crypto/fixtures/test_404.json @@ -0,0 +1,11 @@ +{ + "request": { + "api_url": "https://api.coinbase.com/v2/prices/XYZ-USD/spot" + }, + "response": {}, + "response-headers": { + "status": 404, + "ok": false, + "content-type": "application/json; charset=utf-8" + } + } \ No newline at end of file diff --git a/zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_date.json b/zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_date.json new file mode 100644 index 0000000000..5127d1a7a1 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_date.json @@ -0,0 +1,22 @@ +{ + "request": { + "api_url": "https://api.coinbase.com/v2/prices/BTC-USD/spot", + "params": { + "date": "2022-04-16" + } + }, + "response": { + "meta": { + "status": 200 + }, + "data": { + "amount": 40554.6, + "base" : "BTC", + "currency": "USD" + } + }, + "response-headers": { + "status": 200, + "content-type": "application/json; charset=utf-8" + } +} \ No newline at end of file diff --git a/zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_no_date.json b/zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_no_date.json new file mode 100644 index 0000000000..86d7cd15f4 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/crypto/fixtures/test_normal_no_date.json @@ -0,0 +1,19 @@ +{ + "request": { + "api_url": "https://api.coinbase.com/v2/prices/BTC-USD/spot" + }, + "response": { + "meta": { + "status": 200 + }, + "data": { + "amount": 40696.73, + "base" : "BTC", + "currency": "USD" + } + }, + "response-headers": { + "status": 200, + "content-type": "application/json; charset=utf-8" + } +} \ No newline at end of file diff --git a/zulip_bots/zulip_bots/bots/crypto/test_crypto.py b/zulip_bots/zulip_bots/bots/crypto/test_crypto.py new file mode 100644 index 0000000000..f9bcbe40e1 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/crypto/test_crypto.py @@ -0,0 +1,57 @@ +from zulip_bots.test_lib import BotTestCase, DefaultTests + + +class TestCryptoBot(BotTestCase, DefaultTests): + bot_name = "crypto" + + # Test for correct behavior given proper crypto and date + def test_normal_date(self): + bot_response = "The market price for BTC on 2022-04-16 was $40554.6" + + with self.mock_http_conversation("test_normal_date"): + self.verify_reply("BTC 2022-04-16", bot_response) + + # test for "current" price + def test_normal_no_date(self): + bot_response = "The current market price for BTC is $40696.73" + + with self.mock_http_conversation("test_normal_no_date"): + self.verify_reply("BTC", bot_response) + + # test malformatted date + def test_bad_date(self): + bot_response = "Dates should be in the form YYYY-MM-DD." + + self.verify_reply("BTC 04-16-2022", bot_response) + + # test typo --> Not Found + def test_400_error(self): + bot_response = ( + "Sorry, I wasn't able to find anything on XYZ. " + "Check your spelling and try again." + ) + + with self.mock_http_conversation("test_404"): + self.verify_reply("XYZ", bot_response) + + # test empty message + def test_no_inputs(self): + bot_reponse = """ + This bot allows users to get spot prices for requested cryptocurrencies in USD. + Users should @-mention the bot with the following format: + @-mention + i.e., "@-mention BTC 2022-04-16" or just "@-mention BTC" + """ + + self.verify_reply("", bot_reponse) + + # test too many arguments + def test_too_many_inputs(self): + bot_response = """ + This bot allows users to get spot prices for requested cryptocurrencies in USD. + Users should @-mention the bot with the following format: + @-mention + i.e., "@-mention BTC 2022-04-16" or just "@-mention BTC" + """ + + self.verify_reply("BTC ETH 2022-04-16", bot_response)