stack_overflow : Create StackOverflow bot.
(Use stackoverflow APIs to answer queries.)
ADD
zulip_bots/zulip_bots/bots/stack_overflow/__init__.py
zulip_bots/zulip_bots/bots/stack_overflow/__init__.py
ADD
zulip_bots/zulip_bots/bots/stack_overflow/doc.md
+# StackOverflow Bot
+
+The StackOverflow bot is a Zulip bot that will search Stackoverflow
+for a provided set of keywords or a question, and fetch a link to the associated
+query. The link is returned to the same stream
+it was @mentioned in
+
+The Stackoverflow bot uses the
+[StackExchange API](http://api.stackexchange.com/docs)
+to obtain the search results it returns
+
+Using the StackOverflow bot is as simple as mentioning @\<stackoverflow-bot-name\>,
+followed by the query:
+
+```
+@<stackoverflow-bot-name> <query>
+```
+
+## Setup
+
+Beyond the typical obtaining of the zuliprc file, no extra setup is required to use the StackOverflow Bot
+
+## Usage
+
+1. ```@<stackoverflow-bot-name> <query>``` -
+fetches the link to the appropriate StackOverflow questions.
+
+ * For example, `@<stackoverflow-bot-name> rest api`
+will return the links having questions related to rest api.
+<br>
+
+2. If there are no questions related to the query,
+the bot will respond with an error message:
+
+ `I am sorry. The search query you provided is does not have any related results.`
+
+<br>
+
+3. If no query is provided, the bot will return the help text:
+
+ ```Please enter your message after @mention-bot```

ADD
zulip_bots/zulip_bots/bots/stack_overflow/fixtures/test_incorrect_query.json
+{
+ "request": {
+ "api_url":"http://api.stackexchange.com/2.2/search/advanced?order=desc&sort=relevance&site=stackoverflow&title=narendra"
+ },
+ "response": {
+ "data": {
+ "status_code":200
+ },
+ "items": [
+ ]
+ },
+ "response-headers":{
+ "status":200,
+ "ok":true,
+ "content-type":"application/json; charset=utf-8"
+ }
+}

ADD
zulip_bots/zulip_bots/bots/stack_overflow/fixtures/test_multi_word.json
+{
+ "request": {
+ "api_url":"http://api.stackexchange.com/2.2/search/advanced?order=desc&sort=relevance&site=stackoverflow&title=what%20is%20flutter"
+ },
+ "response": {
+ "data": {
+ "status_code":200
+ },
+ "items": [
+ {
+ "title":"What is flutter/dart and what are its benefits over other tools?",
+ "link":"https://stackoverflow.com/questions/49023008/what-is-flutter-dart-and-what-are-its-benefits-over-other-tools"
+ }
+ ]
+ },
+ "response-headers":{
+ "status":200,
+ "ok":true,
+ "content-type":"application/json; charset=utf-8"
+ }
+}

ADD
zulip_bots/zulip_bots/bots/stack_overflow/fixtures/test_number_query.json
+{
+ "request": {
+ "api_url":"http://api.stackexchange.com/2.2/search/advanced?order=desc&sort=relevance&site=stackoverflow&title=113"
+ },
+ "response": {
+ "data": {
+ "status_code":200
+ },
+ "items": [
+ {
+ "title":"INSTALL_FAILED_NO_MATCHING_ABIS res-113",
+ "link":"https://stackoverflow.com/questions/47117788/install-failed-no-matching-abis-res-113"
+ },
+ {
+ "title":"com.sun.tools.xjc.reader.Ring.get(Ring.java:113)",
+ "link":"https://stackoverflow.com/questions/12848282/com-sun-tools-xjc-reader-ring-getring-java113"
+ },
+ {
+ "title":"no route to host error 113",
+ "link":"https://stackoverflow.com/questions/10516222/no-route-to-host-error-113"
+ }
+ ]
+ },
+ "response-headers":{
+ "status":200,
+ "ok":true,
+ "content-type":"application/json; charset=utf-8"
+ }
+}

ADD
zulip_bots/zulip_bots/bots/stack_overflow/fixtures/test_single_word.json
+{
+ "request": {
+ "api_url":"http://api.stackexchange.com/2.2/search/advanced?order=desc&sort=relevance&site=stackoverflow&title=restful"
+ },
+ "response": {
+ "data": {
+ "status_code":200
+ },
+ "items": [
+ {
+ "title":"What exactly is RESTful programming?",
+ "link":"https://stackoverflow.com/questions/671118/what-exactly-is-restful-programming"
+ },
+ {
+ "title":"RESTful Authentication",
+ "link":"https://stackoverflow.com/questions/319530/restful-authentication"
+ },
+ {
+ "title":"RESTful URL design for search",
+ "link":"https://stackoverflow.com/questions/319530/restful-authentication"
+ }
+ ]
+ },
+ "response-headers":{
+ "status":200,
+ "ok":true,
+ "content-type":"application/json; charset=utf-8"
+ }
+}

ADD
zulip_bots/zulip_bots/bots/stack_overflow/fixtures/test_status_code.json
+{
+ "request": {
+ "api_url":"http://api.stackexchange.com/2.2/search/advanced?order=desc&sort=relevance&site=stackoverflow&title=Zulip"
+ },
+ "response": {
+ "data": {
+ "status_code":404
+ },
+ "items": [
+ ]
+ },
+ "response-headers":{
+ "status":404,
+ "content-type":"text/html"
+ }
+}

ADD
zulip_bots/zulip_bots/bots/stack_overflow/requirements.txt
+requests

ADD
zulip_bots/zulip_bots/bots/stack_overflow/stack_overflow.py
+import requests
+import logging
+import re
+import urllib
+from zulip_bots.lib import Any
+
+from typing import Optional, Any, Dict
+
+# See readme.md for instructions on running this code.
+
+class StackOverflowHandler(object):
+ '''
+ This plugin facilitates searching Stack Overflow for a
+ specific query and returns the top 3 questions from the
+ search. It looks for messages starting with '@mention-bot'
+
+ In this example, we write all Stack Overflow searches into
+ the same stream that it was called from.
+ '''
+
+ META = {
+ 'name': 'StackOverflow',
+ 'description': 'Searches Stack Overflow for a query and returns the top 3 articles.',
+ }
+
+ def usage(self) -> str:
+ return '''
+ This plugin will allow users to directly search
+ Stack Overflow for a specific query and get the top 3
+ articles that are returned from the search. Users
+ should preface query with "@mention-bot".
+ @mention-bot <search query>'''
+
+ def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
+ bot_response = self.get_bot_stackoverflow_response(message, bot_handler)
+ bot_handler.send_reply(message, bot_response)
+
+ def get_bot_stackoverflow_response(self, message: Dict[str, str], bot_handler: Any) -> Optional[str]:
+ '''This function returns the URLs of the requested topic.'''
+
+ help_text = 'Please enter your query after @mention-bot to search StackOverflow'
+
+ # Checking if the link exists.
+ query = message['content']
+ if query == '' or query == 'help':
+ return help_text
+
+ query_stack_link = ('http://api.stackexchange.com/2.2/search/advanced?'
+ 'order=desc&sort=relevance&site=stackoverflow&title=%s'
+ % (urllib.parse.quote(query),))
+ try:
+ data = requests.get(query_stack_link)
+
+ except requests.exceptions.RequestException:
+ logging.error('broken link')
+ return 'Uh-Oh ! Sorry ,couldn\'t process the request right now.:slightly_frowning_face:\n' \
+ 'Please try again later.'
+
+ # Checking if the bot accessed the link.
+ if data.status_code != 200:
+ logging.error('Page not found.')
+ return 'Uh-Oh ! Sorry ,couldn\'t process the request right now.:slightly_frowning_face:\n' \
+ 'Please try again later.'
+
+ new_content = 'For search term:' + query + '\n'
+
+ # Checking if there is content for the searched term
+ if len(data.json()['items']) == 0:
+ new_content = 'I am sorry. The search term you provided is not found :slightly_frowning_face:'
+ else:
+ for i in range(min(3, len(data.json()['items']))):
+ search_string = data.json()['items'][i]['title']
+ link = data.json()['items'][i]['link']
+ new_content += str(i+1) + ' : ' + '[' + search_string + ']' + '(' + link + ')\n'
+ return new_content
+
+handler_class = StackOverflowHandler

ADD
zulip_bots/zulip_bots/bots/stack_overflow/test_stack_overflow.py
+from zulip_bots.test_lib import BotTestCase
+from zulip_bots.request_test_lib import mock_request_exception
+
+class TestStackoverflowBot(BotTestCase):
+ bot_name = "stack_overflow"
+
+ def test_bot(self) -> None:
+
+ # Single-word query
+ bot_request = 'restful'
+ bot_response = ('''For search term:restful
+1 : [What exactly is RESTful programming?](https://stackoverflow.com/questions/671118/what-exactly-is-restful-programming)
+2 : [RESTful Authentication](https://stackoverflow.com/questions/319530/restful-authentication)
+3 : [RESTful URL design for search](https://stackoverflow.com/questions/319530/restful-authentication)
+''')
+ with self.mock_http_conversation('test_single_word'):
+ self.verify_reply(bot_request, bot_response)
+
+ # Multi-word query
+ bot_request = 'what is flutter'
+ bot_response = ('''For search term:what is flutter
+1 : [What is flutter/dart and what are its benefits over other tools?](https://stackoverflow.com/questions/49023008/what-is-flutter-dart-and-what-are-its-benefits-over-other-tools)
+''')
+ with self.mock_http_conversation('test_multi_word'):
+ self.verify_reply(bot_request, bot_response)
+
+ # Number query
+ bot_request = '113'
+ bot_response = ('''For search term:113
+1 : [INSTALL_FAILED_NO_MATCHING_ABIS res-113](https://stackoverflow.com/questions/47117788/install-failed-no-matching-abis-res-113)
+2 : [com.sun.tools.xjc.reader.Ring.get(Ring.java:113)](https://stackoverflow.com/questions/12848282/com-sun-tools-xjc-reader-ring-getring-java113)
+3 : [no route to host error 113](https://stackoverflow.com/questions/10516222/no-route-to-host-error-113)
+''')
+ with self.mock_http_conversation('test_number_query'):
+ self.verify_reply(bot_request, bot_response)
+
+ # Incorrect word
+ bot_request = 'narendra'
+ bot_response = "I am sorry. The search term you provided is not found :slightly_frowning_face:"
+ with self.mock_http_conversation('test_incorrect_query'):
+ self.verify_reply(bot_request, bot_response)
+
+ # 404 status code
+ bot_request = 'Zulip'
+ bot_response = 'Uh-Oh ! Sorry ,couldn\'t process the request right now.:slightly_frowning_face:\n' \
+ 'Please try again later.'
+
+ with self.mock_http_conversation('test_status_code'):
+ self.verify_reply(bot_request, bot_response)
+
+ # Request Exception
+ bot_request = 'Z'
+ with mock_request_exception():
+ self.verify_reply(bot_request, bot_response)

stack_overflow : Create StackOverflow bot.



(Use stackoverflow APIs to answer queries.)