Beispiel #1
0
    def handle_input(self, message: Dict[str, str],
                     bot_handler: BotHandler) -> None:
        original_content = message["content"]

        if self.is_help(original_content) or (original_content == ""):
            bot_handler.send_reply(message, HELP_MESSAGE)

        else:
            sentence = self.format_input(original_content)
            try:
                reply_message = self.send_to_yoda_api(sentence)

                if len(reply_message) == 0:
                    reply_message = "Invalid input, please check the sentence you have entered."

            except (ssl.SSLError, TypeError):
                reply_message = "The service is temporarily unavailable, please try again."
                logging.error(reply_message)

            except ApiKeyError:
                reply_message = (
                    "Invalid Api Key. Did you follow the instructions in the `readme.md` file?"
                )
                logging.error(reply_message)

            bot_handler.send_reply(message, reply_message)
Beispiel #2
0
 def handle_message(self, message: Dict[str, str],
                    bot_handler: BotHandler) -> None:
     command = message["content"]
     if command == "":
         command = "help"
     msg = dbx_command(self.client, command)
     bot_handler.send_reply(message, msg)
Beispiel #3
0
def start_new_quiz(message: Dict[str, Any], bot_handler: BotHandler) -> None:
    quiz = get_trivia_quiz()
    quiz_id = generate_quiz_id(bot_handler.storage)
    bot_response = format_quiz_for_markdown(quiz_id, quiz)
    widget_content = format_quiz_for_widget(quiz_id, quiz)
    bot_handler.storage.put(quiz_id, json.dumps(quiz))
    bot_handler.send_reply(message, bot_response, widget_content)
Beispiel #4
0
 def handle_message(self, message: Dict[str, Any],
                    bot_handler: BotHandler) -> None:
     query = message['content']
     if query == 'new':
         try:
             start_new_quiz(message, bot_handler)
             return
         except NotAvailableException:
             bot_response = 'Uh-Oh! Trivia service is down.'
             bot_handler.send_reply(message, bot_response)
             return
     elif query.startswith('answer'):
         try:
             (quiz_id, answer) = parse_answer(query)
         except InvalidAnswerException:
             bot_response = 'Invalid answer format'
             bot_handler.send_reply(message, bot_response)
             return
         try:
             quiz_payload = get_quiz_from_id(quiz_id, bot_handler)
         except (KeyError, TypeError):
             bot_response = 'Invalid quiz id'
             bot_handler.send_reply(message, bot_response)
             return
         quiz = json.loads(quiz_payload)
         start_new_question, bot_response = handle_answer(
             quiz, answer, quiz_id, bot_handler,
             message['sender_full_name'])
         bot_handler.send_reply(message, bot_response)
         if start_new_question:
             start_new_quiz(message, bot_handler)
         return
     else:
         bot_response = 'type "new" for a new question'
     bot_handler.send_reply(message, bot_response)
Beispiel #5
0
    def handle_message(self, message: Dict[str, Any],
                       bot_handler: BotHandler) -> None:
        content = 'beep boop'  # type: str
        bot_handler.send_reply(message, content)

        emoji_name = 'wave'  # type: str
        bot_handler.react(message, emoji_name)
        return
Beispiel #6
0
    def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None:

        if message["content"] == "" or message["content"] == "help":
            bot_handler.send_reply(message, self.help_content)
        else:
            cmd, query = get_command_query(message)
            bot_response = get_bot_response(query, cmd, self.config_info)
            logging.info(bot_response.format())
            bot_handler.send_reply(message, bot_response)
Beispiel #7
0
    def move_computer(self, message: Dict[str, str], bot_handler: BotHandler,
                      last_fen: str, move_san: str) -> None:
        """Preforms a move for a user in a game with the computer and then
        makes the computer's move. Replies to the bot handler. Unlike `move`,
        replies only once to the bot handler every two moves (only after the
        computer moves) instead of after every move. Doesn't require a call in
        order to make the computer move. To make the computer move without the
        user going first, use `move_computer_first`.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
             - last_fen: The FEN string of the board before the user's move.
             - move_san: The SAN of the user's move to make.
        """
        last_board = self.validate_board(message, bot_handler, last_fen)

        if not last_board:
            return

        move = self.validate_move(message, bot_handler, last_board, move_san,
                                  True)

        if not move:
            return

        new_board = copy.copy(last_board)
        new_board.push(move)

        if self.check_game_over(message, bot_handler, new_board):
            return

        computer_move = calculate_computer_move(new_board, self.engine)

        if not computer_move:
            bot_handler.send_reply(message, make_engine_failed_response())
            return

        new_board_after_computer_move = copy.copy(new_board)
        new_board_after_computer_move.push(computer_move)

        if self.check_game_over(message, bot_handler,
                                new_board_after_computer_move):
            return

        bot_handler.send_reply(
            message,
            make_move_reponse(new_board, new_board_after_computer_move,
                              computer_move))

        bot_handler.storage.put("last_fen",
                                new_board_after_computer_move.fen())
Beispiel #8
0
def start_new_incident(query: str, message: Dict[str, Any],
                       bot_handler: BotHandler) -> None:
    # Here is where we would enter the incident in some sort of backend
    # system.  We just simulate everything by having an incident id that
    # we generate here.

    incident = query[len("new "):]

    ticket_id = generate_ticket_id(bot_handler.storage)
    bot_response = format_incident_for_markdown(ticket_id, incident)
    widget_content = format_incident_for_widget(ticket_id, incident)

    bot_handler.send_reply(message, bot_response, widget_content)
Beispiel #9
0
 def handle_message(self, message: Dict[str, str],
                    bot_handler: BotHandler) -> None:
     msg = message["content"]
     if msg == "help" or msg == "":
         bot_handler.send_reply(message, self.usage())
         return
     reply = requests.get("https://api.susi.ai/susi/chat.json",
                          params=dict(q=msg))
     try:
         answer = reply.json()["answers"][0]["actions"][0]["expression"]
     except Exception:
         answer = "I don't understand. Can you rephrase?"
     bot_handler.send_reply(message, answer)
Beispiel #10
0
    def handle_message(self, message: Dict[str, Any],
                       bot_handler: BotHandler) -> None:
        req = message['content'].strip().split()

        if req == []:
            bot_handler.send_reply(message, 'No Command Specified')
            return

        req[0] = req[0].lower()

        response = ''

        if req == ['my-events']:
            response = helpers.get_my_events(message['sender_id'])
            if response:
                bot_handler.send_reply(message, response)

        elif req == ['all-events']:
            response = helpers.get_all_events()
            if response:
                bot_handler.send_reply(message, response)

        else:
            bot_handler.send_reply(
                message,
                "I don't understand what you're saying...try again :)")

        return
Beispiel #11
0
    def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None:
        HELP_STR = (
            'Use this bot with any of the following commands:'
            '\n* `@uploader <local_file_path>` : Upload a file, where `<local_file_path>` is the path to the file'
            '\n* `@uploader help` : Display help message'
        )

        content = message['content'].strip()
        if content == 'help':
            bot_handler.send_reply(message, HELP_STR)
            return

        path = Path(os.path.expanduser(content))
        if not path.is_file():
            bot_handler.send_reply(message, 'File `{}` not found'.format(content))
            return

        path = path.resolve()
        upload = bot_handler.upload_file_from_path(str(path))
        if upload['result'] != 'success':
            msg = upload['msg']
            bot_handler.send_reply(message, 'Failed to upload `{}` file: {}'.format(path, msg))
            return

        uploaded_file_reply = '[{}]({})'.format(path.name, upload['uri'])
        bot_handler.send_reply(message, uploaded_file_reply)
Beispiel #12
0
    def handle_message(self, message: Dict[str, str],
                       bot_handler: BotHandler) -> None:
        HELP_STR = (
            "Use this bot with any of the following commands:"
            "\n* `@uploader <local_file_path>` : Upload a file, where `<local_file_path>` is the path to the file"
            "\n* `@uploader help` : Display help message")

        content = message["content"].strip()
        if content == "help":
            bot_handler.send_reply(message, HELP_STR)
            return

        path = Path(os.path.expanduser(content))
        if not path.is_file():
            bot_handler.send_reply(message, f"File `{content}` not found")
            return

        path = path.resolve()
        upload = bot_handler.upload_file_from_path(str(path))
        if upload["result"] != "success":
            msg = upload["msg"]
            bot_handler.send_reply(message,
                                   f"Failed to upload `{path}` file: {msg}")
            return

        uploaded_file_reply = "[{}]({})".format(path.name, upload["uri"])
        bot_handler.send_reply(message, uploaded_file_reply)
Beispiel #13
0
    def start(self, message: Dict[str, str], bot_handler: BotHandler) -> None:
        """Starts a game with another user, with the current user as white.
        Replies to the bot handler.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
        """
        new_board = chess.Board()
        bot_handler.send_reply(message, make_start_reponse(new_board))

        # `bot_handler`'s `storage` only accepts `str` values.
        bot_handler.storage.put("is_with_computer", str(False))

        bot_handler.storage.put("last_fen", new_board.fen())
Beispiel #14
0
 def handle_message(self, message: Dict[str, str],
                    bot_handler: BotHandler) -> None:
     if message['content'] == '':
         bot_response = "Please specify the message you want to send to followup stream after @mention-bot"
         bot_handler.send_reply(message, bot_response)
     elif message['content'] == 'help':
         bot_handler.send_reply(message, self.usage())
     else:
         bot_response = self.get_bot_followup_response(message)
         bot_handler.send_message(
             dict(
                 type='stream',
                 to=self.stream,
                 subject=message['sender_email'],
                 content=bot_response,
             ))
Beispiel #15
0
    def resign(self, message: Dict[str, str], bot_handler: BotHandler,
               last_fen: str) -> None:
        """Resigns the game for the current player.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
             - last_fen: The FEN string of the board.
        """
        last_board = self.validate_board(message, bot_handler, last_fen)

        if not last_board:
            return

        bot_handler.send_reply(message,
                               make_loss_response(last_board, "resigned"))
Beispiel #16
0
    def check_game_over(self, message: Dict[str, str], bot_handler: BotHandler,
                        new_board: chess.Board) -> bool:
        """Checks if a game is over due to
         - checkmate,
         - stalemate,
         - insufficient material,
         - 50 moves without a capture or pawn move, or
         - 3-fold repetition.
        Replies to the bot handler if it is game over.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
             - new_board: The board object.

        Returns: True if it is game over, false if it's not.
        """
        # This assumes that the players will claim a draw after 3-fold
        # repetition or 50 moves go by without a capture or pawn move.
        # According to the official rules, the game is only guaranteed to
        # be over if it's  *5*-fold or *75* moves, but if either player
        # wants the game to be a draw, after 3 or 75 it a draw. For now,
        # just assume that the players would want the draw.
        if new_board.is_game_over(claim_draw=True):
            game_over_output = ""

            if new_board.is_checkmate():
                game_over_output = make_loss_response(new_board,
                                                      "was checkmated")
            elif new_board.is_stalemate():
                game_over_output = make_draw_response("stalemate")
            elif new_board.is_insufficient_material():
                game_over_output = make_draw_response("insufficient material")
            elif new_board.can_claim_fifty_moves():
                game_over_output = make_draw_response(
                    "50 moves without a capture or pawn move")
            elif new_board.can_claim_threefold_repetition():
                game_over_output = make_draw_response("3-fold repetition")

            bot_handler.send_reply(message, game_over_output)

            return True

        return False
Beispiel #17
0
    def validate_board(self, message: Dict[str, str], bot_handler: BotHandler,
                       fen: str) -> Optional[chess.Board]:
        """Validates a board based on its FEN string. Replies to the bot
        handler if there is an error with the board.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
             - fen: The FEN string of the board.

        Returns: `None` if the board didn't pass, or the board object itself
                 if it did.
        """
        try:
            last_board = chess.Board(fen)
        except ValueError:
            bot_handler.send_reply(message, make_copied_wrong_response())
            return None

        return last_board
Beispiel #18
0
    def move_computer_first(self, message: Dict[str, str],
                            bot_handler: BotHandler, last_fen: str) -> None:
        """Preforms a move for the computer without having the user go first in
        a game with the computer. Replies to the bot handler. Like
        `move_computer`, but doesn't have the user move first. This is usually
        only useful at the beginning of a game.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
             - last_fen: The FEN string of the board before the computer's
                         move.
        """
        last_board = self.validate_board(message, bot_handler, last_fen)

        if not last_board:
            return

        computer_move = calculate_computer_move(last_board, self.engine)

        if not computer_move:
            bot_handler.send_reply(message, make_engine_failed_response())
            return

        new_board_after_computer_move = copy.copy(last_board)
        new_board_after_computer_move.push(computer_move)

        if self.check_game_over(message, bot_handler,
                                new_board_after_computer_move):
            return

        bot_handler.send_reply(
            message,
            make_move_reponse(last_board, new_board_after_computer_move,
                              computer_move))

        bot_handler.storage.put("last_fen",
                                new_board_after_computer_move.fen())

        # `bot_handler`'s `storage` only accepts `str` values.
        bot_handler.storage.put("is_with_computer", str(True))
Beispiel #19
0
    def handle_message(self, message: Dict[str, str],
                       bot_handler: BotHandler) -> None:
        REGEX_STR = (
            r"("
            r"(?:http|https):\/\/"  # This allows for the HTTP or HTTPS
            # protocol.
            r'[^"<>\{\}|\^~[\]` ]+'  # This allows for any character except
            # for certain non-URL-safe ones.
            r")")

        HELP_STR = ("Mention the link shortener bot in a conversation and "
                    "then enter any URLs you want to shorten in the body of "
                    "the message.")

        content = message["content"]

        if content.strip() == "help":
            bot_handler.send_reply(message, HELP_STR)
            return

        link_matches = re.findall(REGEX_STR, content)

        shortened_links = [self.shorten_link(link) for link in link_matches]
        link_pairs = [(link_match + ": " + shortened_link)
                      for link_match, shortened_link in zip(
                          link_matches, shortened_links)
                      if shortened_link != ""]
        final_response = "\n".join(link_pairs)

        if final_response == "":
            bot_handler.send_reply(message, "No links found. " + HELP_STR)
            return

        bot_handler.send_reply(message, final_response)
Beispiel #20
0
    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_handler.send_reply(message, self.usage())
            return

        if content == ["list-commands"]:
            bot_reply = self.get_all_supported_commands()
        elif content == ["get-all-boards"]:
            bot_reply = self.get_all_boards()
        else:
            if content[0] == "get-all-cards":
                bot_reply = self.get_all_cards(content)
            elif content[0] == "get-all-checklists":
                bot_reply = self.get_all_checklists(content)
            elif content[0] == "get-all-lists":
                bot_reply = self.get_all_lists(content)
            else:
                bot_reply = "Command not supported"

        bot_handler.send_reply(message, bot_reply)
Beispiel #21
0
    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_handler.send_reply(message, self.usage())
            return

        if content == ['list-commands']:
            bot_reply = self.get_all_supported_commands()
        elif content == ['get-all-boards']:
            bot_reply = self.get_all_boards()
        else:
            if content[0] == 'get-all-cards':
                bot_reply = self.get_all_cards(content)
            elif content[0] == 'get-all-checklists':
                bot_reply = self.get_all_checklists(content)
            elif content[0] == 'get-all-lists':
                bot_reply = self.get_all_lists(content)
            else:
                bot_reply = 'Command not supported'

        bot_handler.send_reply(message, bot_reply)
Beispiel #22
0
    def handle_message(self, message: Dict[str, str],
                       bot_handler: BotHandler) -> None:
        content = message["content"]

        if content == "":
            bot_handler.send_reply(message, self.usage())
            return

        start_regex_match = START_REGEX.match(content)
        start_computer_regex_match = START_COMPUTER_REGEX.match(content)
        move_regex_match = MOVE_REGEX.match(content)
        resign_regex_match = RESIGN_REGEX.match(content)

        is_with_computer = False
        last_fen = chess.Board().fen()

        if bot_handler.storage.contains("is_with_computer"):
            is_with_computer = (
                # `bot_handler`'s `storage` only accepts `str` values.
                bot_handler.storage.get("is_with_computer") == str(True))

        if bot_handler.storage.contains("last_fen"):
            last_fen = bot_handler.storage.get("last_fen")

        if start_regex_match:
            self.start(message, bot_handler)
        elif start_computer_regex_match:
            self.start_computer(
                message, bot_handler,
                start_computer_regex_match.group("user_color") == "white")
        elif move_regex_match:
            if is_with_computer:
                self.move_computer(message, bot_handler, last_fen,
                                   move_regex_match.group("move_san"))
            else:
                self.move(message, bot_handler, last_fen,
                          move_regex_match.group("move_san"))
        elif resign_regex_match:
            self.resign(message, bot_handler, last_fen)
Beispiel #23
0
    def validate_move(
        self,
        message: Dict[str, str],
        bot_handler: BotHandler,
        last_board: chess.Board,
        move_san: str,
        is_computer: object,
    ) -> Optional[chess.Move]:
        """Validates a move based on its SAN string and the current board.
        Replies to the bot handler if there is an error with the move.

        Parameters:
             - message: The Zulip Bots message object.
             - bot_handler: The Zulip Bots bot handler object.
             - last_board: The board object before the move.
             - move_san: The SAN of the move.
             - is_computer: Whether or not the user is playing against a
                            computer (used in the response if the move is not
                            legal).

        Returns: `False` if the move didn't pass, or the move object itself if
                 it did.
        """
        try:
            move = last_board.parse_san(move_san)
        except ValueError:
            bot_handler.send_reply(
                message, make_not_legal_response(last_board, move_san))
            return None

        if move not in last_board.legal_moves:
            bot_handler.send_reply(
                message, make_not_legal_response(last_board, move_san))
            return None

        return move
