diff --git a/zulip_bots/zulip_bots/bots/newsboy/__init__.py b/zulip_bots/zulip_bots/bots/newsboy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/zulip_bots/zulip_bots/bots/newsboy/assets/commands.png b/zulip_bots/zulip_bots/bots/newsboy/assets/commands.png new file mode 100644 index 000000000..ec2e413b4 Binary files /dev/null and b/zulip_bots/zulip_bots/bots/newsboy/assets/commands.png differ diff --git a/zulip_bots/zulip_bots/bots/newsboy/assets/help.png b/zulip_bots/zulip_bots/bots/newsboy/assets/help.png new file mode 100644 index 000000000..0c3b76dd4 Binary files /dev/null and b/zulip_bots/zulip_bots/bots/newsboy/assets/help.png differ diff --git a/zulip_bots/zulip_bots/bots/newsboy/assets/news.png b/zulip_bots/zulip_bots/bots/newsboy/assets/news.png new file mode 100644 index 000000000..286601662 Binary files /dev/null and b/zulip_bots/zulip_bots/bots/newsboy/assets/news.png differ diff --git a/zulip_bots/zulip_bots/bots/newsboy/doc.md b/zulip_bots/zulip_bots/bots/newsboy/doc.md new file mode 100644 index 000000000..2f5e2b9c1 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/newsboy/doc.md @@ -0,0 +1,44 @@ +# Newsboy + +The Newsboy bot is a Zulip bot that fetches the top national news of particular country and sends them to the user. + +To use the Newsboy bot, you can simply call it with `@` followed +by a command, like so: + +``` +@Newsboy help +``` + +## Setup + +Before usage, you will need to configure the bot by putting the value of the `` in the config file. +To do this, follow the given steps: + +1. Go to [this]( https://newsdata.io/api-key) link after logging in at [newsdata.io]( https://newsdata.io). +2. Continue to get your `api_key`. +3. Open up `zulip_bots/bots/newsboy/newsboy.conf` in an editor and change the value of the `` attributes to the corresponding noted values. + +## Developer Notes + +Be sure to add the additional commands and their descriptions to the `supported_commands` +list in `newsboy.py` so that they can be displayed with the other available commands using +`@ list-commands`. Also modify the `test_list_commands_command` in +`test_newsboy.py`. + +## Usage + +`@newsboy list-commands` - This command gives a list of all available commands along with +short descriptions. + +Example: + **`list-commands`** + +![](assets/commands.png) + + **`@bot_name help`** + +![](assets/help.png) + + **`get-top-news `** + +![](assets/news.png) diff --git a/zulip_bots/zulip_bots/bots/newsboy/newsboy.conf b/zulip_bots/zulip_bots/bots/newsboy/newsboy.conf new file mode 100644 index 000000000..52d927942 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/newsboy/newsboy.conf @@ -0,0 +1,2 @@ +[newsboy] +api_key = \ No newline at end of file diff --git a/zulip_bots/zulip_bots/bots/newsboy/newsboy.py b/zulip_bots/zulip_bots/bots/newsboy/newsboy.py new file mode 100644 index 000000000..dd5a26718 --- /dev/null +++ b/zulip_bots/zulip_bots/bots/newsboy/newsboy.py @@ -0,0 +1,175 @@ +from typing import Any, Dict, List, Optional + +import requests + +from zulip_bots.lib import BotHandler + +INVALID_ARGUMENTS_ERROR_MESSAGE = "Invalid Arguments." +RESPONSE_ERROR_MESSAGE = "Invalid Response. Please check configuration and parameters." + + +class NewsboyHandler: + def initialize(self, bot_handler: BotHandler) -> None: + self.supported_commands = [ + ("help", "Get the bot usage information."), + ("list-commands", "Get information about the commands supported by the bot."), + ("get-top-news ", "Get top news of mention country e.g. (get-top-news us)."), + ("list-countries", "Get the list of all supported countries."), + ] + self.config_info = bot_handler.get_config_info("newsboy") + self.api_key = self.config_info["api_key"] + + self.check_api_key(bot_handler) + + def check_api_key(self, bot_handler: BotHandler) -> None: + test_query_response = requests.get( + "https://newsdata.io/api/1/news", params={"apikey": self.api_key} + ) + try: + if test_query_response.json()["status"] == "error": + bot_handler.quit( + "Invalid Credentials. Please see doc.md to find out how to get them." + ) + except AttributeError: + pass + + def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: + + content = message["content"].strip().split() + + if content == []: + bot_handler.send_reply(message, "Empty Query") + return + + content[0] = content[0].lower() + + if content == ["help"]: + bot_reply = self.usage() + elif content == ["list-commands"]: + bot_reply = self.get_all_supported_commands() + elif content == ["list-countries"]: + bot_reply = self.get_all_supported_countries() + elif content[0] == "get-top-news": + bot_reply = self.get_news_response(content, self.api_key) + else: + bot_reply = "Command not supported" + + bot_handler.send_reply(message, bot_reply) + + def get_news_response(self, content: List[str], api_key: str) -> Optional[str]: + if len(content) < 2: + return INVALID_ARGUMENTS_ERROR_MESSAGE + + base_url = "https://newsdata.io/api/1/news" + country = content[1] + + params = {"apikey": api_key, "country": country, "q": "national", "language": "en"} + try: + response = requests.get(base_url, params=params).json() + data = response["results"] if response["status"] == "success" else None + + for dt in data: + try: + title = dt["title"] + descr = dt["description"] + link = dt["link"] + image = dt["image_url"] + if ( + title is not None + and descr is not None + and link is not None + and image is not None + ): + return f"## [{title}]({link})\n\n > ***{descr}*** " + except Exception: + continue + except Exception as e: + return (RESPONSE_ERROR_MESSAGE, str(e)) + + def get_all_supported_countries(self) -> str: + countries = """ + Argentina - ar \n + Australia - au \n + Austria - at \n + Belgium - be \n + Brazil - br \n + Bulgaria - bg \n + Canada - ca \n + China - cn \n + Colombia - co \n + Cuba - cu \n + Czech republic - cz \n + Egypt - eg \n + France - fr \n + Germany - de \n + Greece - gr \n + Hong kong - hk \n + Hungary - hu \n + India - in \n + Indonesia - id \n + Ireland - ie \n + Israel - il \n + Italy - it \n + Japan - jp \n + Kazakhstan - kz \n + Latvia - lv \n + Lebanon - lb \n + Lithuania - lt \n + Malaysia - my \n + Mexico - mx \n + Morocco - ma \n + Netherland - nl \n + New zealand - nz \n + Nigeria - ng \n + North korea - kp \n + Norway - no \n + Pakistan - pk \n + Peru - pe \n + Philippines - ph \n + Poland - pl \n + Portugal - pt \n + Romania - ro \n + Russia - ru \n + Saudi arabia - sa \n + Serbia - rs \n + Singapore - sg \n + Slovakia - sk \n + Slovenia - si \n + South africa - za \n + South korea - kr \n + Spain - es \n + Sweden - se \n + Switzerland - ch \n + Taiwan - tw \n + Thailand - th \n + Turkey - tr \n + Ukraine - ua \n + United arab emirates - ae \n + United kingdom - gb \n + United states of america - us \n + Venezuela - ve \n + """ + return countries + + def get_all_supported_commands(self) -> str: + bot_response = "**Commands:** \n" + for index, (command, desc) in enumerate(self.supported_commands): + bot_response += f"{index + 1}. **{command}**: {desc}\n" + + return bot_response + + def usage(self) -> str: + help_content = """ + ## Newsboy + The Newsboy bot is a Zulip bot that fetches the top national news of particular country and + displays it to the user with headline and short description. + + Use `list-commands` to get information about the supported commands. + + Usage: + `get-top-news ` e.g. `get-top-news us` + """ + return help_content + + +handler_class = NewsboyHandler diff --git a/zulip_bots/zulip_bots/bots/newsboy/test_newsboy.py b/zulip_bots/zulip_bots/bots/newsboy/test_newsboy.py new file mode 100644 index 000000000..1514dffac --- /dev/null +++ b/zulip_bots/zulip_bots/bots/newsboy/test_newsboy.py @@ -0,0 +1,59 @@ +import unittest +from unittest.mock import patch + +from zulip_bots.test_lib import BotTestCase, DefaultTests + +mock_config = {"api_key": "TEST"} + + +class Testnewsbot(BotTestCase, DefaultTests): + bot_name = "newsboy" + + def test_bot_responds_to_empty_message(self) -> None: + with self.mock_config_info(mock_config), patch("requests.get"): + self.verify_reply("", "Empty Query") + + def test_bot_usage(self) -> None: + with self.mock_config_info(mock_config), patch("requests.get"): + self.verify_reply( + "help", + """ + ## Newsboy + The Newsboy bot is a Zulip bot that fetches the top national news of particular country and + displays it to the user with headline and short description. + + Use `list-commands` to get information about the supported commands. + + Usage: + `get-top-news ` e.g. `get-top-news us` + """, + ) + + def test_invalid_command(self) -> None: + with self.mock_config_info(mock_config), patch("requests.get"): + self.verify_reply("abcd", "Command not supported") + + def test_list_commands_command(self) -> None: + expected_reply = ( + "**Commands:** \n" + "1. **help**: Get the bot usage information.\n" + "2. **list-commands**: Get information about the commands supported by the bot.\n" + "3. **get-top-news **: Get top news of mention country e.g. (get-top-news us).\n" + "4. **list-countries**: Get the list of all supported countries.\n" + ) + + with self.mock_config_info(mock_config), patch("requests.get"): + self.verify_reply("list-commands", expected_reply) + + def test_command_invalid_arguments(self) -> None: + """Add appropriate tests here for all additional commands with more than one arguments. + This ensures consistency.""" + + expected_error_response = "Invalid Arguments." + + with self.mock_config_info(mock_config), patch("requests.get"): + self.verify_reply("get-top-news", expected_error_response) + + +if __name__ == "__main__": + unittest.main()