Add twitpost bot.
This commit is contained in:
		
							parent
							
								
									b6afa030c5
								
							
						
					
					
						commit
						a9a988f726
					
				
					 5 changed files with 246 additions and 0 deletions
				
			
		
							
								
								
									
										44
									
								
								zulip_bots/zulip_bots/bots/twitpost/Readme.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								zulip_bots/zulip_bots/bots/twitpost/Readme.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
# Twitpost Bot
 | 
			
		||||
 | 
			
		||||
Twitpost bot is a Zulip bot to tweet from zulip chat.
 | 
			
		||||
 | 
			
		||||
To use twitpost bot, you can simply call it with `@twitpost` followed
 | 
			
		||||
by a keyword `tweet` followed by the content to be tweeted.
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
`@twitpost tweet hey batman`
 | 
			
		||||
 | 
			
		||||
# Setup
 | 
			
		||||
 | 
			
		||||
Before starting using the bot, you will need:
 | 
			
		||||
 | 
			
		||||
1. consumer_key
 | 
			
		||||
2. consumer_secret
 | 
			
		||||
3. access_token
 | 
			
		||||
4. access_token_secret
 | 
			
		||||
 | 
			
		||||
To obtain these 4 keys, follow the following steps :
 | 
			
		||||
 | 
			
		||||