Beispiel #24
0
    def handle_message(self, message: Dict[str, str],
                       bot_handler: BotHandler) -> None:
        help_content = """
            This bot returns weather info for specified city.
            You specify city in the following format:
            city, state/country
            state and country parameter is optional(useful when there are many cities with the same name)
            For example:
            @**Weather Bot** Portland
            @**Weather Bot** Portland, Me
            """.strip()

        if (message["content"] == "help") or (message["content"] == ""):
            response = help_content
        else:
            api_params = dict(q=message["content"], APPID=self.api_key)
            r = requests.get(api_url, params=api_params)
            if r.json()["cod"] == "404":
                response = "Sorry, city not found"
            else:
                response = format_response(r, message["content"],
                                           self.response_pattern)

        bot_handler.send_reply(message, response)
Beispiel #25
0
    def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None:
        if message["content"] == "" or message["content"] == "help":
            bot_handler.send_reply(message, self.help_message)
            return

        try:
            res = self.client.message(message["content"])
            message_for_user = self.handle(res)

            if message_for_user:
                bot_handler.send_reply(message, message_for_user)
        except wit.wit.WitError:
            bot_handler.send_reply(message, "Sorry, I don't know how to respond to that!")
        except Exception as e:
            bot_handler.send_reply(message, "Sorry, there was an internal error.")
            print(e)
            return
Beispiel #26
0
    def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None:
        storage = bot_handler.storage
        num = storage.get('number')

        # num should already be an int, but we do `int()` to force an
        # explicit type check
        num = int(num) + 1

        storage.put('number', num)
        if storage.get('message_id') is None:
            result = bot_handler.send_reply(message, str(num))
            if result is not None:
                storage.put('message_id', result['id'])
        else:
            bot_handler.update_message(dict(
                message_id=storage.get('message_id'),
                content=str(num)
            ))
Beispiel #27
0
    def handle_message(self, message: Dict[str, Any],
                       bot_handler: BotHandler) -> None:
        message["content"] = message["content"].strip()

        if message["content"].lower() == "help":
            bot_handler.send_reply(message, self.usage())
            return

        if message["content"] == "":
            bot_handler.send_reply(message, "Empty Mention Query")
            return

        keyword = message["content"]
        content = self.generate_response(keyword)
        bot_handler.send_reply(message, content)
Beispiel #28
0
    def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None:
        content = message["content"].strip().split()

        if content == []:
            bot_handler.send_reply(message, "No Command Specified")
            return

        content[0] = content[0].lower()

        if content == ["help"]:
            bot_handler.send_reply(message, self.usage())
            return

        if content == ["list-commands"]:
            response = "**Available Commands:** \n"
            for command, description in zip(self.commands, self.descriptions):
                response += f" - {command} : {description}\n"

            bot_handler.send_reply(message, response)
            return

        response = self.generate_response(content)
        bot_handler.send_reply(message, response)
Beispiel #29
0
    def handle_message(self, message: Dict[str, str],
                       bot_handler: BotHandler) -> None:
        storage = bot_handler.storage
        num = storage.get('number')

        # num should already be an int, but we do `int()` to force an
        # explicit type check
        num = int(num) + 1

        storage.put('number', num)
        if storage.get('message_id') is not None:
            result = bot_handler.update_message(
                dict(message_id=storage.get('message_id'), content=str(num)))

            # When there isn't an error while updating the message, we won't
            # attempt to send the it again.
            if result is None or result.get('result') != 'error':
                return

        message_info = bot_handler.send_reply(message, str(num))
        if message_info is not None:
            storage.put('message_id', message_info['id'])
Beispiel #30
0
    def handle_message(self, message: Dict[str, Any],
                       bot_handler: BotHandler) -> None:
        content = message['content'].strip().split()

        if content == []:
            bot_handler.send_reply(message, 'No Command Specified')
            return

        content[0] = content[0].lower()

        if content == ['help']:
            bot_handler.send_reply(message, self.usage())
            return

        if content == ['list-commands']:
            response = '**Available Commands:** \n'
            for command, description in zip(self.commands, self.descriptions):
                response += ' - {} : {}\n'.format(command, description)

            bot_handler.send_reply(message, response)
            return

        response = self.generate_response(content)
        bot_handler.send_reply(message, response)