1. Login on [Twitter Application Management](https://apps.twitter.com/) using your Twitter account credentials.
 | 
			
		||||
2. Create a new Twitter app in the [Twitter Application Management](https://apps.twitter.com/)
 | 
			
		||||
3. Provide the required details (Name, Description and Website).
 | 
			
		||||
4. Open your app and click on `Keys and Access Tokens`.
 | 
			
		||||
5. This completes creation of Twitter app to get the 4 required keys.
 | 
			
		||||
6. Take a look at configuration section to configure the bot.
 | 
			
		||||
 | 
			
		||||
# Configuration
 | 
			
		||||
 | 
			
		||||
Enter the 4 keys in the respective field in `twitter.ini` file.
 | 
			
		||||
 | 
			
		||||
Run this bot as described in [here](https://zulipchat.com/api/running-bots#running-a-bot).
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
`@twitpost tweet`
 | 
			
		||||
 | 
			
		||||
- This command tweets the given content to Twitter.
 | 
			
		||||
- Example Usage: `@twitpost tweet hey batman`, `@twitpost tweet hello world!`
 | 
			
		||||
- Sample Output:
 | 
			
		||||
 | 
			
		||||
`Tweet Posted
 | 
			
		||||
https://twitter.com/jasoncosta/status/243145735212777472`
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
{
 | 
			
		||||
    "coordinates": null,
 | 
			
		||||
    "favorited": false,
 | 
			
		||||
    "created_at": "Wed Sep 05 00:37:15 +0000 2012",
 | 
			
		||||
    "truncated": false,
 | 
			
		||||
    "id_str": "243145735212777472",
 | 
			
		||||
    "entities": {
 | 
			
		||||
        "urls": [],
 | 
			
		||||
        "hashtags": [
 | 
			
		||||
            {
 | 
			
		||||
                "text": "peterfalk",
 | 
			
		||||
                "indices": [
 | 
			
		||||
                    35,
 | 
			
		||||
                    45
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "user_mentions": []
 | 
			
		||||
    },
 | 
			
		||||
    "in_reply_to_user_id_str": null,
 | 
			
		||||
    "text": "Maybe he'll finally find his keys. #peterfalk",
 | 
			
		||||
    "contributors": null,
 | 
			
		||||
    "retweet_count": 0,
 | 
			
		||||
    "id": 243145735212777472,
 | 
			
		||||
    "in_reply_to_status_id_str": null,
 | 
			
		||||
    "geo": null,
 | 
			
		||||
    "retweeted": false,
 | 
			
		||||
    "in_reply_to_user_id": null,
 | 
			
		||||
    "place": null,
 | 
			
		||||
    "user": {
 | 
			
		||||
        "name": "Jason Costa",
 | 
			
		||||
        "profile_sidebar_border_color": "86A4A6",
 | 
			
		||||
        "profile_sidebar_fill_color": "A0C5C7",
 | 
			
		||||
        "profile_background_tile": false,
 | 
			
		||||
        "profile_image_url": "http://a0.twimg.com/profile_images/1751674923/new_york_beard_normal.jpg",
 | 
			
		||||
        "created_at": "Wed May 28 00:20:15 +0000 2008",
 | 
			
		||||
        "location": "",
 | 
			
		||||
        "is_translator": true,
 | 
			
		||||
        "follow_request_sent": false,
 | 
			
		||||
        "id_str": "14927800",
 | 
			
		||||
        "profile_link_color": "FF3300",
 | 
			
		||||
        "entities": {
 | 
			
		||||
            "url": {
 | 
			
		||||
                "urls": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "expanded_url": "http://www.jason-costa.blogspot.com/",
 | 
			
		||||
                        "url": "http://t.co/YCA3ZKY",
 | 
			
		||||
                        "indices": [
 | 
			
		||||
                            0,
 | 
			
		||||
                            19
 | 
			
		||||
                        ],
 | 
			
		||||
                        "display_url": "jason-costa.blogspot.com"
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            "description": {
 | 
			
		||||
                "urls": []
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "default_profile": false,
 | 
			
		||||
        "contributors_enabled": false,
 | 
			
		||||
        "url": "http://t.co/YCA3ZKY",
 | 
			
		||||
        "favourites_count": 883,
 | 
			
		||||
        "utc_offset": -28800,
 | 
			
		||||
        "id": 14927800,
 | 
			
		||||
        "profile_image_url_https": "https://si0.twimg.com/profile_images/1751674923/new_york_beard_normal.jpg",
 | 
			
		||||
        "profile_use_background_image": true,
 | 
			
		||||
        "listed_count": 150,
 | 
			
		||||
        "profile_text_color": "333333",
 | 
			
		||||
        "protected": false,
 | 
			
		||||
        "lang": "en",
 | 
			
		||||
        "followers_count": 8760,
 | 
			
		||||
        "time_zone": "Pacific Time (US & Canada)",
 | 
			
		||||
        "profile_background_image_url_https": "https://si0.twimg.com/images/themes/theme6/bg.gif",
 | 
			
		||||
        "verified": false,
 | 
			
		||||
        "profile_background_color": "709397",
 | 
			
		||||
        "notifications": false,
 | 
			
		||||
        "description": "Platform at Twitter",
 | 
			
		||||
        "geo_enabled": true,
 | 
			
		||||
        "statuses_count": 5532,
 | 
			
		||||
        "default_profile_image": false,
 | 
			
		||||
        "friends_count": 166,
 | 
			
		||||
        "profile_background_image_url": "http://a0.twimg.com/images/themes/theme6/bg.gif",
 | 
			
		||||
        "show_all_inline_media": true,
 | 
			
		||||
        "screen_name": "jasoncosta",
 | 
			
		||||
        "following": false
 | 
			
		||||
    },
 | 
			
		||||
    "source": "My Shiny App",
 | 
			
		||||
    "in_reply_to_screen_name": null,
 | 
			
		||||
    "in_reply_to_status_id": null
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								zulip_bots/zulip_bots/bots/twitpost/test_twitpost.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								zulip_bots/zulip_bots/bots/twitpost/test_twitpost.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
from zulip_bots.test_lib import (
 | 
			
		||||
    StubBotHandler,
 | 
			
		||||
    BotTestCase,
 | 
			
		||||
    get_bot_message_handler,
 | 
			
		||||
)
 | 
			
		||||
from zulip_bots.test_file_utils import (
 | 
			
		||||
    read_bot_fixture_data,
 | 
			
		||||
)
 | 
			
		||||
from unittest.mock import patch
 | 
			
		||||
import tweepy
 | 
			
		||||
import os
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestTwitpostBot(BotTestCase):
 | 
			
		||||
    bot_name = "twitpost"
 | 
			
		||||
    mock_config = {'consumer_key': 'abcdefghijklmnopqrstuvwxy',
 | 
			
		||||
                   'consumer_secret': 'aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyy',
 | 
			
		||||
                   'access_token': '123456789012345678-ABCDefgh1234afdsa678lKj6gHhslsi',
 | 
			
		||||
                   'access_token_secret': 'yf0SI0x6Ct2OmF0cDQc1E0eLKXrVAPFx4QkZF2f9PfFCt'}
 | 
			
		||||
    api_response = read_bot_fixture_data('twitpost', 'api_response')
 | 
			
		||||
 | 
			
		||||
    def test_bot_usage(self) -> None:
 | 
			
		||||
        bot = get_bot_message_handler(self.bot_name)
 | 
			
		||||
        bot_handler = StubBotHandler()
 | 
			
		||||
 | 
			
		||||
        with self.mock_config_info(self.mock_config):
 | 
			
		||||
            bot.initialize(bot_handler)
 | 
			
		||||
 | 
			
		||||
        self.assertIn('This bot posts on twitter from zulip chat itself', bot.usage())
 | 
			
		||||
 | 
			
		||||
    def test_bot_responds_to_empty_message(self) -> None:
 | 
			
		||||
        with self.mock_config_info(self.mock_config):
 | 
			
		||||
            self.verify_reply('', 'Please check help for usage.')
 | 
			
		||||
 | 
			
		||||
    def test_help(self) -> None:
 | 
			
		||||
        with self.mock_config_info(self.mock_config):
 | 
			
		||||
            self.verify_reply('help',
 | 
			
		||||
                              "*Help for Twitter-post bot* :twitter: : \n\n"
 | 
			
		||||
                              "The bot tweets on twitter when message starts with @twitpost.\n\n"
 | 
			
		||||
                              "`@twitpost tweet <content>` will tweet on twitter with given `<content>`.\n"
 | 
			
		||||
                              "Example:\n"
 | 
			
		||||
                              " * @twitpost tweet hey batman\n")
 | 
			
		||||
 | 
			
		||||
    @patch('tweepy.API.update_status', return_value=api_response)
 | 
			
		||||
    def test_tweet(self, mockedarg):
 | 
			
		||||
        test_message = 'tweet Maybe he\'ll finally find his keys. #peterfalk'
 | 
			
		||||
        bot_response = 'Tweet Posted\n'\
 | 
			
		||||
                       'https://twitter.com/jasoncosta/status/243145735212777472'
 | 
			
		||||
        with self.mock_config_info(self.mock_config):
 | 
			
		||||
            self.verify_reply(test_message, bot_response)
 | 
			
		||||
							
								
								
									
										54
									
								
								zulip_bots/zulip_bots/bots/twitpost/twitpost.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								zulip_bots/zulip_bots/bots/twitpost/twitpost.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
import zulip
 | 
			
		||||
import tweepy
 | 
			
		||||
from typing import Dict, Any, Union, List, Tuple, Optional
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TwitpostBot(object):
 | 
			
		||||
 | 
			
		||||
    def usage(self) -> str:
 | 
			
		||||
        return ''' This bot posts on twitter from zulip chat itself.
 | 
			
		||||
                   Use '@twitpost help' to get more information
 | 
			
		||||
                   on the bot usage. '''
 | 
			
		||||
    help_content = "*Help for Twitter-post bot* :twitter: : \n\n"\
 | 
			
		||||
                   "The bot tweets on twitter when message starts "\
 | 
			
		||||
                   "with @twitpost.\n\n"\
 | 
			
		||||
                   "`@twitpost tweet <content>` will tweet on twitter " \
 | 
			
		||||
                   "with given `<content>`.\n" \
 | 
			
		||||
                   "Example:\n" \
 | 
			
		||||
                   " * @twitpost tweet hey batman\n"
 | 
			
		||||
 | 
			
		||||
    def initialize(self, bot_handler: Any) -> None:
 | 
			
		||||
        self.config_info = bot_handler.get_config_info('twitter')
 | 
			
		||||
        auth = tweepy.OAuthHandler(self.config_info['consumer_key'],
 | 
			
		||||
                                   self.config_info['consumer_secret'])
 | 
			
		||||
        auth.set_access_token(self.config_info['access_token'],
 | 
			
		||||
                              self.config_info['access_token_secret'])
 | 
			
		||||
        self.api = tweepy.API(auth, parser=tweepy.parsers.JSONParser())
 | 
			
		||||
 | 
			
		||||
    def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
 | 
			
		||||
        content = message["content"]
 | 
			
		||||
 | 
			
		||||
        if content.strip() == '':
 | 
			
		||||
            bot_handler.send_reply(message, 'Please check help for usage.')
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if content.strip() == 'help':
 | 
			
		||||
            bot_handler.send_reply(message, self.help_content)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        content = content.split()
 | 
			
		||||
 | 
			
		||||
        if len(content) > 1 and content[0] == "tweet":
 | 
			
		||||
            status = self.post(" ".join(content[1:]))
 | 
			
		||||
            screen_name = status["user"]["screen_name"]
 | 
			
		||||
            id_str = status["id_str"]
 | 
			
		||||
            bot_reply = "https://twitter.com/{}/status/{}".format(screen_name,
 | 
			
		||||
                                                                  id_str)
 | 
			
		||||
            bot_reply = "Tweet Posted\n" + bot_reply
 | 
			
		||||
            bot_handler.send_reply(message, bot_reply)
 | 
			
		||||
 | 
			
		||||
    def post(self, text):
 | 
			
		||||
        return self.api.update_status(text)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
handler_class = TwitpostBot
 | 
			
		||||
							
								
								
									
										6
									
								
								zulip_bots/zulip_bots/bots/twitpost/twitter.ini
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								zulip_bots/zulip_bots/bots/twitpost/twitter.ini
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
[twitter]
 | 
			
		||||
consumer_key=
 | 
			
		||||
consumer_secret=
 | 
			
		||||
access_token=
 | 
			
		||||
access_token_secret=
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue